Skip to main content

00 to 99 Two Digit Decimal Counter via 7 Segment Display Using Verilog

Since I have already made a detailed post regarding 7 segment LED multiplexing, this post is going to be a short one, in which I will only explain the code via comments in code.

Here I am going to make a 2 digit counter that counts from 00 to 99 and then rolls over back to 00. The counter will increment every 0.1 second. The 0.1 second interval is produced by another counter that will produce an enable tick every 0.1 second to increment our main counter.

How to make a 0.1 second accurate delay in Verilog


We know that the board being used has a 50 MHz clock. So to produce a 0.1 second delay simply multiply the two.. 50Mhz * 0.1 sec = 5000000. So every 5M ticks is equal to 0.1 second. So using the simple log formula ( (x)log(2) = log(5000000) ) we can calculate that a 23 bit wide register will be able to hold a count of 5000000.

The code for this counter is given below:

module twodigit_onefile(
  input clock,
    input reset,
    output a,
    output b,
    output c,
    output d,
    output e,
    output f,
    output g,
    output dp,
    output [3:0]an
    );
  
reg [3:0]first; //register for the first digit
reg [3:0]second; //register for the second digit

reg [22:0] delay; //register to produce the 0.1 second delay
wire test;

always @ (posedge clock or posedge reset)
 begin
  if (reset)
   delay <= 0;
  else
   delay <= delay + 1;
 end
 
assign test = &delay; //AND each bit of delay with itself; test will be high only when all bits of delay are high


always @ (posedge test or posedge reset)
 begin
  if (reset) begin
   first <= 0;
   second <= 0;
  end
   else if (first==4'd9) begin  //x9 reached
    first <= 0;
     if (second == 4'd9) //99 reached
      second <= 0;
      else
       second <= second + 1;
     
   end
   else
    first <= first + 1;
  end
  
//Multiplexing circuit below

localparam N = 18;

reg [N-1:0]count;

always @ (posedge clock or posedge reset)
 begin
  if (reset)
   count <= 0;
  else
   count <= count + 1;
 end

reg [6:0]sseg;
reg [3:0]an_temp;
always @ (*)
 begin
  case(count[N-1:N-2])
   
   2'b00 : 
    begin
     sseg = first;
     an_temp = 4'b1110;
    end
   
   2'b01:
    begin
     sseg = second;
     an_temp = 4'b1101;
    end
   
   2'b10:
    begin
     sseg = 6'ha; //unknown sent to produce '-'
     an_temp = 4'b1011;
    end
    
   2'b11:
    begin
     sseg = 6'ha; //unknown sent to produce '-'
     an_temp = 4'b0111;
    end
  endcase
 end
assign an = an_temp;

reg [6:0] sseg_temp; 
always @ (*)
 begin
  case(sseg)
   4'd0 : sseg_temp = 7'b1000000; //0
   4'd1 : sseg_temp = 7'b1111001; //1
   4'd2 : sseg_temp = 7'b0100100; //2
   4'd3 : sseg_temp = 7'b0110000; //3
   4'd4 : sseg_temp = 7'b0011001; //4
   4'd5 : sseg_temp = 7'b0010010; //5
   4'd6 : sseg_temp = 7'b0000010; //6
   4'd7 : sseg_temp = 7'b1111000; //7
   4'd8 : sseg_temp = 7'b0000000; //8
   4'd9 : sseg_temp = 7'b0010000; //9
   default : sseg_temp = 7'b0111111; //dash
  endcase
 end
assign {g, f, e, d, c, b, a} = sseg_temp; 
assign dp = 1'b1; //we dont need the decimal here so turn all of them off



endmodule

The multiplexing circuit has been explained and commended in detail in my previous post here : Verilog LED Multiplexing Circuit.

Comments

  1. I was trying your code posted above and I get a warning of "Size mismatch between case item and case selector." on the case(sseg) part.
    Any help would be greatly appreciated.

    ReplyDelete
    Replies
    1. Hi,

      This usually happens when you are trying to write to register used in case(in this case sseg) in two different always blocks.

      Please check your code for this error.

      The above code was copied here from my xilinx IDE just before making the video demonstration, so I can assure you its error free.

      Delete
    2. Okay, well I copied the code from above directly and put it in my project in Xilinx 13.4 and get that warning in the Place & Route portion.
      This is all I am using in my ucf file:
      NET "clock" LOC = "B8"; # Bank = 0, Signal name = MCLK
      NET "reset" LOC = "M6"; # Bank = 2, Signal name = UCLK

      NET "an<3>" LOC = "K14"; # Bank = 1, Signal name = AN3
      NET "an<2>" LOC = "M13"; # Bank = 1, Signal name = AN2
      NET "an<1>" LOC = "J12"; # Bank = 1, Signal name = AN1
      NET "an<0>" LOC = "F12"; # Bank = 1, Signal name = AN0
      NET "dp" LOC = "N13"; # Bank = 1, Signal name = DP

      Delete
    3. Honestly if it is a warning and not an error, it can usually be ignored. Also which board are you using, is it the BASYS2? Here is my ucf file, you can try with this:

      # Pin assignment for pushbutton switches
      NET "reset" LOC = "a7";


      # Pin assignment for 7-segment displays
      NET "a" LOC = "l14" ;
      NET "b" LOC = "h12" ;
      NET "c" LOC = "n14" ;
      NET "d" LOC = "n11" ;
      NET "e" LOC = "p12" ;
      NET "f" LOC = "l13" ;
      NET "g" LOC = "m12" ;
      NET "dp" LOC = "n13" ;

      NET "an<3>" LOC = "k14";
      NET "an<2>" LOC = "m13";
      NET "an<1>" LOC = "j12";
      NET "an<0>" LOC = "f12";

      # Pin assignment for clock
      NET "clock" LOC = "b8";

      Delete
    4. Ah, that fixed it.
      Yes, it is with the BASYS2 FPGA.

      Thank you so much.

      Delete
    5. Hello, is there any way for a de-10 board pin planner for this project?

      Delete
  2. Can you help me ?

    i am having a problem using FPGA NEXYS 3 Spartan-6 ,

    for some reason it only shows number 9 ...

    is their problem with code or the assignments or both ?!

    another question ... how can i edit the code to make the maximum 10 or 15 for example ?

    ReplyDelete
    Replies
    1. Hello Jack,

      The above code has been tested to work on a BASYS2 board. I do not have a NEXYS 3. Most probably you might have to check your ucf file and see if your pin mapping is spot on.

      And to change the maximum to 15 or any number can be achieved by editing this code block:

      else if (first==4'd9) begin //x9 reached
      first <= 0;
      if (second == 4'd9) //99 reached
      second <= 0;
      else
      second <= second + 1;

      Delete
  3. Sir I confused why you use this-------assign test = &delay; I mean sir I know you use this here for .1 sec delay but sir why you not use------
    if(delay==24'b11111111_11111111_11111111)condition or event
    @(delay==24'b11111111_11111111_11111111) whenever delay register is filled with desired bit...........please clearify it specially &delay and why you use wire for test and not reg and why test is just I bit wide and not 23 bit wide like that of delay register....for making it global variable?

    ReplyDelete
    Replies
    1. For "assign test = &delay" I mentioned in comments the reason. The function of & is to logically AND every bit of delay with each other. So test will only be high when ALL the bits of delay are high, otherwise it will be 0 or low.

      Yes, you can use the if block you mentioned to achieve the same result, but this was easier and quicker.

      test is not inside any always block that is why its a wire and it is not supposed to retain its value outside of the module. Also you cannot use reg with assign.

      test is only a flag, it does not have to be 23 bits wide. 1 bit will suffice

      Delete
  4. sir, why are we checking 2 MSB's of counter and then accordingly we are enabling the anodes of display??

    ReplyDelete
    Replies
    1. hello Jyotsana,

      I believe you are talking about the counter related to the seven segment multiplexing. I have explained that in detain in my other post here: http://simplefpga.blogspot.co.uk/2012/07/seven-segment-led-multiplexing-circuit.html

      I believe you will get both your answers by reading that post.

      Regards

      Delete
  5. May i know what is function for the below coding?

    reg [6:0]sseg;
    reg [3:0]an_temp;
    always @ (*)
    begin
    case(count[N-1:N-2])

    2'b00 :
    begin
    sseg = first;
    an_temp = 4'b1110;
    end

    2'b01:
    begin
    sseg = second;
    an_temp = 4'b1101;
    end

    2'b10:
    begin
    sseg = 6'ha; //unknown sent to produce '-'
    an_temp = 4'b1011;
    end

    2'b11:
    begin
    sseg = 6'ha; //unknown sent to produce '-'
    an_temp = 4'b0111;
    end
    endcase
    end

    ReplyDelete
    Replies
    1. Thats the code for the seven segment LED multiplexing circuit. Read more about it here: http://simplefpga.blogspot.co.uk/2012/07/seven-segment-led-multiplexing-circuit.html

      Delete
  6. Hi, I have nexys 3 spartan 6 with 100Mhz bacesclock, I want to increment segment number every 0.5 second so delay register should consists 26 bits since log(0.5*100000000) / log (2) = 25.57, What about the COUNT register? I did not understand how to determinate it's size

    ReplyDelete
    Replies
    1. The method is explained in more detail here: http://simplefpga.blogspot.co.uk/2012/07/to-code-stopwatch-in-verilog.html

      Delete
  7. Hello everybody,

    can someone explain me the Pin Assignment for

    output [3:0]an

    Thanks in advance!

    ReplyDelete
    Replies
    1. Hi Dennis,

      The ``output[3:0]an`` is the 4 bit enable signal for multiplexing the four seven segment displays. It has been explained in detail in its own post here: http://simplefpga.blogspot.co.uk/2012/07/seven-segment-led-multiplexing-circuit.html

      Delete
  8. Do you have to have the delay? What is the point in having the delay?

    ReplyDelete
    Replies
    1. The delay is necessary for us, it allows us to see the count. Without the delay the count would increment so fast (at clock speed) we would not be able to see the numbers changing.

      Delete
  9. I want it to work with a push button so that when I press the button it counts by +1. How can I do that ?

    ReplyDelete
    Replies
    1. see my other posts where I have used buttons to control the code. To explain it briefly it should be similar to how we use the reset button, always @ (posedge reset).....

      Delete
  10. hi , i had one problem that i confused
    In this sample
    case(count[N-1:N-2]) , how does it work ? 
    why 2'b01 will choose the digit one , 2'b01 choose the digit two

    ReplyDelete
    Replies
    1. Hi, see 7 segment multiplexing explanation for your answer: http://simplefpga.blogspot.co.uk/2012/07/seven-segment-led-multiplexing-circuit.html

      Delete
  11. hi
    I have a problem in simulating this example in xilinx IDE
    I change value of clock manually but the output just has a X value i don't know why is that.
    could u help me?

    ReplyDelete
  12. Hello,
    i need to add one more logic i.e count from 99 to 00 when an extra input(assume top_down) is on. How can i make changes in the code.
    * Note :I want both 00 to 99 and from 99 to 00

    ReplyDelete
    Replies
    1. just subtract in stead of adding, if you want to do both then map two buttons for each task

      for example:

      always @ (posedge clock or posedge reset)
      begin
      if (reset)
      count <= 99;
      else
      count <= count - 1;
      end

      Delete
  13. Hi, i now want to reverse the numbers from 99 to 00 what changes should be done?

    ReplyDelete
    Replies
    1. just subtract instead of add:

      always @ (posedge clock or posedge reset)
      begin
      if (reset)
      count <= 99;
      else
      count <= count - 1;
      end

      Delete
  14. I edited your code and i was able to count up to 9999. i edited the code to display number 1234 but i'm not able to get it. Sir can you help me how I should approach to display four digit number eg:1234 with no counting. i removed the delay.

    ReplyDelete
    Replies
    1. if you just need to display the number 1234 then you dont need a counter, just follow this post:https://simplefpga.blogspot.co.uk/2012/07/seven-segment-led-multiplexing-circuit.html

      Delete
  15. Can you please post a vhdl code for this.

    ReplyDelete
  16. please i need a help!!! what will be the verilog code for 000-999 ?

    ReplyDelete
  17. I copied the code and executed,but it is showing error

    ReplyDelete
  18. hi sir !! I'm doing a digital countdown, but when I substitute a function of mine, it works fine with a fixed number, but it doesn't work when I use a variable... Can you explain?

    ReplyDelete

Post a Comment

Popular posts from this blog

To Code a Stopwatch in Verilog

The stopwatch coded here will be able to keep time till 10 minutes. It will be a 4 digit stopwatch counting from 0:00:0 till 9:59:9. The right most digit will be incremented every 0.1 second, when it reaches 9 it will increment the middle two digits, which represent the second count. When it reaches 59 seconds it will increment the right most minute display. The stopwatch will be in the format M:SS:D. How to Create an Accurate Delay in Verilog: To make the stop watch an accurate device we need to be able to produce an accurate 0.1 second delay. I have already explained how to do this before in my decimal counter in verilog post. But since it is of great importance to the design will be explained in more detail here. Since we know that the BASYS2 (the one I am using, yours may be different) has a 50 MHz clock which means that the clock cycle is repeated 50M times in one second. So to create a 0.1 second delay we multiply the clock with the required time: 50MHz * 0.1 sec =

Seven Segment LED Multiplexing Circuit in Verilog

The seven segment LED circuit uses seven different and individual LED's to display a hexadecimal symbol. It has 7 wires to control the individual LED's one wire to control the decimal point and one enable wire. The demo board I am using here consists of four such 7-segment LED's(As do any other demo board). To reduce the number of wires a multiplexing circuit is used to control the display. Using the multiplexing circuit the number of wires required to light up all 4 displays are reduced from 32 to 12 (8 data bits and 4 enable bits). All bits here are active low, such that to enable them a '0' is required. For example the figure below shows how to display a 3 on the seven segment. The multiplexing circuit can take 4 inputs and have only one output. But the inputs should be displayed on the output fast enough to fool the viewer into thinking all outputs are enabled individually and simultaneously. This is achieved by having an enable signal that changes so fast t

Random Number Generator in Verilog | FPGA

In verilog a random number can be generated by using the $random keyword but that works only for simulation purposes and cannot be implemented. So when we need a random number for implementation i.e. in hardware it can be achieved using an LFSR (Liner Feedback Shift Register). An LFSR is simply a shift register with some of its bits (known as taps) XOR'd with themselves to create a feedback term. When implementing an LFSR it's width and it's repeatability must be kept under consideration .An N-bit LFSR will be able to generate (2**N) - 1 random bits before it starts repeating. For example a 30 bit LFSR will have 1073741823 random states before repeating, so for most practical purposes this can be considered true random. In an LFSR the MSB will always be the feedback point also the main thing to take care of while coding an LFSR is to know which bits are the taps (to be selected for XOR ). This is confusing as the taps are different for different size registers. For e