一个按键状态机程序怎么检测等待按键释放后执行相关处理程序?
bit flag_keyscan_enable = 0;unsigned char read_key(void)//马老师状态扫描按键
{
static unsigned char key_state = 0;
unsigned char key_press, key_return = 0;
key_press = key_input; // 读按键I/O电平
_nop_();
key_press = key_input; // 读按键I/O电平
switch (key_state)
{
case key_state_0: // 按键初始态
if (!key_press)
{
key_state = key_state_1; //键被按下,状态转换到键确认态
}
break;
case key_state_1: // 按键确认态
if (!key_press)
{
key_return = 1; // 按键仍按下,按键确认输出为"1" (1)
key_state = key_state_2; //状态转换到键释放态
}
else
{
key_state = key_state_0; //按键已抬起,转换到按键初始态
}
break;
case key_state_2:
if (key_press)
{
key_state = key_state_0; //按键已释放,转换到按键初始态
}
break;
}
return key_return;
}
while(1)//主函数循环
{
v_ClockUpdata_f();
if(flag_keyscan_enable)//10ms定时扫描键盘
{
flag_keyscan_enable = 0;//
if(read_key()) // 返回1 变量加一,
{
Count_number ++;
if(Count_number > 999)//如果大于999,计数器置1从头开始
{
Count_number = 1;
}
Print_data(); //打印输出函数,将变量Counter_number 输出
}
}
}
请教马老师及大家们,学习了马老师的状态机按键。检测一个按键成功了。但是现在有个问题是:主程序里我这样写的话好像就是函数返回1就说明有键按下,就开始执行变量加一,再打印输出。是按键按下就执行了,我现在想要等按键放开的时候再执行变量加一以及打印输出,该怎么检测啊?谢谢!! 1. 你为什么要“等按键放开的时候再执行变量加一以及打印输出”?如果用户不熟悉的话,会一直按着不放,等着打印输出。如果该键的功能是单一的,不需要区分短按和长按的话,还是只要确认有按键按下,不管是否已经释放,都执行按键处理。这个按键扫描的代码不管是短按,还是长按,都是确定只有一次按键按下的。
2。如果你喜欢“等按键放开的时候再执行变量加一以及打印输出”,改动也是非常简单的,就是一条指令的位置变化。为什么你不会仔细体会这个代码,自己做修改尝试呢?连20行不到的代码都不能体会里面的思路与方法,那以后如何设计更复杂的东西。 谢谢马老师,昨天晚上回家,修改了程序,已经改成可以按键放开后执行了。有看了琢磨了状态机,看来真的还不错!谢谢!!! 马老师,这个状态图还不会怎么看?谢谢
http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_544679.JPG
(原文件名:未命名.JPG) //在定时器中,定时10ms,定时到后在中断服务程序中调用上述函数,
//每次执行的间隔10ms,可以有效的消除消抖,提高CPU的利用率。
//PTD10,11,12,13,14
#include "key.h"
uint8 kk=0; //六个按键标志
uint8 rr=0; //松手检测标志位
void key_gpio_init()
{
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_PTx=PTD;
gpio_init.GPIO_Pins=GPIO_Pin10|GPIO_Pin11|GPIO_Pin12|GPIO_Pin13|GPIO_Pin14;
gpio_init.GPIO_PinControl=INPUT_PULL_UP|INPUT_PF_EN;
gpio_init.GPIO_Dir=DIR_INPUT;
LPLD_GPIO_Init(gpio_init); //GPIO通用初始化函数.0--配置错误;1--配置成功
}
void key_scan()
{
static enum key_states_e key_state=KEY_S1; //声明枚举变量,并且赋予枚举值
switch(key_state)
{
case KEY_S1: //按下
{
if((PTD10_I==0)||(PTD11_I==0)||(PTD12_I==0)||(PTD13_I==0)||(PTD14_I==0)) key_state = KEY_S2;
else key_state = KEY_S1;
break;
}
case KEY_S2: //防抖
{
if((PTD10_I==0)||(PTD11_I==0)||(PTD12_I==0)||(PTD13_I==0)||(PTD14_I==0))
{
key_state = KEY_S3;
if(PTD10_I==0) rr=1; //用于确定是哪个按键再松手之前按下
if(PTD11_I==0) rr=2;
if(PTD12_I==0) rr=3;
if(PTD13_I==0) rr=4;
if(PTD14_I==0) rr=5;
}
else key_state = KEY_S1;
break;
}
case KEY_S3: //松手
{
if((PTD10_I==1)&&(PTD11_I==1)&&(PTD12_I==1)&&(PTD13_I==1)&&(PTD14_I==1))
{
key_state = KEY_S1;
if(rr==1) {rr=0;kk=1;}
if(rr==2) {rr=0;kk=2;}
if(rr==3) {rr=0;kk=3;}
if(rr==4) {rr=0;kk=4;}
if(rr==5) {rr=0;kk=5;}
}
// else key_state = KEY_S1; //此语句应删除
break;
}
default:
key_state = KEY_S1;
break;
}
} 試看看是否有達到你要的功能
bit flag_keyscan_enable = 0;
unsigned char read_key(void)//馬老師狀態掃瞄按鍵
{
static unsigned char key_state = 0;
unsigned char key_press, key_return = 0;
key_press = key_input; // 讀按鍵I/O電平
_nop_();
key_press = key_input; // 讀按鍵I/O電平
switch (key_state)
{
case key_state_0: // 按鍵初始態
if (!key_press)
{
key_state = key_state_1; //鍵被按下,狀態轉換到鍵確認態
}
break;
case key_state_1: // 按鍵確認態
if (!key_press)
{
key_return = 1; // 按鍵仍按下,按鍵確認輸出為"1" (1)
key_state = key_state_2; //狀態轉換到鍵釋放態
}
else
{
key_state = key_state_0; //按鍵已抬起,轉換到按鍵初始態
}
break;
case key_state_2:
if (key_press)
{
key_state = key_state_0; //按鍵已釋放,轉換到按鍵初始態
key_return =2;
}
break;
}
return key_return;
}
while(1)//主函數循環
{
v_ClockUpdata_f();
if(flag_keyscan_enable)//10ms定時掃瞄鍵盤
{
flag_keyscan_enable = 0;//
if(read_key()==2) // 返回1 變數加一,
{
if(++Count_number > 999)//如果大於999,計數器置1從頭開始
{
Count_number = 1;
}
Print_data(); //列印輸出函數,將變數Counter_number 輸出
}
}
}
页:
[1]