Home > Uncategorized > Verilog Code for counter increment on button press

Verilog Code for counter increment on button press

September 25th, 2015

We will present an important verilog code that will form the basis of some more important verilog topics. We will discuss how a push button press can increment counter and display it on a 7 segment display.

This is how it looks like..

There are two inputs to the circuit - a button_in and a n_reset. On pressing button_in the counter increments by 1. On pressing n_reset the counter resets to 0.

If you wish to understand the code, we strongly recommend that you go though the following posts ( in that order)

1. Binary to 7 Segment Display

2. Implementation of Key Debounce
- The key debounce code will ensure that we have a stable input, otherwise, our counter will increment several times on pressing key once.

3. Level Change detection in Verilog
- We monitor the level change of the debounced output of the key.

If you understand the above three, it will be easy for you to follow the code below.


module  counterdisplay 
    (
input   clk, n_reset, button_in,        // inputs
output leda,
output ledb,
output ledc,
output ledd,
output lede,
output ledf,
output ledg

	 
    );
	 reg DB_out;
	  reg [3:0] counter;
     reg [6:0] seg_data;
	  reg [3:0] counter_reg;
    /*
    Parameter N defines the debounce time. Assuming 50 KHz clock,
    the debounce time is 2^(11-1)/ 50 KHz = 20 ms
     
    For 50 MHz clock increase value of N accordingly to 21.
     
    */
    parameter N = 11 ;      
 
    reg  [N-1 : 0]  delaycount_reg;                     
    reg  [N-1 : 0]  delaycount_next;
     
    reg DFF1, DFF2;                                 
    wire q_add;                                     
    wire q_reset;
 

 reg  delay_reg ; // Registers for detecting level change of DB_out
 wire level_out;
 
        always @ ( posedge clk or negedge n_reset )
        begin
            if(n_reset ==  0) // At reset initialize FF and counter 
                begin
                    DFF1 <= 1'b0;
                    DFF2 <= 1'b0;
					// For level change detection
					delay_reg  <=  1'b0;

                    delaycount_reg <= { N {1'b0} };
                end
            else
                begin
                    DFF1 <= button_in;
                    DFF2 <= DFF1;
                    delaycount_reg <= delaycount_next;
						
					
					
					delay_reg  <=  DB_out;// to detect level change
                end
        end
     
     
    assign q_reset = (DFF1  ^ DFF2); // Ex OR button_in on conecutive clocks
                                     // to detect level change 
                                      
    assign  q_add = ~(delaycount_reg[N-1]); // Check count using MSB of counter         
     
 
    always @ ( q_reset, q_add, delaycount_reg)
        begin
            case( {q_reset , q_add})
                2'b00 :
                        delaycount_next <= delaycount_reg;
                2'b01 :
                        delaycount_next <= delaycount_reg + 1;
                default :
                // In this case q_reset = 1 => change in level. Reset the counter 
                        delaycount_next <= { N {1'b0} };
            endcase    
        end
     
     
    always @ ( posedge clk )
        begin
            if(delaycount_reg[N-1] == 1'b1)
                    DB_out <= DFF2;
            else
                    DB_out <= DB_out;
        end
         
	
	assign  level_out  =  (delay_reg)  &  (~DB_out);	 
   
			 

	
	always @(posedge  clk )
	
	if ( n_reset == 0)
	counter <= 0;

	else if ( level_out == 1'b1)
	begin
	if (counter  < 9)
	counter <= counter +1;
	else counter <= 0;
	end
	

	
always @(counter)
case (counter)
4'b0000:seg_data=7'b1111110;
4'b0001:seg_data=7'b0110000;
4'b0010:seg_data=7'b1101101;
4'b0011:seg_data=7'b1111001;
4'b0100:seg_data=7'b0110011;
4'b0101:seg_data=7'b1011011;
4'b0110:seg_data=7'b1011111;
4'b0111:seg_data=7'b1110000;
4'b1000:seg_data=7'b1111111;
4'b1001:seg_data=7'b1111011;
default:seg_data=7'b1111110;
endcase
 
assign leda=seg_data[6];
assign ledb=seg_data[5];
assign ledc=seg_data[4];
assign ledd=seg_data[3];
assign lede=seg_data[2];
assign ledf=seg_data[1];
assign ledg=seg_data[0];

		 
endmodule

The following test bench may be used.

`timescale 1 us / 1 us
 
module tb_counterdisplay();
    reg clk;
    reg n_reset;
    reg button_in;
    wire DB_out;
 
    counterdisplay UUT (
        .clk(clk), 
        .n_reset(n_reset), 
        .button_in(button_in)     
        );
  
    initial begin
            clk = 1'b0;
            n_reset = 1'b0;
            #20 n_reset = 1'b1;      // at time 20 release the reset
            button_in = 1'b1;
             
            // We need at least twice the counter value to stabilize value of DB_out
            // before we change the button in
            #50000 button_in = 1'b0; // We pressed the key here 
            #400 button_in = 1'b1; // Key debounce to 1 after 400 micro seconds             
            #800 button_in = 1'b0;    // Debounce after 800 ms
            #2000 button_in = 1'b1; // Decounce after 2 ms          
            #800 button_in = 1'b0;
            #40000 button_in = 1'b1;
            #4000 button_in = 1'b0;     
            #40000 button_in = 1'b1;
            #400 button_in = 1'b0;
            #800 button_in = 1'b1;      
            #800 button_in = 1'b0;
            #800 button_in = 1'b1;
            #40000 button_in = 1'b0;        
            #40000 button_in = 1'b0;
			   #400 button_in = 1'b1;
            #800 button_in = 1'b1;      
            #800 button_in = 1'b0;
            #800 button_in = 1'b1;
            #40000 button_in = 1'b0;
			#40000 button_in = 1'b0;			
            #4000 button_in = 1'b1;
            $finish;
    end
    always
            #10 clk = ~clk;  // 20 mirco seconds = 50 KHz Clock cycle   
 
initial
      begin
      $dumpfile ("debounce.vcd");
      $dumpvars (0,DeBounce_tf);
      end
endmodule

Uncategorized

  1. Andy Marty
    October 14th, 2016 at 22:30 | #1

    Hi, if I understood correctly, what your program does is it increments by 1 whenever you push the button. I have an almost similar task but I have no idea what to do at this point because I'm really noob toVerilog. In our homework, we are tasked to implement a basketball scoreboard using the Altera DE1.

    1. The Altera DE1 we use has 4 7-segment displays.
    2. In the first 2 7-segment displays, we have to show the score of the 1st team.
    3. In the last 2 7-segment displays, we have to show the score of the 2nd team.
    4. The Altera DE1 we use has 4 push buttons (PB0 - PB3)
    5. If we push PB0, the score of the 1st team should increase by 1. If we push PB1, the score of the 1st team should decrease by 1.
    6. Similar logic for the 2nd team except we should use PB2 and PB3.

    How do I do this? I really you could help me. Please and Thank you.

  2. Andy Marty
    October 14th, 2016 at 22:44 | #2

    @Andy Marty

    We have to assume that the score is only up to 99.

  3. Andy Marty
    October 15th, 2016 at 20:19 | #3

    How do you do this for 2 digits?

  1. No trackbacks yet.