Verilog功能模块 —— 按键消抖
一. 什么是按鍵消抖
按鍵消抖_百度百科 (baidu.com)
按鍵消抖通常的按鍵所用開(kāi)關(guān)為機(jī)械彈性開(kāi)關(guān),當(dāng)機(jī)械觸點(diǎn)斷開(kāi)、閉合時(shí),由于機(jī)械觸點(diǎn)的彈性作用,一個(gè)按鍵開(kāi)關(guān)在閉合時(shí)不會(huì)馬上穩(wěn)定地接通,在斷開(kāi)時(shí)也不會(huì)一下子斷開(kāi)。因而在閉合及斷開(kāi)的瞬間均伴隨有一連串的抖動(dòng),如下圖所示,為了不產(chǎn)生這種現(xiàn)象而作的措施就是按鍵消抖。
從按鍵對(duì)應(yīng)的數(shù)字電平來(lái)看,按鍵的抖動(dòng)過(guò)程如下圖所示。在抖動(dòng)期間,按鍵的輸入電平是不穩(wěn)定的,消抖的目的就是去除抖動(dòng)的影響,得到能表征按鍵過(guò)程的穩(wěn)定的按鍵輸入電平。
二. 按鍵消抖的方案
2.1 硬件消抖
通常的做法是在按鍵兩端并聯(lián)一個(gè)貼片電容,利用電容兩端電壓不能突變的特性來(lái)消除抖動(dòng)。
2.2 軟件消抖
利用按鍵按下的特點(diǎn)來(lái)消抖:
1.按鍵按下和彈起都會(huì)抖動(dòng),抖動(dòng)的持續(xù)時(shí)間和按鍵類(lèi)型和質(zhì)量有關(guān),一般為5~10ms
2.按鍵按下后保持穩(wěn)定電平的時(shí)間一般不小于120ms
三. Verilog實(shí)現(xiàn)按鍵消抖
3.1 模塊框圖
3.2 參數(shù)列表 與 接口列表
| CLKFREQ | 計(jì)時(shí)時(shí)鐘頻率, 注意修改 |
| INTI_MS | 初始檢測(cè)未按下電平, 需要持續(xù)多少M(fèi)S才視為檢測(cè)成功, 默認(rèn)50ms, 通常無(wú)需修改 |
| KEEP_MS | 檢測(cè)到按鍵按下/松開(kāi)需要持續(xù)多少M(fèi)S才視為有效, 默認(rèn)40ms, 通常無(wú)需修改 |
| key_in | 按鍵輸入 |
| clk | 工作時(shí)鐘 |
| rstn | 復(fù)位,復(fù)位有效結(jié)束后會(huì)重新檢測(cè)一次未按下電平,所以需要在復(fù)位時(shí)保證按鍵處于未按下的狀態(tài) 不使用復(fù)位信號(hào)模塊同樣可以正常工作,只是失去了重新檢測(cè)未按下電平的功能 |
| key_down | 消抖后的按鍵狀態(tài) |
| key_down_one_time | 按鍵按下一次 |
| key_up_one_time | 按鍵松開(kāi)一次 |
3.3 模塊IP框圖 與 使用說(shuō)明
使用說(shuō)明請(qǐng)參照3.2 參數(shù)列表與接口列表 以及 3.4 模塊源碼。
3.4 模塊源碼
/** @Author : Xu Dakang* @Email : xudaKang_up@qq.com* @Date : 2021-12-20 15:13:10* @LastEditors : Xu Dakang* @LastEditTime : 2021-12-21 22:03:28* @Filename :* @Description : *//* ! 模塊功能: 消除按鍵抖動(dòng), 得到正確的按鍵輸入的電平 * 思路:1.先檢測(cè)按鍵未按下時(shí)的電平必須保證在復(fù)位完成后的50ms(可通過(guò)參數(shù)INTI_MS修改)內(nèi),按鍵一直處于未按下的狀態(tài),否則未按下電平的檢測(cè)會(huì)出錯(cuò)2.當(dāng)按鍵電平為按下電平時(shí),開(kāi)始一個(gè)40ms(可通過(guò)參數(shù)KEEP_MS修改)的計(jì)數(shù)器,計(jì)數(shù)到最大值則認(rèn)為按鍵按下3.當(dāng)按鍵電平為松開(kāi)電平時(shí),開(kāi)始一個(gè)40ms(可通過(guò)參數(shù)KEEP_MS修改)的計(jì)數(shù)器,計(jì)數(shù)到最大值則認(rèn)為按鍵松開(kāi) */module myKeyEliminateJitter #(parameter CLKFREQ = 100, // 計(jì)時(shí)時(shí)鐘頻率, 注意修改parameter INTI_MS = 50, // 初始檢測(cè)未按下電平, 需要持續(xù)多少M(fèi)S才視為檢測(cè)成功, 默認(rèn)50ms, 通常無(wú)需修改parameter KEEP_MS = 40 // 檢測(cè)到按鍵按下/松開(kāi)需要持續(xù)多少M(fèi)S才視為有效, 默認(rèn)40ms, 通常無(wú)需修改 )(output logic key_down, // 按鍵按下output logic key_down_one_time, // 按鍵按下一次output logic key_up_one_time, // 按鍵松開(kāi)一次input logic key_in, // 按鍵輸入input logic clk,input logic rstn );//++ 按鍵輸入同步 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic key_in_r1; logic key; always_ff @(posedge clk) beginkey_in_r1 <= key_in;key <= key_in_r1; end //-- 按鍵輸入同步 ------------------------------------------------------------//++ 按鍵未按下時(shí)的電平檢測(cè) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic key_r1; always_ff @(posedge clk) beginkey_r1 <= key; endlogic auto_detection_success; // 50ms計(jì)數(shù)器 localparam CNT_50MS_MAX = CLKFREQ * 1000 * INTI_MS; logic [$clog2(CNT_50MS_MAX+1)-1 : 0] cnt_50ms; always_ff @(posedge clk, negedge rstn) beginif (~rstn)cnt_50ms <= '0;else if (auto_detection_success)cnt_50ms <= cnt_50ms;// 按鍵信號(hào)一改變就重新計(jì)數(shù), 初始情況下這不應(yīng)該發(fā)生, 只是為了應(yīng)對(duì)電磁干擾或機(jī)械振動(dòng)等極端條件else if (key_r1 != key)cnt_50ms <= '0;else if (cnt_50ms < CNT_50MS_MAX)cnt_50ms <= cnt_50ms + 1'b1;elsecnt_50ms <= '0; endalways_comb beginif (cnt_50ms == CNT_50MS_MAX) // 按鍵信號(hào)從復(fù)位開(kāi)始50ms內(nèi)輸入未發(fā)生變化auto_detection_success = 1'b1;elseauto_detection_success = 1'b0; endlogic auto_detection_success_r1; always_ff @(posedge clk) beginauto_detection_success_r1 <= auto_detection_success; endassign auto_detection_success_pedge = auto_detection_success && ~auto_detection_success_r1;logic key_up_value; // 存儲(chǔ)按鍵未按下時(shí)的引腳電平 always_ff @(posedge clk) beginif (auto_detection_success_pedge)key_up_value <= key;elsekey_up_value <= key_up_value; end //-- 按鍵未按下時(shí)的電平檢測(cè) ------------------------------------------------------------//++ 按鍵消抖 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 檢測(cè)按下電平, 如果按下保持40ms, 則認(rèn)為鍵正常按下 localparam CNT_40MS_MAX = CLKFREQ * 1000 * KEEP_MS; logic [$clog2(CNT_40MS_MAX+1)-1 : 0] key_down_cnt_40ms; always_ff @(posedge clk) beginif (~rstn)key_down_cnt_40ms <= '0;if (key == ~key_up_value) // 按鍵按下了if (key_down_cnt_40ms < CNT_40MS_MAX)key_down_cnt_40ms <= key_down_cnt_40ms + 1'b1;elsekey_down_cnt_40ms <= key_down_cnt_40ms;elsekey_down_cnt_40ms <= '0; end// 檢測(cè)按鍵松開(kāi), 如果松開(kāi)保持40ms, 則認(rèn)為鍵正常松開(kāi) logic [$clog2(CNT_40MS_MAX+1)-1 : 0] key_up_cnt_40ms; always_ff @(posedge clk) beginif (~rstn)key_up_cnt_40ms <= '0;if (key == key_up_value) // 按鍵松開(kāi)了if (key_up_cnt_40ms < CNT_40MS_MAX)key_up_cnt_40ms <= key_up_cnt_40ms + 1'b1;elsekey_up_cnt_40ms <= key_up_cnt_40ms;elsekey_up_cnt_40ms <= '0; endalways_ff @(posedge clk) beginif (~rstn)key_down <= 1'b0;else if (key_down_cnt_40ms == CNT_40MS_MAX) // 按下計(jì)數(shù)值保持最大值不變說(shuō)明鍵處于按下的狀態(tài)key_down <= 1'b1;else if (key_up_cnt_40ms == CNT_40MS_MAX) // 松開(kāi)計(jì)數(shù)值保持最大值不變說(shuō)明鍵處于松開(kāi)的狀態(tài)key_down <= 1'b0;elsekey_down <= key_down; endlogic key_down_r1; always_ff @(posedge clk) beginkey_down_r1 <= key_down; endassign key_down_pedge = key_down && ~key_down_r1; assign key_down_nedge = ~key_down && key_down_r1;assign key_down_one_time = key_down_pedge; assign key_up_one_time = key_down_nedge; //-- 按鍵消抖 ------------------------------------------------------------endmodule3.5 工程分享
Verilog功能模塊 —— 按鍵消抖 Vivado 2021.2工程 基于正點(diǎn)原子ZYNQ領(lǐng)航者V1。
鏈接:https://pan.baidu.com/s/1IF6bHiO6y9_-S69DTPI4Zg
提取碼:84vx
總結(jié)
以上是生活随笔為你收集整理的Verilog功能模块 —— 按键消抖的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Verilog功能模块——AXI4-Li
- 下一篇: Git简介及其下载 安装 卸载