非阻塞延时,状态机按键检测
2026/6/4 17:11:13 网站建设 项目流程

该程序使用的单片机为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_NOevent=0x10,//休闲状态 key_OneEvent, //短按一下 key_TwoEvent, //短按两下 key_ThrEvent, //短按三下 key_LonEvent, //长按 }KEY_EVENT;
//枚举,按键状态 typedef enum{ key_idle=0, //休闲状态 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 & (0x01<<APP_keyPIN))==0) ? 1 : 0 ; }
//按键扫描函数,10ms调用一次 //返回按键数据协议:1xh,具体数据参数见按键事件枚举 KEY_DET key_det={0}; uint8_t APP_scanKey(void) { _Bool read_key; read_key=APP_readKey(); switch(key_det.key_state) { case key_idle: //空闲状态 if(read_key){ //按下 key_det.key_state=key_DePr;//进入消抖状态 key_det.key_rmsTime++;//开始计时 } else key_det.key_rmsTime=0; key_det.key_event=key_NOevent; break; case key_DePr: if(!read_key){//松开状态,属于抖动,返回空闲状态 key_det.key_state=key_idle; key_det.key_rmsTime=0;//计时清0 } else{ if(key_det.key_rmsTime>=key_dtime)//完成消抖 { key_det.key_state=key_pressed;//确认按下 key_det.key_longState=0; key_det.key_dptime=0; } key_det.key_rmsTime++; } key_det.key_event=key_NOevent; break; case key_pressed: if(!read_key){ key_det.key_state=key_RelDePr;//释放中,进入消抖 } else { //按键按下时间大于长按时间且,长按情况未上报,则进入长按状态 if(key_det.key_rmsTime>=key_ltime && !key_det.key_longState) { key_det.key_state=key_longPre; key_det.key_longState=1; key_det.key_count=0;//长按触发,打断短按计数 key_det.key_event=key_LonEvent; } else{ key_det.key_event=key_NOevent; key_det.key_rmsTime++; } } break; case key_longPre: if(!read_key){ key_det.key_state=key_RelDePr; //等待释放 key_det.key_dptime++; } key_det.key_event=key_NOevent; break; case key_waitRel://短按等待释放 if(!read_key){ key_det.key_state=key_RelDePr; //等待释放 key_det.key_dptime++; } key_det.key_event=key_NOevent; break; case key_RelDePr: if(read_key){ //干扰,回到之前的状态 key_det.key_state=key_det.key_longState ? key_longPre : key_waitRel; key_det.key_dptime=0; } else { if(key_det.key_dptime>=key_dtime)//消抖完成 { key_det.key_dptime=0; if(key_det.key_longState){ key_det.key_state=key_idle; key_det.key_longState=0; } else{ key_det.key_state=key_shortPre; } } else key_det.key_dptime++; } key_det.key_event=key_NOevent; break; case key_shortPre://短按 key_det.key_count++; key_det.key_state=key_waitMuPre; if(key_det.key_count>=3) { key_det.key_count=3; key_det.key_event=key_ThrEvent; } break; case key_waitMuPre://等待连续按下或超时 if(read_key){ key_det.key_state=key_DePr; key_det.key_event=key_NOevent; } else { if(key_det.key_dptime>key_ftime)//超时 { if(key_det.key_count==1)key_det.key_event=key_OneEvent; else if(key_det.key_count==2)key_det.key_event=key_TwoEvent; key_det.key_count=0; key_det.key_state=key_idle; key_det.key_dptime=0; } else { key_det.key_dptime++; key_det.key_event=key_NOevent; } } break; default: key_det.key_state=key_idle; key_det.key_event=key_NOevent; break; } return key_det.key_event; }

main.c

volatile 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(tick>=10) { tick=0; APP_usartSendByte(APP_scanKey());//模拟串口发送按键协议数据 } } }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询