Jump to content

    
Sign in to follow this  
agathodaimon

Семисегментный индикатор, странное поведение

Recommended Posts

Добрый день, форумчане.

Есть такая странная ситуация. Написал код для динамической индикации 7-сегментного индикатора. Все работает, однако наблюдаю странное поеведение. Разряд, который выступает следующим, светится тускло знаком предыдущего.

Может кто увидит сразу и дкнет в проблему? пытался гуглить примеры, но они вроде от моего кода не слишком отличаются.

Плис Altera Cyclone 4, EDI Quartus.

module helloworlds (
	input [3:0]btn, output [3:0]led ,
	output reg [3:0] digits,
	output reg [7:0] dots,
	output speaker,
	input clk);
	assign led[0] = btn[0];
		
	reg [23:0]CTCQ;
	reg [16:0]CTFQ;
	reg [16:0]freq;
	reg [1:0]dig = 2'd0;
	reg [3:0]curr_digit;
	reg [15:0]CNT;
	reg strobe = 1;
	reg [7:0]strobe_ct = 0;
	always @(posedge clk)
	begin
		CTCQ <= CTCQ + 1'd1;
		if (curr_digit == 4'd0 || curr_digit == 4'd8)
			CTFQ <= CTFQ + 1'd1;
		else
			CTFQ <= 14'd0;
		
		strobe_ct <= strobe_ct + 1'd1;
		
		if(strobe_ct == 8'hff) begin
			dig <= dig + 1'd1;
		end
		
		if(strobe_ct > 8'hf0) begin
			strobe = 0;
		end else begin
			strobe = 1;
		end
		
		curr_digit <= CNT >> (dig * 4);				
		
		case(dig)
			2'd0:
				digits = ~4'd1;
			2'd1:
				digits = ~4'd2;
			2'd2:
				digits = ~4'd4;
			2'd3:
				digits = ~4'd8;
		endcase
	//
	//     ___
	//  b | g | f
	//    |___|
	//    | a |
	//  c |___| e
	//		  d
		if (strobe)
		begin
			case(curr_digit)// ABCDEFG
				4'h0: dots = ~7'b0111111;
				4'h1: dots = ~7'b0000110;
				4'h2: dots = ~7'b1011011;
				4'h3: dots = ~7'b1001111;
				4'h4: dots = ~7'b1100110;
				4'h5: dots = ~7'b1101101;
				4'h6: dots = ~7'b1111101;
				4'h7: dots = ~7'b0000111;
				4'h8: dots = ~7'b1111111;
				4'h9: dots = ~7'b1101111;
				4'ha: dots = ~7'b1110111;
				4'hb: dots = ~7'b1111100;
				4'hc: dots = ~7'b0111001;
				4'hd: dots = ~7'b1011110;
				4'he: dots = ~7'b1111001;
				4'hf: dots = ~7'b1110001;
			endcase
		end else begin
			dots = ~7'b0000000;
		end
		
	end

	// Speaker wire
	//assign speaker = CTFQ[16];
	
	//always @(posedge CTCQ[23]) CTQ <= CTQ + 1'd1;
	always @(posedge CTCQ[23]) CNT <= CNT + 1'd1;
	//always digits = 4'd0;

endmodule

Моделирование пока не освоил... пока что не разобрался как это сделать. Выглядит это примерно как на фото, правда плохо видно. Четверка самого верхнего сегмента отдает восьмеркой, которая является предыдущем.

Буду признателен любой наводке)

photo_2020-11-22_22-42-47.jpg

Share this post


Link to post
Share on other sites

Правда, симуляция говорит ровно то, что я вижу своими глазами. Переключение digits происходит до смены значения на dots.

осталось теперь понять, почему это происходит)

image.thumb.png.d47e4ea1525c791773156bc9752b567b.png

Share this post


Link to post
Share on other sites
44 минуты назад, agathodaimon сказал:

Правда, симуляция говорит ровно то, что я вижу своими глазами. Переключение digits происходит до смены значения на dots.

осталось теперь понять, почему это происходит)

image.thumb.png.d47e4ea1525c791773156bc9752b567b.png

Разбивайте код на логические модули.

Есть декодер семисегментного индикатора - значит оформляйте это в отдельный модуль. Чем легче читается код - тем проще найти в нем ошибки. 

Динамическая индикация для семисегментного индикатора - это по сути кольцевой сдвиговый регистр, где единичка бегает по кругу. В вашем коде это сделано неочевидно. через присвоение значений 1, 2, 4, 8 .

А вообще такие штуки лучше делать цифровыми автоматами. И читаются легко, и поддерживаются легко. И при должном навыке занимают минимум ресурсов. Но при этом легко масштабируются.

 

Share this post


Link to post
Share on other sites
3 часа назад, agathodaimon сказал:

