關于按鍵消抖或者開關量信號監測,可以參考本公眾號的另外一篇原創文章:按鍵消抖常用的軟硬件方法。在該文章中介紹了兩種軟件延時的方式。但也都各有缺點。
一:舊方案
方案一:純軟件延時
sbit KEY = P1^3; ///按鍵讀取函數 uint8_t GetKey(void) { if(KEY == 1) { DelayMs(20); //延時消抖 if(KEY == 1) { return 1; } else { return 0; } } else { return 0; } }致命缺點:在延時的時候一直占用cpu的資源,如果在延時的時候,有其他外部中斷或者搶占事件,系統完全沒有響應的
方案二:中斷消抖
此處不在貼出代碼:感興趣的同學可到文章中查看:按鍵消抖常用的軟硬件方法
致命缺點:多占用中斷資源。操作復雜。在資源就是成本的產品中(多占用一個中斷可能會導致需要選擇價格更高的MCU),這種方案的缺點更加明顯。
推薦方案
本文推薦一種更高效、合適,已在產品中使用過的軟件設計方案。直接上代碼。
#include1、函數詳解:// 定義開關信號結構體 typedef struct { bool lastState; // 上次開關信號狀態 bool currentState; // 當前開關信號狀態 bool validState; // 有效的開關信號狀態 int debounceDelayCounter; // 開關信號消抖計數器 } DebouncedSwitch; // 初始化開關信號結構體 void initializeSwitch(DebouncedSwitch* switchObj) { switchObj->lastState = false; switchObj->currentState = false; switchObj->validState = false; switchObj->debounceDelayCounter = 0; } // 模擬讀取開關信號狀態的函數 bool readSwitchState() { // 在這里替換為實際的開關信號讀取代碼 // 返回開關信號的當前狀態(true表示開,false表示關) return false; } // 處理開關信號消抖的函數 void debounceSwitch(DebouncedSwitch* switchObj, int debounceTime) { // 讀取當前開關信號狀態 switchObj->currentState = readSwitchState(); // 如果當前狀態與上次狀態不同,重置計數器并更新上次狀態 if (switchObj->currentState != switchObj->lastState) { switchObj->debounceDelayCounter = 0; } else { // 如果狀態相同,增加計數器值 switchObj->debounceDelayCounter++; } // 如果計數器達到指定的消抖時間,表示開關信號狀態穩定 if (switchObj->debounceDelayCounter >= (debounceTime / 10)) { // 如果當前狀態與 validState 不同,表示發生了有效的狀態變化 if (switchObj->currentState != switchObj->validState) { switchObj->validState = switchObj->currentState; } } // 更新上次狀態 switchObj->lastState = switchObj->currentState; } int main() { // 創建一個開關信號的DebouncedSwitch結構體 DebouncedSwitch switchObj; initializeSwitch(&switchObj); while (1) { debounceSwitch(&switchObj, 100); // 設置消抖時間為100毫秒 if (switchObj.validState) { if (switchObj.validState) { // 執行開關信號為開的操作 printf("開關信號為開 "); } else { // 執行開關信號為關的操作 printf("開關信號為關 "); } } // 在這里可以添加其他需要執行的代碼 // 模擬延時或等待開關信號狀態變化 // 這里使用usleep函數來模擬10毫秒的延時 // 實際上,你需要根據你的硬件和操作系統來等待開關信號狀態變化 usleep(10000); // 10毫秒 } return 0; }
debounceSwitch函數該函數用于處理開關信號的消抖,以確保穩定的開關狀態。 它接受一個指向 DebouncedSwitch 結構體的指針,該結構體包含了上次狀態、當前狀態、有效狀態等信息,以及消抖時間的設置。
該函數的被調用周期為10ms(可以與產品程序中其他任務并行執行)。
2、函數的工作流程如下:
1)讀取當前開關信號狀態。
2)如果當前狀態與上次狀態不同,重置計數器并更新上次狀態。
3)如果當前狀態與上次狀態相同,增加計數器值。
4)如果計數器達到指定的消抖時間,表示開關信號狀態穩定。
5)如果當前狀態與 validState 不同,表示發生了有效的狀態變化,更新有效狀態。
6)更新上次狀態以便下一次比較
3、優點介紹:
1)擴展性:
debounceSwitch該函數使用結構體指針的形式,提供了開關量檢測的框架,需要多個開關量/按鍵檢測時,實例化對應的按鍵變量即可。例如:main函數的示例中實例化了switchObj,多有多個按鍵可以多定義不同的switchObj即可。如下:代碼所展示:
DebouncedSwitch switchObj_key1;
DebouncedSwitch switchObj_key2;
//其他代碼
debounceSwitch(&switchObj_key1, 100);
debounceSwitch(&switchObj_key2,50);
2、高度可定制:
debounceSwitch函數中的消抖時間是作為參數傳遞的,這使得消抖時間可以根據不同的開關信號或應用場景進行定制。這種可定制性允許您在不同情況下使用不同的消抖時間,以滿足特定需求。
3、適用于實時系統:
相對于純軟件延時消抖,debounceSwitch函數是更可靠的,因為它不依賴于軟件的延時,而是基于實際的狀態變化來判斷開關信號的穩定性。這使得它適用于實時系統和對時間精度要求較高的應用。
總結
當然,作為一個產品中使用的函數還有很多可優化的空間,比如:函數內判斷指針不為空。進行參數的有效性檢查等等。
審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
開關量
+關注
關注
2文章
169瀏覽量
15062 -
源碼
+關注
關注
8文章
639瀏覽量
29185 -
函數
+關注
關注
3文章
4327瀏覽量
62573 -
按鍵消抖
+關注
關注
2文章
27瀏覽量
10448
原文標題:共享一個產品中使用的按鍵消抖/開關量監測函數(附源碼,可移植)
文章出處:【微信號:玩轉單片機與嵌入式,微信公眾號:玩轉單片機與嵌入式】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
如何在FPGA中實現按鍵消抖
在FPGA(現場可編程門陣列)中實現按鍵消抖是一個重要的設計環節,特別是在處理用戶輸入時,由于物理按鍵的機械特性和電氣特性,
評論