- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 4 von 4

Thema: VHDL unerklährliche Wartezeit nach Tastendruck

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    22.03.2007
    Beiträge
    15

    VHDL unerklährliche Wartezeit nach Tastendruck

    Hallo Leute,

    ich habe hier meine ersten Schritte in VHDL gepostet. Das Programm lässt eine LED mit verschiedenen Frequenzen (je nach Tastereingabe blinken).
    Drückt man Taster 1 (sBtn0_i), Taster 2 (sBtn1_i) oder Taster 3 (sBtn2_i), dann blinkt die LED entweder mit 0,125Hz, 0,25Hz, oder 0,5 Hz.

    Haupt-Entity mit eigentlichem Blink-Prozess ganz am Ende ist:

    Code:
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all;
    use ieee.std_logic_arith.all;
    
    
    
    entity blinky_tast_top is
      
      generic (
        iTWaitDebounce				: integer range 0 to 99999999 := 50000
      );
      
      port (
    	sClk_i						: in  std_logic;
    	sBtn0_i, sBtn1_i, sBtn2_i	: in  std_logic;
    	sLed_o						: out std_logic
       );
       
    end;
    
    
    
    architecture rtl of blinky_tast_top is
      
      
      -- components -----------------------------------------------------------------------
      
      component debouncer
      
    	generic (
          iTWait			: integer range 0 to 99999999
        );
        
        port (
          sClk_i, sRst_i	: in std_logic;
          sPb_i				: in std_logic;
          sPb_debounced_o	: out std_logic
        );
        
      end component;
      
      
      -- signals -------------------------------------------------------------------------
      
      signal sCnt_s							: std_logic_vector(27 downto 0) := x"0000000";
      signal sLed_s							: std_logic :='0';
      signal iTimeCnt_s						: integer range 0 to 99999999 := 50000000;
      signal sBtn0_s, sBtn1_s, sBtn2_s		: std_logic := '1';
      
      
      
    begin
    
    
    
      
    ---===============================Debounce Button 1===============================---
    
      DebounceBtn0: debouncer
        generic map (
          iTWait => iTWaitDebounce
        )
        port map (
    	  sClk_i => sClk_i,
    	  sRst_i => 'L',            -- Reset not required -> always "low"
          sPb_i  => sBtn0_i,
    	  sPb_debounced_o => sBtn0_s
        );
    
    
    
       
    ---===============================Debounce Button 2===============================---
    
      DebounceBtn1: debouncer
        generic map (
          iTWait => iTWaitDebounce
        )
        port map (
    	  sClk_i => sClk_i,
    	  sRst_i => 'L',			-- Reset not required -> always "low"
          sPb_i  => sBtn1_i,
    	  sPb_debounced_o => sBtn1_s
        );
    
    
    
        
    ---===============================Debounce Button 3===============================---
    
      DebounceBtn2: debouncer
        generic map (
          iTWait => iTWaitDebounce
    	  )
        port map (
    	  sClk_i => sClk_i,
    	  sRst_i => 'L',			-- Reset not required -> always "low"
          sPb_i  => sBtn2_i,
    	  sPb_debounced_o => sBtn2_s
        );
    
    
    
    
    ---================Change the blinking frequency by Button input==================---
    
      DetectSpeed: process(sClk_i)
      begin
          
        if (sBtn0_s = '0') then
            
          iTimeCnt_s <= 12500000;
          
        elsif (sBtn1_s = '0') then
            
          iTimeCnt_s <= 25000000;
        
        elsif (sBtn2_s = '0') then
      
          iTimeCnt_s <= 50000000;
            
        end if;      
      end process;
    
    
    
    
    ---===============================Toggle the LEDs=================================---
      
      Toggle: process(sClk_i)			-- sClk_i -> 50Mhz
      begin
        if rising_edge(sClk_i) then
    	  
    	  sCnt_s <= sCnt_s + 1;			-- every clock cycle -> increment
    	  
    	  if sCnt_s = iTimeCnt_s then	-- increment until count = 12500000 (Btn0)or 25000000 (Btn1) or 50000000 (Btn2)
    	  
    	    sCnt_s <= (others=>'0');	-- reset counter
    	    sLed_s <= not sLed_s;		-- toggle LED
    	  
    	  end if;
        end if;
      end process;
    
      sLed_o <= sLed_s;
      
    end;
    Und die Entity der Entprell-Routine:

    Code:
    library ieee;
    use ieee.std_logic_1164.all;
    
    
    
    entity debouncer is
      
      generic (
        iTWait			: integer range 0 to 99999999
      );
      
      port (
        sClk_i, sRst_i	: in std_logic; -- clk frequency = 50Mhz
        sPb_i			: in std_logic;
        sPb_debounced_o	: out std_logic
      );
      
    end entity debouncer;
    
    
    
    architecture rtl of debouncer is
    
    
      -- signals ------------------------------------------------------------------------   
    
      signal iCntWait_s	: integer range 0 to 99999999;
      signal sClkDiv_s	: std_logic;
      signal sPb_sampled_s	: std_logic;
    
    
    begin
    
    
    
    ---===============================Divide Frequency===============================---
    
      DivideFrequency: process(sClk_i, sRst_i)
      begin
       
        if sRst_i = '1' then
    
          sClkDiv_s <= '0'; 
          iCntWait_s <= 0;
    
        elsif rising_edge(sClk_i) then
      
          if iCntWait_s = iTWait then
    	    iCntWait_s <= 0;
    	    sClkDiv_s <= '1';
    	  else
    	    iCntWait_s <= iCntWait_s + 1;
    	    sClkDiv_s <= '0';
    	  end if;
      
        end if;
      end process DivideFrequency;
    
    
    
    ---============================Debounce Push Button===============================---
    
      debounce_pb: process(sClk_i) is
      begin
        if rising_edge(sClk_i) then
    
    	  if sClkDiv_s='1' then
            if sPb_i = sPb_sampled_s then
    	      sPb_debounced_o <= sPb_i;
    	    end if;
    	  end if;
    	
    	  sPb_sampled_s <= sPb_i;
    	
        end if;
      end process debounce_pb;
      
    end architecture rtl;
    Wenn ich den Button 3 (sBtn2_i) drücke, verharrt die LED 5 s (also eine Ewigkeit, wenn man bedenkt, dass der Eingangstakt 50 MHz beträgt) in ihrem Zustand, bevor sie die Dem Knopfdruck entsprechende Frequenz annimmt. Dies passiert aber nur wenn ich gerade diesen Button drücke. Bei den anderen kommt dies nicht vor und ich kann mir dieses Verhalten nicht erklären.

    Weiß jemand, woran dies liegen könnte, oder wo ich nach dem Fehler suchen kann.

    Ich würde mich freuen, wenn vielleicht ein erfahrener VHDL-Programmierer prinzipiell seine Meinung zum Code abgeben könnte. Wie gesagt, es ist mein erster!

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    22.03.2007
    Beiträge
    15
    Ich habe gestern den Code nochmal etwas geändert:

    - Ich habe die Entprell-Routine rausgeworfen, da ich gesehen habe, dass bei den Tastern RC-Glieder sind, mit einer Zeitkonstante von 100ms.

    - Ich habe die Sensitivity List den Prozess geändert, der die Tasten abfragt. Zum einen habe ich die Taktfrequenz aus der Sensitivity-List herausgenommen, und stattdessen die Tastersignale reingepackt. Es ist ja sinnvoller den Prozess aufzurufen, wenn sich ein Taster ändert. Ausserdem habe ich einen 4-ten Taster eingebaut. Bei dessen Betätigung wird eine Subtraktion zur Reduktion des Zählersignals (iTimeCnt_s) ausgeführt. Dieses Signal legt fest wie lange der Zähler hochzählt bis die LED getoggelt wird und bestimmt damit die Blinkfrequenz festlegt. Ziel ist es also damit die Blinkfrequenz durch Tastendruck stetig zu erhöhen. Aufgrund dieser Subtraktionsoperation hab ich alle Variablen des Zählers (iCnt_s iTimeCnt), zu Integer gemacht.

    Hier der entsprechende Code des geänderten Prozesses:

    Code:
    ---================Change the blinking frequency by Button input==================---
      
      DetectSpeed: process(sBtn0_i, sBtn1_i, sBtn2_i, sBtn3_i)
      begin
            
        if (sBtn0_i = '0') then
            
          iTimeCnt_s <= 12500000;
          
        elsif (sBtn1_i = '0') then
            
          iTimeCnt_s <= 25000000;
        
        elsif (sBtn2_i = '0') then
        
          iTimeCnt_s <= 50000000;
          
        elsif (sBtn3_i = '0') and (iTimeCnt_s > 12500000) then
          
          iTimeCnt_s <= iTimeCnt_s - 12500000;
        
        end if;      
      end process;
    Und der gesamte Code des Projektes, das jetzt nur noch aus einer Entity besteht, da die Entprellung rausgeflogen ist:

    Code:
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    use ieee.std_logic_arith.all;
    
    
    
    entity blinky_tast_top is
       
      port (
    	sClk_i								: in  std_logic;
    	sBtn0_i, sBtn1_i, sBtn2_i, sBtn3_i	: in  std_logic;
    	sLed_o								: out std_logic
       );
       
    end;
    
    
    
    architecture rtl of blinky_tast_top is
      
      
      -- signals -------------------------------------------------------------------------
      
      signal svCnt_s								: integer range 0 to 99999999 := 0;
      signal iTimeCnt_s								: integer range 0 to 99999999 := 50000000;
      signal sLed_s									: std_logic :='0';
      signal sBtn0_s, sBtn1_s, sBtn2_s, sBtn3_s		: std_logic := '1';
      
      
      
    begin
    
    
    
    ---================Change the blinking frequency by Button input==================---
      
      DetectSpeed: process(sBtn0_i, sBtn1_i, sBtn2_i, sBtn3_i)
      begin
            
        if (sBtn0_i = '0') then
            
          iTimeCnt_s <= 12500000;
          
        elsif (sBtn1_i = '0') then
            
          iTimeCnt_s <= 25000000;
        
        elsif (sBtn2_i = '0') then
        
          iTimeCnt_s <= 50000000;
          
        elsif (sBtn3_i = '0') and (iTimeCnt_s > 12500000) then
          
          iTimeCnt_s <= iTimeCnt_s - 12500000;
        
        end if;      
      end process;
    
    
    
    
    ---===============================Toggle the LEDs=================================---
      
      Toggle: process(sClk_i, iTimeCnt_s)	-- sClk_i -> 50Mhz
      begin
        if rising_edge(sClk_i) then
    	  
    	  svCnt_s <= svCnt_s + 1;		-- every clock cycle -> increment
    	  
    	  if svCnt_s = iTimeCnt_s then	-- After several Time (iTimeCnt_s):
    									--
    	    svCnt_s <= 0;				--  -> reset counter
    	    sLed_s <= not sLed_s;		--  -> toggle LED
    	  
    	  end if;
        end if;
      end process;
    
      sLed_o <= sLed_s;
      
    end;
    Leider funktioniert das mit der Subtraktion noch nicht. Und wieder einmal weiß ich nicht, was ich falsch gemacht habe. Wenn ich beispielsweise die zweite Taste betätige (sBtn1_s) habe ich Zählt der Counter bis 25000000. Wenn ich danach die neu hinzugefügte Taste betätige, sollte der counter (25000000-12500000=12500000) die Blinkfrequenz verdoppeln. Tut er aber nicht. Stattdessen blinkt die LED langsamer. Ich habe aber nirgends einen Überlauf oder ähnliches

    Kann jemand mit Erfahrung die Subtraktion mal beurteielen? Ich kann doch mit Integer addieren und subtrahieren ...

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    04.11.2007
    Beiträge
    100
    Hallo!

    vorab: ich bin leider jemand der _nicht_ viel Erfahrung hat...

    So ganz verstehe ich daher das Programm noch nicht. Soweit ich das überblicke wird iTimeCnt_s geändert wenn du eine Taste drückst. Aber was ist wenn zu dem Zeitpunkt svCnt_s schon größer ist als der neue iTimeCnt_s Wert?

    Kann es außerdem nicht passieren, daß an der Stelle

    elsif (sBtn3_i = '0') and (iTimeCnt_s > 12500000) then ....

    die Subtraktion mehrfach ausgeführt wird (so lange wie man den Knopf gedrückt hält)? Muß man da nicht noch auf eine Flanke triggern oder so was?

    Warum die LED langsamer blinkt erschließt sich mir im Augenblick aber auch nicht. Ist sicher was ganz einfaches, offensichtliches .. wie immer

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    04.11.2007
    Beiträge
    100
    Hallo nochmal!

    Ich habe deinen Code ausprobiert. Folgende Beobachtungen:

    - beim 1. Einschalten ist das Blinken besonders langsam (ungefähr nur halb so schnell wie die mit sBtn2_i einstellbare Frequenz) - irgendwas mit der initialisierung der Werte?!?
    - durch drücken von Taste 4 wird immer gleich auf die schnellste Blinkrate geschaltet - es wird also vermutlich mehrfach subtrahiert
    - manchmal dauert es nach Druck einer Taste extra lange bevor die gewünschte Operation ausgeführt wird - vermutlich Überlauf weil svCnt_s schon weiter ist als der neue gewünschte Endwert

    Ich vermute die Sache ist vielleicht nicht so synthetisierbar wie beabsichtigt. Der Prozess DetectSpeed ist als kombinatorischer Prozess angegeben aber der Ausdruck
    iTimeCnt_s <= iTimeCnt_s - 12500000;
    ist wohl nicht rein kombinatorisch sondern bezieht sich auf den eigenen früheren Wert. Wenn ich das richtig verstehe darf sowas nur in getakteten Prozessen vorkommen da nur dann das vorher und nachher eindeutig geregelt ist.

    Quelle: Grundregeln für synthetisierbaren VHDL-Code

    Wenn man das Ändern der Blinkfrequenz mit in den Clock Prozess stopft wird es zwar unübersichtlich - aber es scheint zu funktionieren..

    Code:
    
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;
    
    
    
    entity blinky_tast_top is 
      
      port ( 
       sClk_i                        : in  std_logic; 
       sBtn0_i, sBtn1_i, sBtn2_i, sBtn3_i   : in  std_logic; 
       sLed_o                        : out std_logic 
       ); 
        
    end; 
    
    
    
    architecture rtl of blinky_tast_top is 
      
      -- signals ------------------------------------------------------------------------- 
      
      signal svCnt_s       : integer range 0 to 99999999 := 0; 
      signal iTimeCnt_s    : integer range 0 to 99999999 := 50000000;
      signal sLed_s        : std_logic :='0'; 
      signal sBtn3_s       : std_logic :='1';  -- remember last state of sBtn3_i in sBtn3_s
      
    begin 
    
    
    
    ---==Toggle the LEDs and change the blinking frequency by Button input==--- 
      
      Toggle: process(sClk_i)   -- sClk_i -> 50Mhz 
      begin 
        if rising_edge(sClk_i) then 
         
         svCnt_s <= svCnt_s + 1;      -- every clock cycle -> increment 
         
         if svCnt_s = iTimeCnt_s then   -- After several Time (iTimeCnt_s): 
    
           svCnt_s <= 0;              --  -> reset counter 
           sLed_s <= not sLed_s;      --  -> toggle LED 
         
         end if; 
    	  
    	  
    	  
    	  
         --  change the blinking frequency by Button input:	  
    
         if (sBtn0_i = '0') then 
            
           iTimeCnt_s <= 12500000; 
          
         elsif (sBtn1_i = '0') then 
            
           iTimeCnt_s <= 25000000; 
        
         elsif (sBtn2_i = '0') then 
        
           iTimeCnt_s <= 50000000; 
          
         elsif (sBtn3_i = '0') and (iTimeCnt_s > 12500000) and (sBtn3_s = '1') then 
          
           iTimeCnt_s <= iTimeCnt_s - 12500000; 
    
    	 
         end if;      
    
    
    
         sBtn3_s <= sBtn3_i;  -- remember last state of sBtn3_i
    		 
    
    
    
         -- fix the issue with casual counter overflow:
    
         if (sBtn3_i and sBtn2_i and sBtn1_i and sBtn0_i) = '0' then
           svCnt_s <= 0;  --  -> reset counter on any button input
         end if;
    
    	  
        end if; 
      end process; 
    
    
      sLed_o <= sLed_s; 
      
      
    end;

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests