Question

I am a beginner so please excuse my code logic. I am trying to diplay 20 values on a 7 segment through a counter. When the value is greater than 9 the second segment is selected. When I run this code my first segment flickers very fast and the second one goes off. I know I have done some mistake with the case where i have assigned values to the segment. What am i missing here? My prescaled value is 48Hz. any ideas?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter is
Port ( clk : in  STD_LOGIC;
            segment : out  STD_LOGIC_VECTOR (6 downto 0);
            anode: out std_logic_vector (3 downto 0) );
end counter;

architecture Behavioral of counter is
constant prescaler: STD_LOGIC_VECTOR(16 downto 0) := "00000000000110000";
signal prescaler_counter: STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
signal counter: std_logic_vector (19 downto 0):= (others => '0');
signal r_anode: std_logic_vector (3 downto 0):= (others => '0');
begin
  process (clk) begin
  if (clk'event and clk = '1') then
    prescaler_counter <= std_logic_vector (unsigned(prescaler_counter) + 1);
        if(prescaler_counter = prescaler) then
                counter <= std_logic_vector (unsigned(counter)+1);
            end if;
   end if;
  end process;

anode <= r_anode;

 process  (counter) begin
  if (counter > "00000000000000001001") then
    r_anode <= "1110"; 
  else
    r_anode <= "1101";
 end if;    
 case counter is
 when "00000000000000000000" => segment <= "0000001"; --0
 when "00000000000000000001" => segment <= "1001111"; --1
 when "00000000000000000010" => segment <= "0010010"; --2
 when "00000000000000000011" => segment <= "0000110"; --3
 when "00000000000000000100" => segment <= "1001100"; --4
 when "00000000000000000101" => segment <= "0100100"; --5
 when "00000000000000000110" => segment <= "0100000"; --6
 when "00000000000000000111" => segment <= "0001111"; --7
 when "00000000000000001000" => segment <= "0000000"; --8
 when "00000000000000001001" => segment <= "0000100"; --9   
 when others => segment <= "1111111"; 
 end case;  
 end process;

end Behavioral;
Was it helpful?

Solution

48Hz still seems pretty fast to cycle through 10 values for a digit, but if that's what you want... (if you slowed it down, the problem might become more obvious, by the way)

The problem is a combination of your count process, how you're setting r_anode, and your case statement to determine the value of segment, possibly among other things.

  1. Your count process goes from 1 to, well, a lot, and you only want to go to 20, as I understand it. You may want to consider adding a wraparound condition. That depends on how you do the following, though.

  2. r_anode is "1110" for 10 clocks and then "1101" for the rest of the 2^20 cycles. I don't think this is what you want. By the way, with numeric_std, you can just write unsigned(counter) > 9 - I'm not sure what you have written should even compile (you were using std_logic_unsigned before, I gather?).

  3. This is the main problem. You seem to want the values for both of your digits to depend on this one counter, but you are comparing the entire 20-bit counter value, so segments are only active for 10 clocks out of 2^20, and only on for the first digit, since you're explicitly checking only values 0 through 9. What you need is some sort of a modulus operation (or separate counters for each digit, or something).

You may also need to think about how you are driving the two displays, but that depends on how you fix the other issues.

OTHER TIPS

I was in the middle of getting this ready to display when fru1bat answered. It may provide illumination:

counter_tb

Note I used a 10 ns clock for sake of expediency.

The first digit goes through it's counts (seen on segment) then switches to the other digit, who's segments show the others choice):

process  (counter) 
begin
    if (counter > "00000000000000001001") then
        r_anode <= "1110"; 
    else
        r_anode <= "1101";
    end if;    
    case counter is
        when "00000000000000000000" => segment <= "0000001"; --0
        when "00000000000000000001" => segment <= "1001111"; --1
        when "00000000000000000010" => segment <= "0010010"; --2
        when "00000000000000000011" => segment <= "0000110"; --3
        when "00000000000000000100" => segment <= "1001100"; --4
        when "00000000000000000101" => segment <= "0100100"; --5
        when "00000000000000000110" => segment <= "0100000"; --6
        when "00000000000000000111" => segment <= "0001111"; --7
        when "00000000000000001000" => segment <= "0000000"; --8
        when "00000000000000001001" => segment <= "0000100"; --9   
        when others => segment <= "1111111"; 
    end case;  
