Search code examples
vhdlquartus

Control signal with two buttons


I am trying to make a VHDL code in Quartus that turns on buzzer when I push button1 on the demo board and turns it off when I push button 2. But, it doesn't react to button2. It compiles without errors, but doesn't work as I expected. It always produces sound.

How do I make it to turn on when I push button1 and turn off when I push button2?

architecture Behavioral of buzz is
signal Hz_counter : natural range 0 to 56818 := 0;
signal wave : std_logic := '0';
signal sound_on : std_logic := '0';
signal sound_off : std_logic := '0';
begin
process(clk, button1, button2)
begin
         if rising_edge(clk) then
            Hz_counter <= Hz_counter + 1;
            if Hz_counter >= 56818 then
                wave <= not wave;
                Hz_counter <= 0;
            end if;
        end if;
          
          if rising_edge(button1) then
            sound_on <= '1';
          end if;       
          if rising_edge(button2) then
            sound_off <= '1';  
        end if;
          
          if (sound_on = '1') then
              sound_off <= '0';
          end if;
          if (sound_off = '1') then
              sound_on <= '0';
          end if; 
end process;

    buzzer <= wave when (sound_on = '1') else '0';
     
end Behavioral;

Solution

  • You have built two flip-flops that are set by the rising edges of buttons, but asynchronously reset by the set state of each other.

    Initially, sound_on and sound_off are '0'.

    If you press button1, sound_on becomes '1'. This keeps sound_off at '0' asynchronously:

            if (sound_on = '1') then
                sound_off <= '0';
            end if;
    

    If you want to observe the same effect but for button2, press it as the first button. Now you are not able to switch the sound on with button1.


    The solution is to avoid this kind of dead-lock. Use only one flip-flop to store "sound on/off".

    The most simple alternative is to use button1 to set and button2 to reset:

            if button1 = '1' then
                sound_on <= '1';
            elsif button2 = '1' then
                sound_on <= '0';
            end if;
    

    If you want a clocked flip-flop, use button1 as clock to set and button2 as reset. Since the asynchronous signal has higher priority in the real world, you need write this:

            if button2 = '1' then
                sound_on <= '0';
            elsif rising_edge(button1) then
                sound_on <= '1';
            end if;
    

    Finally, a pure synchronous design is:

            if rising_edge(clk) then
                if button1 = '1' then
                    sound_on <= '1';
                elsif button2 = '1' then
                    sound_on <= '0';
                end if;
            end if;