Перейти к содержанию
    

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

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

Есть такая странная ситуация. Написал код для динамической индикации 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

image.thumb.png.d47e4ea1525c791773156bc9752b567b.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

44 минуты назад, agathodaimon сказал:

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

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

image.thumb.png.d47e4ea1525c791773156bc9752b567b.png

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, agathodaimon сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 hours ago, Plain said:

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

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

13 hours ago, Flip-fl0p said:

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

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

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, agathodaimon сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поскольку я пишу на 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_ сказал:

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

Зачем ? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 минут назад, Flip-fl0p сказал:

Зачем ?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, Vasily_ сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 hours ago, Vasily_ said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кажется, я понял в чем у меня проблема. На симуляторе сейчас все красиво, приду домой - проверю, если все ок, выложу свой код :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Изменено пользователем new123

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По сути тоже самое, что функция у 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;

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

38 минут назад, Nemos760 сказал:

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

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

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...