end process;

From that we can imagine you'll see every segment in the 'fast' digit flicker, followed by a long interval waiting for counter to roll over, then flicker again.

Both the prescaler counter and counter seem too long.

You want to switch through enabled anodes, meaning the switch should be between one digit and the other. That should be a bit faster than 48 Hz more than likely. (LCD or LED?).

You want the counter that drives segment to be much slower. Start out with 48 Hz to switch anode values between the two display digits using counter's LSB. Use bits from toward the other end of counter to drive the seven segement conversion. You want the digits to change slow enough to see. Also note that because counter isn't a BCD counter (now there's an idea), there will be blank displayed times for any four bits when those are greater than 9 as an aggregate.

You could always drive 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F (by modifying your case statement). This will allow you to pick a prescaler value that gives you minimum flicker.

I don't recommend simply simulating your design, I did it to make the same points fru1bat covered. I wanted the picture. I stopped it about 1/10th of the way through (was going to run for 2 seconds, got 186 MB of clock transitions as it is).

I posted this code and I figured out my errors thanks to @fru1bat and @David. Yes I was using a 20 bit counter which was really dumb of me so i used a 5 bit counter and slowed my clock with this delay code.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity delay is
Port ( clk : in  STD_LOGIC;
       a : in  STD_LOGIC_VECTOR (31 downto 0);
       flag : out  STD_LOGIC);
end delay;

architecture Behavioral of delay is
signal count :integer:=0;
    begin
    process(clk) begin

        if(clk'event and clk='1') then
            count <= count +1;   --increment counter.
        end if;
        --see whether counter value is reached,if yes set the flag.
            if(count = to_integer (unsigned(a))) then 
                count <= 0;
                flag <='1';
            else
                flag <='0';
            end if;
    end process;

end Behavioral

And then I used this code in my 7 segment code, which for now turns on only one segment, it starts form 0 and goes till 9, after reaching 9 the counter resets. Now my question is how should I display two digits? Should I use the double dabble algorithm here? Or what? My basic issue of flickering is gone now I need to turn on the second segment to display two digits using this same code. How should i modify my code? Any ideas? Here is my final one digit code!

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter is
Port ( clk : in  STD_LOGIC;
            segment : out  STD_LOGIC_VECTOR (6 downto 0);
            anode: out std_logic_vector (3 downto 0) );
end counter;

 architecture Behavioral of counter is

 component delay
 Port ( clk : in  STD_LOGIC;
       a : in  STD_LOGIC_VECTOR (31 downto 0);
       flag : out  STD_LOGIC);
end component;

signal flag : std_logic :='0';
signal delay_needed : std_logic_vector(31 downto 0); 
constant countvalue: STD_LOGIC_VECTOR (4 downto 0) := "01001";
signal counter: std_logic_vector (4 downto 0):= (others => '0');
    signal r_anode: std_logic_vector (3 downto 0):= (others => '0');

begin
    delay_needed <=  "00000001011111010111100001000000";  --25000000 in binary

    inst_delay : delay port map(clk,delay_needed,flag);  

 process (flag) begin

  if (flag'event and flag = '1') then
        counter <= std_logic_vector (unsigned(counter)+1);
            if (counter = countvalue) then
                counter <= (others => '0');
            end if;
    end if;
  end process;

        anode <= r_anode;
        r_anode <= "1110"; 

process (counter, r_anode) begin
case r_anode is 
        when "1110" => case counter is 
                                    when "00000" => segment <= "0000001"; --0
                                    when "00001" => segment <= "1001111"; --1
                                    when "00010" => segment <= "0010010"; --2
                                    when "00011" => segment <= "0000110"; --3
                                    when "00100" => segment <= "1001100"; --4
                                    when "00101" => segment <= "0100100"; --5
                                    when "00110" => segment <= "0100000"; --6
                                    when "00111" => segment <= "0001111"; --7
                                    when "01000" => segment <= "0000000"; --8
                                    when "01001" => segment <= "0000100"; --9
                                    when others => segment <= "1111111";
                                    end case;
    when others => segment <= "1111111";
    end case;   
 end process;

end Behavioral;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top