關於嵌入式微控制器按鍵應用的小總結
阿新 • • 發佈:2018-12-15
微控制器按鍵驅動小技巧
平時在開發簡單的工程應用時,會應用引腳資源少一些的MCU,這時要做稍複雜一些的使用者互動功能選項時,就需要單個按鍵實現更多的功能,這時就需要按鍵實現短按、長按、連按功能,以下說明這些功能的實現方法,應用場合在按鍵資源不足無法使用矩陣鍵盤的情況下。
業務邏輯說明
實現程式碼
給出的示例程式碼以STC15F系微控制器實現,硬體環境為觸控IC輸出訊號,實際可以應用到輕觸按鍵等任何需要消抖的按鍵需求; 硬體配置:
sbit touchPad_1 = P1 ^6;
sbit touchPad_2 = P1^7;
sbit touchPad_3 = P1^5;
單次掃描:
u8 touchPadScan_oneShoot(void){
u8 valKey_Temp = 0;
if(!touchPad_1)valKey_Temp |= 0x01;
if(!touchPad_2)valKey_Temp |= 0x02;
if(!touchPad_3)valKey_Temp |= 0x04;
return valKey_Temp;
}
實踐步驟-1):首先初始化定時器用於對按鍵按下時間以及連按間隔時間進行計時
定義按鍵按下計時值以及連按間隔時間進行計時值
u16 xdata touchPadActCounter = 0; //觸控計時
u16 xdata touchPadContinueCnt = 0; //連按間隔計時
定時器初始化
void appTimer0_Init(void){ //50us 中斷@24.000M
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 = 0x50;
TH0 = 0xFB;
TF0 = 0;
ET0 = 1; //開中斷
PT0 = 0; //高優先順序中斷
TR0 = 1;
}
計時執行
void timer0_Rountine (void) interrupt TIMER0_VECTOR{
u8 code period_1ms = 20;
static u8 counter_1ms = 0;
//****************1ms專用**********************************************/
if(counter_1ms < period_1ms)counter_1ms ++;
else{
/*觸控動作時間計時*/
if(touchPadActCounter)touchPadActCounter --;
/*連按間隔時間計時*/
if(touchPadContinueCnt)touchPadContinueCnt --;
}
}
實踐步驟-1-2):具體業務邏輯實現,本程式碼段為非同步進行,即在主程式大迴圈內一直呼叫即可. 相關巨集及資料結構
#define timeDef_touchPressContinue 350 //連按間隔時間設定,單位:ms
typedef enum{
press_Null = 1, //無按鍵
press_Short, //短按
press_ShortCnt, //連按
press_LongA, //長按A
press_LongB, //長按B
}keyCfrm_Type;
普通長短按觸發邏輯封裝
void touchPad_functionTrigNormal(u8 statusPad, keyCfrm_Type statusCfm){ //普通長短按觸發
switch(statusCfm){
case press_Short:{
#if(DEBUG_LOGOUT_EN == 1)
{ //用後註釋,否則佔用大量程式碼空間
u8 xdata log_buf[64];
sprintf(log_buf, "touchPad:%02X, shortPress.\n", (int)statusPad);
PrintString1_logOut(log_buf);
}
#endif
switch(statusPad){
case 1:
case 2:
case 4:{
swCommand_fromUsr.actMethod = relay_flip;
swCommand_fromUsr.objRelay = statusPad;
EACHCTRL_realesFLG = statusPad; //互控
devActionPush_IF.push_IF = 1; //推送使能
}break;
default:{}break;
}
}break;
case press_ShortCnt:{
#if(DEBUG_LOGOUT_EN == 1)
{ //用後註釋,否則佔用大量程式碼空間
u8 xdata log_buf[64];
sprintf(log_buf, "touchPad:%02X, cntPress.\n", (int)statusPad);
PrintString1_logOut(log_buf);
}
#endif
switch(statusPad){
case 1:
case 2:
case 4:{
swCommand_fromUsr.actMethod = relay_flip;
swCommand_fromUsr.objRelay = statusPad;
}break;
default:{}break;
}
}break;
case press_LongA:{
#if(DEBUG_LOGOUT_EN == 1)
{ //用後註釋,否則佔用大量程式碼空間
u8 xdata log_buf[64];
sprintf(log_buf, "touchPad:%02X, longPress_A.\n", (int)statusPad);
PrintString1_logOut(log_buf);
}
#endif
switch(statusPad){
case 1:{
}break;
case 2:{}break;
case 4:{
devStatusChangeTo_devHold(1); //裝置網路掛起
}break;
default:{}break;
}
}break;
case press_LongB:{
#if(DEBUG_LOGOUT_EN == 1)
{ //用後註釋,否則佔用大量程式碼空間
u8 xdata log_buf[64];
sprintf(log_buf, "touchPad:%02X, longPress_B.\n", (int)statusPad);
PrintString1_logOut(log_buf);
}
#endif
switch(statusPad){
case 1:{}break;
case 2:{}break;
case 4:{}break;
default:{}break;
}
}break;
default:{}break;
}
}
連按觸發邏輯封裝
void touchPad_functionTrigContinue(u8 statusPad, u8 loopCount){ //連按觸發
EACHCTRL_realesFLG = statusPad; //最後一次按下觸發互控同步
devActionPush_IF.push_IF = 1; //最後一次按下觸發推送使能
#if(DEBUG_LOGOUT_EN == 1)
{ //用後註釋,否則佔用大量程式碼空間
u8 xdata log_buf[64];
sprintf(log_buf, "touchPad:%02X, %02Xtime pressOver.\n", (int)statusPad, (int)loopCount);
PrintString1_logOut(log_buf);
}
#endif
switch(statusPad){
case 1:{
switch(loopCount){
case 3:{
}break;
case 4:{
usrZigbNwkOpen(); //開放網路
}break;
default:{}break;
}
}break;
case 2:{
switch(loopCount){
case 3:{}break;
default:{}break;
}
}break;
case 4:{
switch(loopCount){
case 3:{}break;
case 4:{
devHoldStop_makeInAdvance(); //裝置網路掛起提前結束
}break;
default:{}break;
}
}break;
default:{}break;
}
}
具體業務邏輯
void touchPad_Scan(void){
static u8 touchPad_temp = 0;
static bit keyPress_FLG = 0;
static bit funTrigFLG_LongA = 0;
static bit funTrigFLG_LongB = 0;
code u16 touchCfrmLoop_Short = timeDef_touchPressCfm, //消抖時間,即短按確認時間,單位:ms
touchCfrmLoop_LongA = timeDef_touchPressLongA, //長按A確認時間,單位:ms
touchCfrmLoop_LongB = timeDef_touchPressLongB, //長按B確認時間,單位:ms
touchCfrmLoop_MAX = 60000;//計時封頂
static u8 pressContinueGet = 0;
u8 pressContinueCfm = 0;
u16 conterTemp = 0; //時差計算快取,所有計時都為倒計時,初值為touchCfrmLoop_MAX,所以確認時間時,需要進行減法運算
if(touchPadScan_oneShoot()){
if(!keyPress_FLG){
keyPress_FLG = 1;
touchPadActCounter = touchCfrmLoop_MAX;
touchPadContinueCnt = timeDef_touchPressContinue; //連按間隔判斷時間更新
touchPad_temp = touchPadScan_oneShoot();
}
else{
if(touchPad_temp == touchPadScan_oneShoot()){
conterTemp = touchCfrmLoop_MAX - touchPadActCounter;
if(conterTemp > touchCfrmLoop_LongA && conterTemp <= touchCfrmLoop_LongB){
if(!funTrigFLG_LongA){
funTrigFLG_LongA = 1;
touchPad_functionTrigNormal(touchPad_temp, press_LongA);
}
}
if(conterTemp > touchCfrmLoop_LongB && conterTemp <= touchCfrmLoop_MAX){
if(!funTrigFLG_LongB){
funTrigFLG_LongB = 1;
touchPad_functionTrigNormal(touchPad_temp, press_LongB);
}
}
}
}
}else{
if(keyPress_FLG){
conterTemp = touchCfrmLoop_MAX - touchPadActCounter;
if(conterTemp > touchCfrmLoop_Short && conterTemp <= touchCfrmLoop_LongA){
if(touchPadContinueCnt)pressContinueGet ++;
if(pressContinueGet <= 1)touchPad_functionTrigNormal(touchPad_temp, press_Short);
else touchPad_functionTrigNormal(touchPad_temp, press_ShortCnt);
beeps_usrActive(3, 50, 3);
}
}
if(!touchPadContinueCnt && pressContinueGet){
pressContinueCfm = pressContinueGet;
pressContinueGet = 0;
if(pressContinueCfm >= 2){
touchPad_functionTrigContinue(touchPad_temp, pressContinueCfm);
pressContinueCfm = 0;
}
touchPad_temp = 0;
}
funTrigFLG_LongA = 0;
funTrigFLG_LongB = 0;
touchPadActCounter = 0;
keyPress_FLG = 0;
}
}