本文主要以AB32VG1作為主控,結合板載按鍵實現按鍵的軟件濾波,按下時間判斷(長按,短按),按下判斷,松手判斷等,可以應對各種按鍵使用的場合,多種按鍵方式結合使用可以在只有一個按鍵的情況下實現多種按鍵操作邏輯。
一、創建工程
創建工程比較簡單,在這里不在贅述,可以參考官方的操作文檔:https://file.elecfans.com/web2/M00/14/6F/pYYBAGE-y4WAGoojANBtfI0No2g719.pdf
二、按鍵邏輯初始化
1. 創建按鍵線程
static void KEY_ThreadManage(void)
{
rt_thread_t key_thread;
key_thread = rt_thread_create("KEY Thread Manage", /*線程名字*/
KEY_ManageEntry,/*線程入口函數*/
RT_NULL, /*線程入口函數參數*/
2048, /*線程棧大小*/
5, /*線程優先級*/
10); /*線程時間片*/
rt_thread_startup (key_thread);
}
2. 按鈕初始化
初始化函數需要在mian函數的while循環之前調用,也可以使用RT-Thread提供的硬件初始化宏來初始化。
本程序中設置了按鍵的狀態有三種:
typedef enum
{
KEY_PRESSED = 0u,
KEY_RELEASED = 1u,
KEY_UNKNOW = 2u
} E_KeySt;
主要作用:
1)設置按鍵引腳;
2)設置引腳狀態為輸入;
3)設置按鍵濾波結構體,設置按鍵初始狀態為UNKNOW
原理圖如下:
S2 — PF1
S3 — PF0
S4 — PA2
![poYBAGGqFY6Ae6-3AAAoQKbRhtg315.png](http://file.elecfans.com/web2/M00/23/0C/poYBAGGqFY6Ae6-3AAAoQKbRhtg315.png)
void KEY_AppInit(void)
{
uint8_t i = 0u;
Key_pin.Key1 = rt_pin_get("PF.1");
Key_pin.Key2 = rt_pin_get("PF.0");
Key_pin.Key3 = rt_pin_get("PA.2");
rt_pin_mode(Key_pin.Key1, PIN_MODE_INPUT);
rt_pin_mode(Key_pin.Key2, PIN_MODE_INPUT);
rt_pin_mode(Key_pin.Key3, PIN_MODE_INPUT);
for(i=0; i
三、按鍵濾波
按鍵濾波邏輯:檢測按鍵引腳狀態是否連續40ms都為低電平,如果都為低電平的話就認為是真的按下了,邏輯如下,修改KEY_SW_FILTER_THD可以修改按鍵的濾波時間,當前值為4,按鍵線程的運行周期為10ms,所以濾波時間為40ms:
static void KEY_KeySwFilterCounting(S_KeyStatusStr *paraKeySta)
{
if(0u == paraKeySta->m_key_pin_st)
{
if(paraKeySta->m_filter_cnt >= KEY_SW_FILTER_THD)
{
paraKeySta->m_status = KEY_PRESSED;
}
else
{
paraKeySta->m_filter_cnt ++;
}
}
else
{
paraKeySta->m_filter_cnt = 0u;
paraKeySta->m_status = KEY_RELEASED;
}
}
四、按鍵按下狀態判斷
按鍵按下狀態的判斷邏輯:
1)代碼中有一個變量定義為用于記錄上一個周期的按鍵按下的狀態
static E_KeySt Last_KeyStatus[KEY_NUM] = {KEY_UNKNOW, KEY_UNKNOW, KEY_UNKNOW};
2)讀取濾波之后的按鍵狀態變量
3)如果上一次按鍵的狀態為KEY_RELEASED,本次的按鍵狀態為KEY_PRESSED,則認為按鍵按下了
if((KEY_PRESSED == KEY_GetKeyStatus(i))
&& (KEY_RELEASED== Last_KeyStatus[i]))
{
key_Pressed[i] = KEY_PRESSED;
}
五、按鍵松手狀態判斷
與按鍵的按下邏輯相似,不同點在于上一次的按鍵按下狀態為KEY_PRESSE,這一次為KEY_RELEASED就認為按鍵釋放了。
if((KEY_RELEASED == KEY_GetKeyStatus(i))
&& (KEY_PRESSED == Last_KeyStatus[i]))
{
key_Pressed[i] = KEY_RELEASED;
}
六、按鍵按下時間判斷
按鍵按下時間可以用來區別按鍵是長安還是短按,可以用一個按鍵實現兩種或多種功能。
具體實現方式需要結合按鍵松手判斷一起時間,當按鍵按下的時候需要一個counter來記錄按鍵按下的時間,然后按鍵松手的時候讀取這個counter值的時間來判斷是長按還是短按。
時間counter的累積邏輯為:
if((KEY_PRESSED == KEY_GetKeyStatus(i))
&& (KEY_PRESSED == Last_KeyStatus[i]))
{
key_pressed_counter[i] ++;
}
七、實現效果
按鈕按下會打印:Key [1,2,3] Pressed
按鈕松開會打印:Key [1,2,3] Released, 同時會打印按下的時間:Hold Key [1,2,3] for xxx ms
![pYYBAGGqHRGANUz2AALpzzOwAxg160.png](http://file.elecfans.com/web2/M00/23/16/pYYBAGGqHRGANUz2AALpzzOwAxg160.png)
八、代碼實現
貼上完整代碼實現,有問題歡迎指正
代碼直接粘貼可能存在遺漏,建議移步gitee:https://gitee.com/hehung/ab32-vg1_-rt-thread
.c文件
#include "app_key.h"
#include "board.h"
typedef struct
{
uint8_t Key1;
uint8_t Key2;
uint8_t Key3;
} S_key_pin;
typedef struct
{
uint8_t m_filter_cnt;
E_KeySt m_status;
uint8_t m_key_pin_st;
} S_KeyStatusStr;
S_key_pin Key_pin;
S_KeyStatusStr Key_Status[KEY_NUM];
E_KeySt key_Pressed[KEY_NUM] = {KEY_UNKNOW, KEY_UNKNOW, KEY_UNKNOW};
uint16_t key_pressed_counter[KEY_NUM] = {0, 0, 0};
static void KEY_ReadKeyLevel(void);
static void KEY_KeySwFilterCounting(S_KeyStatusStr *paraKeySta);
static void KEY_KeySwFilter(void);
static void KEY_ManageEntry(void *parameter);
static void KEY_ThreadManage(void);
static void KEY_JudgeKeyPressed(void);
void KEY_AppInit(void)
{
uint8_t i = 0u;
Key_pin.Key1 = rt_pin_get("PF.1");
Key_pin.Key2 = rt_pin_get("PF.0");
Key_pin.Key3 = rt_pin_get("PA.2");
rt_pin_mode(Key_pin.Key1, PIN_MODE_INPUT);
rt_pin_mode(Key_pin.Key2, PIN_MODE_INPUT);
rt_pin_mode(Key_pin.Key3, PIN_MODE_INPUT);
for(i=0; i {
Key_Status[i].m_filter_cnt = 0u;
Key_Status[i].m_key_pin_st = 0u;
Key_Status[i].m_status = KEY_UNKNOW;
}
KEY_ThreadManage();
}
E_KeySt KEY_GetKeyStatus(uint8_t paraKeyNum)
{
return Key_Status[paraKeyNum].m_status;
}
E_KeySt KEY_GetKeyPressedStatus(uint8_t paraKeyNum)
{
return key_Pressed[paraKeyNum];
}
static void KEY_ReadKeyLevel(void)
{
Key_Status[KEY_NUM_1].m_key_pin_st = (uint8_t)rt_pin_read(Key_pin.Key1);
Key_Status[KEY_NUM_2].m_key_pin_st = (uint8_t)rt_pin_read(Key_pin.Key2);
Key_Status[KEY_NUM_3].m_key_pin_st = (uint8_t)rt_pin_read(Key_pin.Key3);
}
static void KEY_KeySwFilterCounting(S_KeyStatusStr *paraKeySta)
{
if(0u == paraKeySta->m_key_pin_st)
{
if(paraKeySta->m_filter_cnt >= KEY_SW_FILTER_THD)
{
paraKeySta->m_status = KEY_PRESSED;
}
else
{
paraKeySta->m_filter_cnt ++;
}
}
else
{
paraKeySta->m_filter_cnt = 0u;
paraKeySta->m_status = KEY_RELEASED;
}
}
static void KEY_KeySwFilter(void)
{
KEY_KeySwFilterCounting(&Key_Status[KEY_NUM_1]);
KEY_KeySwFilterCounting(&Key_Status[KEY_NUM_2]);
KEY_KeySwFilterCounting(&Key_Status[KEY_NUM_3]);
}
static void KEY_JudgeKeyPressed(void)
{
uint8_t i = 0u;
static E_KeySt Last_KeyStatus[KEY_NUM] = {KEY_UNKNOW, KEY_UNKNOW, KEY_UNKNOW};
for(i=0u; i {
/*Key pressed this cycle*/
if((KEY_PRESSED == KEY_GetKeyStatus(i))
&& (KEY_RELEASED == Last_KeyStatus[i]))
{
key_Pressed[i] = KEY_PRESSED;
key_pressed_counter[i] = 0u;
rt_kprintf("KEY: Key %d Pressedn", i);
}
else if((KEY_RELEASED == KEY_GetKeyStatus(i))
&& (KEY_PRESSED == Last_KeyStatus[i]))
{
key_Pressed[i] = KEY_RELEASED;
rt_kprintf("KEY: Key %d Releasedn", i);
rt_kprintf("KEY: Hold Key for %d msn", key_pressed_counter[i]*10);
}
else if((KEY_PRESSED == KEY_GetKeyStatus(i))
&& (KEY_PRESSED == Last_KeyStatus[i]))
{
key_pressed_counter[i] ++;
}
Last_KeyStatus[i] = KEY_GetKeyStatus(i);
}
}
static void KEY_ManageEntry(void *parameter)
{
while(1)
{
KEY_ReadKeyLevel();
KEY_KeySwFilter();
KEY_JudgeKeyPressed();
rt_thread_mdelay(10);
}
}
static void KEY_ThreadManage(void)
{
rt_thread_t key_thread;
key_thread = rt_thread_create("KEY Thread Manage", /*線程名字*/
KEY_ManageEntry,/*線程入口函數*/
RT_NULL, /*線程入口函數參數*/
2048, /*線程棧大小*/
5, /*線程優先級*/
10); /*線程時間片*/
if(key_thread != RT_NULL)
{
rt_kprintf("KEY Thread Created Success!n");
rt_thread_startup (key_thread);
}
else
{
rt_kprintf("KEY Thread Create Failed!n");
}
}
.h文件
#ifndef APPLICATIONS_APP_KEY_H_
#define APPLICATIONS_APP_KEY_H_
#include "stdint.h"
typedef enum
{
KEY_PRESSED = 0u,
KEY_RELEASED = 1u,
KEY_UNKNOW = 2u
} E_KeySt;
#define KEY_NUM (3u)
#define KEY_NUM_1 (0u)
#define KEY_NUM_2 (1u)
#define KEY_NUM_3 (2u)
#define KEY_SW_FILTER_THD (4u)
#define KEY_SAMPLE_PERIOD (10u)
#define KEY_HOLD_SHORT_TIME (500u) /*ms*/
#define KEY_HOLD_MIDDLE_TIME (1500u) /*ms*/
#define KEY_HOLD_LONG_TIME (1500u) /*ms*/
extern E_KeySt KEY_GetKeyStatus(uint8_t paraKeyNum);
extern E_KeySt KEY_GetKeyPressedStatus(uint8_t paraKeyNum);
void KEY_AppInit(void);
#endif
-
濾波
+關注
關注
10文章
669瀏覽量
56773 -
按鍵
+關注
關注
4文章
223瀏覽量
57663 -
RT-Thread
+關注
關注
31文章
1305瀏覽量
40391
發布評論請先 登錄
相關推薦
【RTT大賽作品連載】AB32VG1評估板到貨控制彩燈測試
![【<b class='flag-5'>RTT</b><b class='flag-5'>大賽</b><b class='flag-5'>作品</b><b class='flag-5'>連載</b>】AB32VG1評估板到貨控制彩燈測試](https://file.elecfans.com//web2/M00/1B/B6/poYBAGGHqjGAZgd_AAQ5JxBMxnU803.jpg)
【RTT大賽作品連載】中科藍訊AB32VG1開發板開箱篇
![【<b class='flag-5'>RTT</b><b class='flag-5'>大賽</b><b class='flag-5'>作品</b><b class='flag-5'>連載</b>】中科藍訊AB32VG1開發板開箱篇](https://file.elecfans.com//web2/M00/1C/FD/pYYBAGGOg5-AaQa2AA-J9MBxhQg611.png)
CY方案,想做一個按鍵的短按和長按功能
【文章連載】RT-Thread創新應用大賽文章匯總
基于狀態機的單片機按鍵短按長按功能的實現
![基于狀態機的單片機<b class='flag-5'>按鍵</b><b class='flag-5'>短按</b><b class='flag-5'>長按</b>功能的實現](https://file1.elecfans.com//web2/M00/A7/1E/wKgZomUMQn2AC-71AABInne3axk814.png)
單片機按鍵進行長按和短按的流程分析和程序代碼免費下載
![單片機<b class='flag-5'>按鍵</b>進行<b class='flag-5'>長按</b>和<b class='flag-5'>短按</b>的流程分析和程序代碼免費下載](https://file.elecfans.com/web1/M00/A6/F5/o4YBAF2C5r2AHEntAACK_1dkE60808.png)
評論