非阻塞延时,状态机按键检测
该程序使用的单片机为py32c642主要使用系统滴答定时器定一个1ms中断为计时时基每隔10ms扫描检测一次按键引脚电平未达到10ms计时时间系统可以去执行其它程序段达到非阻塞目的key.c//宏定义GPIO端口和引脚方便移植修改 #define APP_keyGPIO GPIOB #define APP_keyPIN 3//宏定义按键检测需要时间参数 #define key_dtime 2 //抖动时间 #define key_ltime 100 //长按判定时间1s #define key_ftime 30 //连续短按空闲时间300ms//枚举按键事件 typedef enum{ key_NOevent0x10,//休闲状态 key_OneEvent, //短按一下 key_TwoEvent, //短按两下 key_ThrEvent, //短按三下 key_LonEvent, //长按 }KEY_EVENT;//枚举按键状态 typedef enum{ key_idle0, //休闲状态 key_DePr, //消抖 key_pressed, //确认按下 key_longPre, //长按状态 key_waitRel, //等待释放 key_RelDePr, //释放消抖 key_shortPre, //确认一次短按 key_waitMuPre, //等待连续按下或超时 }KEY_STATE;//结构体按键检测需要参数 typedef struct{ uint16_t key_rmsTime; //按下计时/10ms uint8_t key_freeTime; //松开计时/10ms uint8_t key_count; //短按计数 uint8_t key_dptime; //释放消抖计时/10ms _Bool key_DEstate; //消抖标志位复位0 _Bool key_longState; //长按事件上报情况 KEY_EVENT key_event; //按键事件 KEY_STATE key_state; //按键状态 }KEY_DET;void APP_keyInit(void)//按键引脚初始化 { APP_keyGPIO-MODER ~(0x03(2*APP_keyPIN)); //输入模式 APP_keyGPIO-PUPDR |0x01(2*APP_keyPIN); //上拉 } _Bool APP_readKey(void)//读取key引脚电平低电平(按下)为true/1高电平(松开)为false/0 { return ((APP_keyGPIO-IDR (0x01APP_keyPIN))0) ? 1 : 0 ; }//按键扫描函数10ms调用一次 //返回按键数据协议1xh具体数据参数见按键事件枚举 KEY_DET key_det{0}; uint8_t APP_scanKey(void) { _Bool read_key; read_keyAPP_readKey(); switch(key_det.key_state) { case key_idle: //空闲状态 if(read_key){ //按下 key_det.key_statekey_DePr;//进入消抖状态 key_det.key_rmsTime;//开始计时 } else key_det.key_rmsTime0; key_det.key_eventkey_NOevent; break; case key_DePr: if(!read_key){//松开状态属于抖动返回空闲状态 key_det.key_statekey_idle; key_det.key_rmsTime0;//计时清0 } else{ if(key_det.key_rmsTimekey_dtime)//完成消抖 { key_det.key_statekey_pressed;//确认按下 key_det.key_longState0; key_det.key_dptime0; } key_det.key_rmsTime; } key_det.key_eventkey_NOevent; break; case key_pressed: if(!read_key){ key_det.key_statekey_RelDePr;//释放中进入消抖 } else { //按键按下时间大于长按时间且长按情况未上报则进入长按状态 if(key_det.key_rmsTimekey_ltime !key_det.key_longState) { key_det.key_statekey_longPre; key_det.key_longState1; key_det.key_count0;//长按触发打断短按计数 key_det.key_eventkey_LonEvent; } else{ key_det.key_eventkey_NOevent; key_det.key_rmsTime; } } break; case key_longPre: if(!read_key){ key_det.key_statekey_RelDePr; //等待释放 key_det.key_dptime; } key_det.key_eventkey_NOevent; break; case key_waitRel://短按等待释放 if(!read_key){ key_det.key_statekey_RelDePr; //等待释放 key_det.key_dptime; } key_det.key_eventkey_NOevent; break; case key_RelDePr: if(read_key){ //干扰回到之前的状态 key_det.key_statekey_det.key_longState ? key_longPre : key_waitRel; key_det.key_dptime0; } else { if(key_det.key_dptimekey_dtime)//消抖完成 { key_det.key_dptime0; if(key_det.key_longState){ key_det.key_statekey_idle; key_det.key_longState0; } else{ key_det.key_statekey_shortPre; } } else key_det.key_dptime; } key_det.key_eventkey_NOevent; break; case key_shortPre://短按 key_det.key_count; key_det.key_statekey_waitMuPre; if(key_det.key_count3) { key_det.key_count3; key_det.key_eventkey_ThrEvent; } break; case key_waitMuPre://等待连续按下或超时 if(read_key){ key_det.key_statekey_DePr; key_det.key_eventkey_NOevent; } else { if(key_det.key_dptimekey_ftime)//超时 { if(key_det.key_count1)key_det.key_eventkey_OneEvent; else if(key_det.key_count2)key_det.key_eventkey_TwoEvent; key_det.key_count0; key_det.key_statekey_idle; key_det.key_dptime0; } else { key_det.key_dptime; key_det.key_eventkey_NOevent; } } break; default: key_det.key_statekey_idle; key_det.key_eventkey_NOevent; break; } return key_det.key_event; }main.cvolatile uint16_t tick 0; void SysTick_Handler(void) { tick; //实现系统时间戳 } int main() { /*系统时钟以及滴答定时器初始化*/ system_clock_init(); /*GPIO时钟*/ RCC-IOPENR | RCC_IOPENR_GPIOAEN; RCC-IOPENR | RCC_IOPENR_GPIOBEN; RCC-IOPENR | RCC_IOPENR_GPIOCEN; /*外设初始化*/ //APP_Tim14Init(24,0xffff); 定时器初始化 //APP_Tim1Init(24,200-1); APP_usartInit();//模拟发送串口初始化 APP_keyInit();//按键初始化 APP_ledInit(); while(1) { if(tick10) { tick0; APP_usartSendByte(APP_scanKey());//模拟串口发送按键协议数据 } } }