关于嵌入式单片机按键应用的小总结

单片机按键驱动小技巧

平时在开发简单的工程应用时,会应用引脚资源少一些的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 --;
	}
}

实践步骤-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;
	}
}

至此,业务逻辑程序代码实现结束,以上代码针对按键功能对原工程进行剥离整理,若有需要,可查看博主原工程更为详细完整代码:https://github.com/Nepenthes/LB_ZIGB_devNode_sw_3bit/blob/master/Proj_sw_devZigbNode/Sensor/usrKin.c
同时,以上示例中的打印输出为串口引脚印射输出,与实际通信串口内部串口寄存器共用,这样做可以节省一点内存,具体实现也看查看原工程.

以上完成后便可以将驱动在前台大循环进行调用:
在这里插入图片描述
功能效果(图片):
在这里插入图片描述
功能效果(视频):
https://www.bilibili.com/video/av33750150?from=search&seid=12846664617436496314

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值