Все работает, однако наблюдаю странное поведение. Разряд, который выступает следующим, светится тускло знаком предыдущего.

Ничего странного. Сегмент сначала нужно выключить, и только потом включить следующий.

Share this post


Link to post
Share on other sites
14 hours ago, Plain said:

На какой частоте это работает?

На железке clk напрямую от кварца - 50МГц

13 hours ago, Flip-fl0p said:

Разбивайте код на логические модули.

Есть декодер семисегментного индикатора - значит оформляйте это в отдельный модуль. Чем легче читается код - тем проще найти в нем ошибки. 

Динамическая индикация для семисегментного индикатора - это по сути кольцевой сдвиговый регистр, где единичка бегает по кругу. В вашем коде это сделано неочевидно. через присвоение значений 1, 2, 4, 8 .

А вообще такие штуки лучше делать цифровыми автоматами. И читаются легко, и поддерживаются легко. И при должном навыке занимают минимум ресурсов. Но при этом легко масштабируются.

Да, спасибо! я и сам планировал разбить, только хотел вначале привести к рабочему варианту)

По поводу сдвигового регистра, там получается выбор, либо сдвигать, и делать case на вот эту строчку

curr_digit <= CNT >> (dig * 4);	

либо оставлять как было.

Share this post


Link to post
Share on other sites
3 минуты назад, agathodaimon сказал:

curr_digit <= CNT >> (dig * 4);	

Ну так этот генератор случайных чисел у Вас на системной частоте молотит — другого предназначения этой загогулины не видно, никаких данных для вывода на этот дисплей на входе модуля не указано.

Share this post


Link to post
Share on other sites

Поскольку я пишу на VHDL - то думаю могу приложить пример как бы я написал вывод на семисегментный индикатор. 

В моем примере перевод из двоичного кода осуществляется при помощи функции. Можно в виде отдельного модуля. Я тут показываю суть: есть 4 знака семисегментного индикатора. Для каждого знака индикатора описано свое состояние автомата, в котором этот знак включается. В этом же состоянии описано что за значение выводить на сегмент индикатора.  Потом автомат переходит в следующее состояние, в котором зажигается новый знак. И так циклически автомат переключается по всем знакам. 

library IEEE;
    use IEEE.std_logic_1164.all;

entity sign is
    port 
    (
        clk                 : in  std_logic;
        in_sign0_tdata      : in  std_logic_vector(3 downto 0); -- Значение, которое нужно вывести на нулевом разряде индикатора 
        in_sign1_tdata      : in  std_logic_vector(3 downto 0);
        in_sign2_tdata      : in  std_logic_vector(3 downto 0);
        in_sign3_tdata      : in  std_logic_vector(3 downto 0);
        sign_enable         : out std_logic_vector(3 downto 0); -- Включение сегмента 
        out_7SEGMENT_TDATA  : out std_logic_vector(6 downto 0)  -- Значение, выдаваемое на сегмент
    );
end entity;

architecture RTL of sign is
    
    -- ===========================================================
    -- Функция возвращающая код семисегментного индикатора
    -- ===========================================================
    function GET_7SEGMENT_CODE
    (
        binary_code : std_logic_vector       
    )
        return std_logic_vector is
    begin   
        case binary_code is 
            when x"0"    => return "0111111"; 
            when x"1"    => return "0000110"; 
            when x"2"    => return "1011011"; 
            when x"3"    => return "1001111"; 
            when x"4"    => return "1100110"; 
            when x"5"    => return "1101101"; 
            when x"6"    => return "1111101"; 
            when x"7"    => return "0000111"; 
            when x"8"    => return "1111111"; 
            when x"9"    => return "1101111"; 
            when x"A"    => return "1110111"; 
            when x"B"    => return "1111100"; 
            when x"C"    => return "0111001"; 
            when x"D"    => return "1011110"; 
            when x"E"    => return "1111001"; 
            when x"F"    => return "1110001"; 
            when others  => return (others => '-');
        end case;
    end function;
	
    type FSM_state is
    (
        SIGN0  ,                              
        SIGN1  ,
        SIGN2  ,
        SIGN3
    );
    signal press_state, next_state : FSM_state := SIGN0;
    signal sign_TDATA : std_logic_vector(3 downto 0);

