OPPO K7x、Reno3 5G 開啟 ColorOS 12×Android 12 升級公測招募
阿新 • • 發佈:2022-04-07
當按鍵被按下在到被釋放,期間產生的輸入訊號會發生抖動,如果不進行消抖處理,直接使用可能就會誤觸發。
按鍵消抖實驗設計思路,當按鍵被按下,隔20ms取資料,也就是說20ms的前後各取一次資料進行邊沿檢測:
(1)、需要一個計數器cnt,因為按鍵隨時都可能會被按下,所以計數器需一直啟動在計數,需一直在檢測。
1 always @(posedge clk or negedge rst_n)begin 2 if(!rst_n)begin 3 cnt <= 0; 4 end 5 else if(add_cnt)begin 6 if(end_cnt)begin7 cnt <= 0; 8 end 9 else begin 10 cnt <= cnt + 1; 11 end 12 end 13 end 14 15 assign add_cnt = 1; 16 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en;
(2)、需要一個邊沿檢測器,需要對輸入pin 上的訊號進行邊沿檢測,檢測到下降沿之後,立刻馬上將計數器cnt 清0 ,cnt從0開始計數,數到20ms 取一次資料
1 always @(posedge clk or negedge rst_n)begin 2 if(!rst_n)begin 3 key_rst <= 1; 4 key_rst_r <= 1; 5 end 6 else begin 7 key_rst <= wr_en; 8 key_rst_r <= key_rst; 9 end 10 end 11 //當key_en = 1時,說明有檢測到下降沿,但這個並不能當做一個真正有效的訊號去啟動cnt0, 12 //在按鍵按下到釋放期間可能會多次產生key_en = 113 assign key_en = key_rst_r & (~key_rst);
1 //每隔20ms就取按鍵上的值 2 always @(posedge clk or negedge rst_n)begin 3 if(!rst_n) begin 4 pin_status <= 1; 5 end 6 else if(end_cnt) begin //隔20ms 取一次資料 7 pin_status <= wr_en; 8 end 9 end 10 11 always @(posedge clk or negedge rst_n)begin 12 if(!rst_n)begin 13 pin_status_r <= 1; 14 end 15 else begin 16 pin_status_r <= pin_status; 17 end 18 end 19 20 //前20MS的值與後20MS的值 21 assign pin_status_ctrl = pin_status_r & (~pin_status);//這個訊號才比較穩定訊號,可以當做啟動計數器cnt0
完整程式碼:該程式碼是基於spi flash 一個讀ID操作
1 module spi_flash( 2 clk, 3 rst_n, 4 wr_en, 5 spi_miso, 6 7 spi_sclk, 8 spi_mosi, 9 spi_cs, 10 rec_buf 11 ); 12 parameter SCLK_CLK = 3'd04; 13 parameter T_20MS = 20'd1_000_000; 14 parameter CMD_ID = 8'h9f; 15 16 input clk ; 17 input rst_n ; 18 input wr_en ; 19 input spi_miso; 20 21 output spi_sclk; 22 output spi_mosi; 23 output spi_cs ; 24 output[24-1:0] rec_buf ; 25 26 wire add_cnt0; 27 wire end_cnt0; 28 wire add_cnt1; 29 wire end_cnt1; 30 wire add_cnt/*synthesis keep=1*/; 31 wire end_cnt/*synthesis keep=1*/; 32 wire key_en/*synthesis keep=1*/; 33 34 wire key_h_2_l; 35 wire pin_status_ctrl/*synthesis keep=1*/; 36 37 reg[3-1:0] cnt0; 38 reg[6-1:0] cnt1; 39 reg[20-1:0] cnt/*synthesis preserve=1*/; 40 reg wr_vld; 41 reg key_rst; 42 reg key_rst_r; 43 reg pin_status; 44 reg pin_status_r; 45 46 47 /************************************************/ 48 //按鍵消抖動 49 always @(posedge clk or negedge rst_n)begin 50 if(!rst_n)begin 51 key_rst <= 1; 52 key_rst_r <= 1; 53 end 54 else begin 55 key_rst <= wr_en; 56 key_rst_r <= key_rst; 57 end 58 end 59 60 assign key_en = key_rst_r & (~key_rst); 61 62 //每隔20ms就取按鍵上的值 63 always @(posedge clk or negedge rst_n)begin 64 if(!rst_n) begin 65 pin_status <= 1; 66 end 67 else if(end_cnt) begin 68 pin_status <= wr_en; 69 end 70 end 71 72 always @(posedge clk or negedge rst_n)begin 73 if(!rst_n)begin 74 pin_status_r <= 1; 75 end 76 else begin 77 pin_status_r <= pin_status; 78 end 79 end 80 81 //前20MS的值與後20MS的值 82 assign pin_status_ctrl = pin_status_r & (~pin_status); 83 84 always @(posedge clk or negedge rst_n)begin 85 if(!rst_n)begin 86 cnt <= 0; 87 end 88 else if(add_cnt)begin 89 if(end_cnt)begin 90 cnt <= 0; 91 end 92 else begin 93 cnt <= cnt + 1; 94 end 95 end 96 end 97 98 assign add_cnt = 1; 99 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en; 100 101 102 always @(posedge clk or negedge rst_n)begin 103 if(!rst_n)begin 104 wr_vld <= 0; 105 end 106 else if(pin_status_ctrl)begin 107 wr_vld <= 1; 108 end 109 else if(end_cnt1)begin 110 wr_vld <= 0; 111 end 112 end 113 114 always @(posedge clk or negedge rst_n)begin 115 if(!rst_n)begin 116 cnt0 <= 0; 117 end 118 else if(add_cnt0)begin 119 if(end_cnt0)begin 120 cnt0 <= 0; 121 end 122 else begin 123 cnt0 <= cnt0 + 1; 124 end 125 end 126 end 127 128 assign add_cnt0 = wr_vld; 129 assign end_cnt0 = add_cnt0 && cnt0 == SCLK_CLK -1; 130 131 always @(posedge clk or negedge rst_n)begin 132 if(!rst_n)begin 133 cnt1 <= 0; 134 end 135 else if(add_cnt1)begin 136 if(end_cnt1)begin 137 cnt1 <= 0; 138 end 139 else begin 140 cnt1 <= cnt1 + 1; 141 end 142 end 143 end 144 145 assign add_cnt1 = end_cnt0; 146 assign end_cnt1 = add_cnt1 && cnt1 == 33 -1; 147 148 reg spi_sclk; 149 always @(posedge clk or negedge rst_n)begin 150 if(!rst_n)begin 151 spi_sclk <= 1; 152 end 153 else if(end_cnt0 && cnt1 != 32)begin 154 spi_sclk <= 0; 155 end 156 else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1))begin 157 spi_sclk <= 1; 158 end 159 end 160 161 reg spi_cs; 162 always @(posedge clk or negedge rst_n)begin 163 if(!rst_n)begin 164 spi_cs <= 1; 165 end 166 else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1) && cnt1 == 0)begin 167 spi_cs <= 0; 168 end 169 else if(end_cnt1)begin 170 spi_cs <= 1; 171 end 172 end 173 174 reg spi_mosi; 175 always @(posedge clk or negedge rst_n)begin 176 if(!rst_n)begin 177 spi_mosi <= 1; 178 end 179 else if(end_cnt0 && cnt1 >= 0 && cnt1 < 8)begin 180 spi_mosi <= CMD_ID[7-cnt1]; 181 end 182 end 183 184 reg[24-1:0] rec_buf_temp; 185 always @(posedge clk or negedge rst_n)begin 186 if(!rst_n)begin 187 rec_buf_temp <= 0; 188 end 189 else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1)-1) && cnt1 >= 9 && cnt1 < 33)begin 190 rec_buf_temp[32-cnt1] <= spi_miso; 191 end 192 end 193 194 reg dout_vld; 195 always @(posedge clk or negedge rst_n)begin 196 if(!rst_n)begin 197 dout_vld <= 0; 198 end 199 else begin 200 dout_vld <= end_cnt1; 201 end 202 end 203 204 reg[24-1:0] rec_buf; 205 always @(posedge clk or negedge rst_n)begin 206 if(!rst_n)begin 207 rec_buf <= 0; 208 end 209 else if(end_cnt1)begin 210 rec_buf <= rec_buf_temp; 211 end 212 end 213 214 endmoduleView Code
用quartus II 的SignalTab抓取的波形:
如果pin_status_ctl 檢測到多次,可以將間隔時間適當的加長點。一般的輕觸按鍵20~50ms。
觸發條件可以多開幾個視窗進行捕獲觀察 。