Blog directory
Write in front
- Personal WeChat official account: FPGA LAB
- Home page of personal blog
- Note: learn to communicate!
text
Background introduction and review
We often see this kind of Verilog design on the Internet, which is to read the switch every 20ms, The so-called recognized key time is less than 20ms.
In fact, the jitter time of different keys is different. See resources: debouncing In, the author tested the jitter time of different keys:
Jitter time (in microseconds) used to turn each switch (numbers A to R) on and off. Switch E was excluded because its 157 millisecond jitter severely distorted the pattern.
If you are interested, please have a look!
A common key circuit is as follows:
When the key is not pressed, the value signal is high and the value is low. There is a short or long key jitter in physical keys! As shown in the figure below:
As mentioned above, key jitter is generally recognized as 20ms. If the jitter is eliminated by software or logic design, the edge of key signal is detected first, and then the key value is sampled every 20ms! In this way, the purpose of key shaking is realized!
Single button
The design of a key's anti shake
Take a key as an example:
The following figure is the design block diagram:
Design documents:
`timescale 1ns / 1ps ///////////////////////////////////////////// // Engineer: Reborn Lee // Module Name: debounce_1b //////////////////////////////////////////// module debounce_1b( input clk, //50MHz input rst, input sw_in_n, output reg sw_out_n ); reg sw_mid_r1, sw_mid_r2, sw_valid; always@(posedge clk or posedge rst) begin if(rst) begin sw_mid_r1 <= 1; // synchronize 1 clock sw_mid_r2 <= 1; // delay 1 clock sw_valid <= 0; // gen negedge end else begin sw_mid_r1 <= sw_in_n; sw_mid_r2 <= sw_mid_r1; sw_valid <= sw_mid_r2 & (~sw_mid_r1); end end reg [19:0] key_cnt; always@(posedge clk or posedge rst) begin if(rst) begin key_cnt <= 0; end else if(sw_valid) begin key_cnt <= 0; end else begin key_cnt <= key_cnt + 1; //20ms end end always@(posedge clk or posedge rst) begin if(rst) begin sw_out_n <= 1; end else if(key_cnt == 20'hfffff) begin sw_out_n <= sw_in_n; end end endmodule
It is easy to understand that it is to detect whether the key value changes first and detect the falling edge of the key value. If the falling edge is detected, the counter will be cleared. Otherwise, the counter will be counted to 20ms (20'dfffff), and the key value will be sampled once as the output.
Next, I design jitter to test this design.
Test documents
`timescale 1ns / 1ps module debounce1_tb( ); reg clk; reg rst; reg sw_in_n; wire sw_out_n; initial begin clk = 0; forever begin #5 clk = ~clk; end end initial begin rst = 1; sw_in_n = 1; #50 rst = 0; @(negedge clk) sw_in_n = 0; repeat(3) @(negedge clk); sw_in_n = 1; repeat(20000) begin repeat(5) @(negedge clk); sw_in_n = 0; repeat(2) @(negedge clk); sw_in_n = 1; repeat(3) @(negedge clk); sw_in_n = 0; end repeat(3000000) begin @(negedge clk); end sw_in_n = 1; end debounce_1b inst0( .clk(clk), .rst(rst), .sw_in_n(sw_in_n), .sw_out_n(sw_out_n) ); endmodule
The simulation waveform is:
Schematic diagram of RTL designed:
Other design versions of single button
It has to be said that, data The schematic diagram of jitter removal given:
In fact, it is the RTL diagram that simplifies the above-mentioned design. I think it is more exquisite than the first design.
This version design does not detect the falling edge of the key, but directly synchronizes two beats of the key value, and detects the XOR of the two beats of data. If the XOR value is 1, it means that the key value has changed, when the count value is cleared; otherwise, count, until the count value reaches the specified value, sample the key value data.
The following is the VHDL design. It is very simple. There is no need to convert verilog into it. If it is necessary, pay attention to my WeChat official account FPGA LAB, and give me a background news.
---------------------------------------------------------------- -- FileName: debounce.vhd -- Version History -- Version 1.0 3/26/2012 Scott Larson ---------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY debounce IS GENERIC( counter_size : INTEGER := 19); --counter size (19 bits gives 10.5ms with 50MHz clock) PORT( clk : IN STD_LOGIC; --input clock button : IN STD_LOGIC; --input signal to be debounced result : OUT STD_LOGIC); --debounced signal END debounce; ARCHITECTURE logic OF debounce IS SIGNAL flipflops : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops SIGNAL counter_set : STD_LOGIC; --sync reset to zero SIGNAL counter_out : STD_LOGIC_VECTOR(counter_size DOWNTO 0) := (OTHERS => '0'); --counter output BEGIN counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter PROCESS(clk) BEGIN IF(clk'EVENT and clk = '1') THEN flipflops(0) <= button; flipflops(1) <= flipflops(0); If(counter_set = '1') THEN --reset counter because input is changing counter_out <= (OTHERS => '0'); ELSIF(counter_out(counter_size) = '0') THEN --stable input time is not yet met counter_out <= counter_out + 1; ELSE --stable input time is met result <= flipflops(1); END IF; END IF; END PROCESS; END logic;
There is also an improved version of the previous version:
LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY debounce IS GENERIC( clk_freq : INTEGER := 50_000_000; --system clock frequency in Hz stable_time : INTEGER := 10); --time button must remain stable in ms PORT( clk : IN STD_LOGIC; --input clock reset_n : IN STD_LOGIC; --asynchronous active low reset button : IN STD_LOGIC; --input signal to be debounced result : OUT STD_LOGIC); --debounced signal END debounce; ARCHITECTURE logic OF debounce IS SIGNAL flipflops : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops SIGNAL counter_set : STD_LOGIC; --sync reset to zero BEGIN counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter PROCESS(clk, reset_n) VARIABLE count : INTEGER RANGE 0 TO clk_freq*stable_time/1000; --counter for timing BEGIN IF(reset_n = '0') THEN --reset flipflops(1 DOWNTO 0) <= "00"; --clear input flipflops result <= '0'; --clear result register ELSIF(clk'EVENT and clk = '1') THEN --rising clock edge flipflops(0) <= button; --store button value in 1st flipflop flipflops(1) <= flipflops(0); --store 1st flipflop value in 2nd flipflop If(counter_set = '1') THEN --reset counter because input is changing count := 0; --clear the counter ELSIF(count < clk_freq*stable_time/1000) THEN --stable input time is not yet met count := count + 1; --increment counter ELSE --stable input time is met result <= flipflops(1); --output the stable value END IF; END IF; END PROCESS; END logic;
If you are interested, go to the link: De jitter logic circuit (taking VHDL as an example) View (except those that cannot be opened)!
Well, that's it for a single button. Here's the design of multiple buttons.
Multiple buttons
The design of several buttons for anti shake is as follows:
A fairly simple method is used to find n consecutive stable readings of the switch, where n is a number from 1 (no bounce at all) to seemingly infinite. Usually, the code first detects a jump, and then starts to increment or decrement the counter, each time it rereads the input, until n reaches some safe, jitter free count. If the status is not stable, the counter resets to its initial value.
`timescale 1ns / 1ps //Note: when one of the three independent keys is pressed, the corresponding LED is lit; // After pressing again, the LED goes out and the key control LED goes on and off module sw_debounce( clk,rst_n, sw1_n,sw2_n,sw3_n, led_d1,led_d2,led_d3 ); input clk; //Master clock, 50MHz input rst_n; //Reset signal, low effective input sw1_n,sw2_n,sw3_n; //Three independent keys, low means press output led_d1,led_d2,led_d3; //LED, respectively controlled by key //--------------------------------------------------------------------------- reg key_rst; always @(posedge clk or negedge rst_n) if (!rst_n) key_rst <= 1'b1; else key_rst <= sw3_n&sw2_n&sw1_n; reg key_rst_r; //The rising edge of each clock cycle will be low_sw signal latched to low_sw_r medium always @ ( posedge clk or negedge rst_n ) if (!rst_n) key_rst_r <= 1'b1; else key_rst_r <= key_rst; //When register key_ LED when RST changes from 1 to 0_ The value of an becomes high, maintaining a clock cycle wire key_an = key_rst_r & (~key_rst); /* key_rst 1 1 1 0 0 1 ~key_rst 0 0 0 1 1 0 key_rst_r 1 1 1 0 0 1 key_an 0 0 1 0 0 */ //--------------------------------------------------------------------------- reg[19:0] cnt; //Count register always @ (posedge clk or negedge rst_n) if (!rst_n) cnt <= 20'd0; //Asynchronous reset else if(key_an) cnt <=20'd0; else cnt <= cnt + 1'b1; reg[2:0] low_sw; always @(posedge clk or negedge rst_n) if (!rst_n) low_sw <= 3'b111; else if (cnt == 20'hfffff) //For 20ms, lock the key value to register low_ cnt == 20 'in SWhfffff low_sw <= {sw3_n,sw2_n,sw1_n}; //--------------------------------------------------------------------------- reg [2:0] low_sw_r; //The rising edge of each clock cycle will be low_sw signal latched to low_sw_r medium always @ ( posedge clk or negedge rst_n ) if (!rst_n) low_sw_r <= 3'b111; else low_sw_r <= low_sw; /* low_sw 111 111 111 110 110 110 ~low_sw 000 000 000 001 001 001 low_sw_r 111 111 111 110 110 110 led_ctrl 000 000 000 001 000 000 */ //When register low_ When SW changes from 1 to 0, LED_ The value of Ctrl becomes high, maintaining a clock cycle wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]); reg d1; reg d2; reg d3; always @ (posedge clk or negedge rst_n) if (!rst_n) begin d1 <= 1'b0; d2 <= 1'b0; d3 <= 1'b0; end else begin //When a key value changes, the LED will turn on and off if ( led_ctrl[0] ) d1 <= ~d1; if ( led_ctrl[1] ) d2 <= ~d2; if ( led_ctrl[2] ) d3 <= ~d3; end assign led_d3 = d1 ? 1'b1 : 1'b0; //LED flip output assign led_d2 = d2 ? 1'b1 : 1'b0; assign led_d1 = d3 ? 1'b1 : 1'b0; endmodule
From the beginning to here:
always @(posedge clk or negedge rst_n) if (!rst_n) low_sw <= 3'b111; else if (cnt == 20'hfffff) //For 20ms, lock the key value to register low_ cnt == 20 'in SWhfffff low_sw <= {sw3_n,sw2_n,sw1_n};
It's over. The rest is the LED part!
Let's take a brief look at this Code:
always @(posedge clk or negedge rst_n) if (!rst_n) key_rst <= 1'b1; else key_rst <= sw3_n&sw2_n&sw1_n;
As long as the change of key value (even jitter) is detected, the key will be lowered here_ Rst pull down!
reg key_rst_r; //The rising edge of each clock cycle will be low_sw signal latched to low_sw_r medium always @ ( posedge clk or negedge rst_n ) if (!rst_n) key_rst_r <= 1'b1; else key_rst_r <= key_rst; //When register key_ LED when RST changes from 1 to 0_ The value of an becomes high, maintaining a clock cycle wire key_an = key_rst_r & (~key_rst);
Yes, key_ After one shot delay of RST, the falling edge detection is performed. If the falling edge key is detected_ An effective!
That is, if the key value changes, key_an works!
reg[19:0] cnt; //Count register always @ (posedge clk or negedge rst_n) if (!rst_n) cnt <= 20'd0; //Asynchronous reset else if(key_an) cnt <=20'd0; else cnt <= cnt + 1'b1;
At key_ After an is valid, we will clear the count value and then count (key_an is invalid). If the key value is in the jitter stage during counting, the key_an will be valid again and the count will be cleared again. Until the end of jitter, count all the time, count to 20ms, take the key value signal!
always @(posedge clk or negedge rst_n) if (!rst_n) low_sw <= 3'b111; else if (cnt == 20'hfffff) //For 20ms, lock the key value to register low_ cnt == 20 'in SWhfffff low_sw <= {sw3_n,sw2_n,sw1_n};
This program means that the count is full. If the system clock frequency is 50MHz, it means that the count is about 20ms and the key value will be sampled. Here, take three keys as an example.
So far, it's the end of the button shake!
Write at the end
In fact, for the elimination of key jitter, you can also use hardware to remove the jitter, but it is not within the scope of this article, you can refer to 5! Reference 5
reference material
Make a friend
-
Personal WeChat official account: FPGA LAB
- Zhihu: Li ruiboon