begin

    --========================================================
    -- Процесс переключения состояний автомата
    --========================================================
    press_state_to_next_state : process(clk)
    begin         
        if (rising_edge(clk)) then
            press_state <= next_state;
        end if;
    end process;

    --========================================================
    -- Процесс вычисления следующего состояния автомата
    --========================================================
    next_state_calk : process(all)
    begin
        case press_state is 
            when SIGN0    =>  next_state <= SIGN1;                         
            when SIGN1    =>  next_state <= SIGN2;
            when SIGN2    =>  next_state <= SIGN3;
            when SIGN3    =>  next_state <= SIGN0;
            when others   =>  next_state <= SIGN0;
        end case;
    end process;
    
    --========================================================
    -- Выходная логика работы автомата 
    --========================================================
    FSM_output_logic : process(all)
    begin
        sign_enable        <= (others => '-');
        sign_TDATA         <= (others => '-');
        case press_state is 
            when SIGN0    =>  
                            sign_enable <= "0001";                  -- Зажигаем нужный разряд 
                            sign_TDATA  <= in_sign0_tdata;          -- На этот разряд выводим нужную нам цифру
            --======================================================================
            when SIGN1    =>    
                            sign_enable <= "0010";   
                            sign_TDATA  <= in_sign1_tdata;
            --======================================================================
            when SIGN2    =>  
                            sign_enable <= "0100";   
                            sign_TDATA  <= in_sign2_tdata;
            --======================================================================
            when SIGN3    =>  
                            sign_enable <= "1000";   
                            sign_TDATA  <= in_sign3_tdata;
            --======================================================================
            when others   =>  null;
        end case;
    end process;

    out_7SEGMENT_TDATA <= GET_7SEGMENT_CODE(sign_TDATA);


end architecture;

P.S. Интересно почему студентов не учат именно автоматному проектированию, как самому быстрому, простому и надежному способу описывать свои схемы ? 

20 часов назад, Vasily_ сказал:

Ничего странного. Сегмент сначала нужно выключить, и только потом включить следующий.

Зачем ? 

Share this post


Link to post
Share on other sites
27 минут назад, Flip-fl0p сказал:

Зачем ?

Что-бы не было подсветки соседнего сегмента, или вы считаете что светодиоды не имеют инерции?

Share this post


Link to post
Share on other sites
19 минут назад, Vasily_ сказал:

Что-бы не было подсветки соседнего сегмента, или вы считаете что светодиоды не имеют инерции?

При правильно подобранной частоте тактирования инерцией светодиода можно смело пренебречь. Конечно если каждые 5..10 нс. переключать сегменты нужно будет учитывать это. А если переключать раз в миллисекунду, то на инерцию пофиг, если у нас тас не весит конденсатор))

Share this post


Link to post
Share on other sites
11 hours ago, Vasily_ said:

Что-бы не было подсветки соседнего сегмента, или вы считаете что светодиоды не имеют инерции?

Не очень понятно, как связана инерция диода и подсветка соседнего сегмента. Соседний сегмент - это другой диод. Чтобы не было засветки надо обеспечить одновременное переключение сигналов. Или дэдтаймы.

Share this post


Link to post
Share on other sites

Если что, у альтеры в cookbook есть пример семисегментного дисплея + последние квартусы могут генерить уже готовые шаблоны модули этого дела. Но там как то все просто до безобразия

Edited by new123

Share this post


Link to post
Share on other sites

По сути тоже самое, что функция у Flip-Flop, только в виде модуля и выводит в 16-коде. На вход подаются уже готовые данные из другого модуля (выход мультиплексора, управляемого машиной состояний). Никакой проблемы с засветкой никогда не наблюдал.

И да, с функцией было бы удобнее.

Quote

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity HEX_encoder is

    port(
        DATA: in unsigned(3 downto 0);
        HEX: out std_logic_vector(6 downto 0)
    );
    
end entity HEX_encoder;

architecture rtl of HEX_encoder is
    
begin

    with to_integer(DATA) select HEX<=
        "1000000" when 16#0#,
        "1111001" when 16#1#,
        "0100100" when 16#2#,
        "0110000" when 16#3#,
        "0011001" when 16#4#,
        "0010010" when 16#5#,
        "0000010" when 16#6#,
        "1111000" when 16#7#,
        "0000000" when 16#8#,
        "0010000" when 16#9#,
        "0001000" when 16#A#,
        "0000011" when 16#B#,
        "1000110" when 16#C#,
        "0100001" when 16#D#,
        "0000110" when 16#E#,
        "0001110" when 16#F#,
        "1111111" when others;
        
end rtl;

 

 

Share this post


Link to post
Share on other sites
38 минут назад, Nemos760 сказал:

По сути тоже самое, что функция у Flip-Flop, только в виде модуля и выводит в 16-коде. На вход подаются уже готовые данные из другого модуля (выход мультиплексора, управляемого машиной состояний). Никакой проблемы с засветкой никогда не наблюдал.

И да, с функцией было бы удобнее.

 

 

Я предпочитаю преобразователь из двоичного в семи сегментный держать в виде отдельного модуля с параметром каким логичесим уровнем зажигать сегмент. Хотя все чаще и чаще я стал в своём коде применять различного рода функции, хоть раньше этого и не любил.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this