按键这个看似简单的应用
无帝老三 发表于 2017-2-22 13:56
您好,是不是状态机加定时器?
可不可以用任务延时代替定时器?
是状态机+定时器的做法。
不建议用任务延时代替定时器,因为任务延时会额外占用一个任务描述符。但是在操作系统环境下,用一个专门的任务监控状态机并且分发按键消息是非常有必要的。
很不错,学到了,谢谢 楼主
suyong_yq 发表于 2017-3-5 00:47
是状态机+定时器的做法。
不建议用任务延时代替定时器,因为任务延时会额外占用一个任务描述符。但是在操 ...
这还有一个方法就是,用OS的软件定时器,对于还有误触发情况我们可以用STM32硬件按键滤波方法
---》STM32的定时器输入通道都有一个滤波单元,分别位于每个输入通路上(下图中的黄色框)和外部触发输入通路上(下图中的兰色框),它们的作用是滤除输入信号上的高频干扰。
http://www.eeworld.com.cn/mndz/2013/0922/article_19360.html
这个是香水城分享的
appllo 发表于 2015-12-18 11:12
消息队列肯定是更好的
方法很多,基于队列也很好。不过基于队列同时相应两个按键连击好像处理就麻烦点了。
下面是我开一个按键扫描任务里面发送标志到标志组,其他任务检查标志组就可以。
void KeyTask(void *parg)
{
OS_ERRerr;
CPU_INT08U key;
APP_ARG *p_arg = (APP_ARG *)parg;
static LCDDAT lcd;
if(OSFlagPend(p_arg->pfgrp,(OS_FLAGS)SDCardLessFlag+NoSDCardFlag,100,OS_OPT_PEND_NON_BLOCKING + OS_OPT_PEND_FLAG_SET_ANY,NULL,&err))
{
lcd.pic = FlashDiyLCD;lcd.period = 0;
SysPower(CLOSE);
}else {
lcd.pic = SystemNormalLCD;lcd.period = 1;
}
OSQPost(p_arg->pLCDQ,(void *)&lcd,sizeof(lcd),OS_OPT_POST_FIFO,&err);
OSTimeDlyResume(p_arg->LCDTaskTCB,&err);
LED_B(CLOSE);
do{OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_DLY,&err);}
while(GetKEYStatus(POWER));
while(1)
{
key = QueryKeyCode();
if(key != NoKey){
if(key==POWER_CTL_KEY){
//OSTimeDlyHMSM(0,0,PWR_KEY_TIME_DELAY,0,OS_OPT_TIME_DLY,&err); /* 关机延时 */
OSFlagPost(p_arg->pfgrp,BeepRunFlag,OS_OPT_POST_FLAG_SET,&err);//打开蜂鸣器
OSTimeDlyHMSM(0,0,0,300,OS_OPT_TIME_DLY,&err);
OSFlagPost(p_arg->pfgrp,BeepRunFlag,OS_OPT_POST_FLAG_CLR,&err);//关闭蜂鸣器
OSTimeDlyHMSM(0,0,0,300,OS_OPT_TIME_DLY,&err);
OSFlagPost(p_arg->pfgrp,BeepRunFlag,OS_OPT_POST_FLAG_SET,&err);//打开蜂鸣器
OSTimeDlyHMSM(0,0,0,300,OS_OPT_TIME_DLY,&err);
OSFlagPost(p_arg->pfgrp,BeepRunFlag,OS_OPT_POST_FLAG_CLR,&err);//关闭蜂鸣器
GPIO_ResetBits(GPIOC, GPIO_Pin_2);//不叫
}else{
OSTimeDlyHMSM(0,0,0,KEY_TIME_DELAY,OS_OPT_TIME_DLY,&err); /* 按键去抖延时 */
}
if(key == QueryKeyCode())
{
lcd.period = 1;
switch(key){
case POWER_CTL_KEY:
if(StartADCFlag)StartADCFlag = 0;
OSFlagPost(p_arg->pfgrp,PowerDownFlag,OS_OPT_POST_FLAG_SET,&err);
SysPower(CLOSE); LED_B(CLOSE);LED_G(CLOSE);
lcd.pic = ShutDownFinishLCD;
OSQPost(p_arg->pLCDQ,(void *)&lcd,sizeof(lcd),OS_OPT_POST_FIFO,&err);
OSTimeDlyResume(p_arg->LCDTaskTCB,&err);
break;
case START_RECORD_KEY:
OSFlagPost(p_arg->pfgrp,StartRecordFlag,OS_OPT_POST_FLAG_SET,&err);
//OSFlagPend(p_arg->pfgrp,(OS_FLAGS)StartADCCnvFlag,0,OS_OPT_PEND_BLOCKING + OS_OPT_PEND_FLAG_SET_ALL,NULL,&err);
lcd.pic = RecordingLCD;
OSQPost(p_arg->pLCDQ,(void *)&lcd,sizeof(lcd),OS_OPT_POST_FIFO,&err);
OSTimeDlyResume(p_arg->LCDTaskTCB,&err);
OSFlagPost(p_arg->pfgrp,RecordRunFlag,OS_OPT_POST_FLAG_SET,&err);
break;
case ECG_MARK_KEY:
if(OSFlagPend(p_arg->pfgrp,(OS_FLAGS)RecordRunFlag,0,OS_OPT_PEND_FLAG_SET_ALL+
OS_OPT_PEND_NON_BLOCKING,NULL,&err)){
if(OS_ERR_NONE == err){
OSFlagPost(p_arg->pfgrp,(OS_FLAGS)ECGMarkFlag,OS_OPT_POST_FLAG_SET,&err);
lcd.pic = EcgMarkLCD;
}
}else lcd.pic = SystemNormalLCD;
OSQPost(p_arg->pLCDQ,(void *)&lcd,sizeof(lcd),OS_OPT_POST_FIFO,&err);
OSTimeDlyResume(p_arg->LCDTaskTCB,&err);
break;
case DISPLAY_INFO_KEY:
if(OSFlagPend(p_arg->pfgrp,(OS_FLAGS)StartRecordFlag,0,OS_OPT_PEND_FLAG_SET_ALL+
OS_OPT_PEND_NON_BLOCKING,NULL,&err)){
lcd.pic = DisplayInfoLCD;
}else lcd.pic = SystemNormalLCD;
OSQPost(p_arg->pLCDQ,(void *)&lcd,sizeof(lcd),OS_OPT_POST_FIFO,&err);
OSTimeDlyResume(p_arg->LCDTaskTCB,&err);
break;
}
OSTimeDlyHMSM(0,0,0,200,OS_OPT_TIME_DLY,&err);
}
}elseOSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_DLY,&err);
}
}