基于有限状态机与STM32实现按键扫描
有限状态机其实是一种概念性机器,表示有限个状态以及在这些状态之间的转移和动作等行为的框图(在程序上)。
以我的程序绘成的图为例:
以高电平作为标志,在S1时检测输入电平是否为高,是高电平则运行至S2,否则保持在S1;
在S2时再次判断判断输入电平是否为高,若为低则说明刚刚的改变是干扰,回到S1,若为高电平则说明按键被按下,运行至S3;
在S3可判断这次对按键的操作是长按还是短按,具体方法是判断电平是否还是为高,若为高则令状态机保持在S3,同时定义一个变量(建议用指针,具体见代码),使其一直自加。若为低则运行至S4;
在S4时判断那个变量是否大于某个数值,大于则为长按,小于则为短按,并执行相关的操作,执行完之后令状态机回到S1
这种写法是可以利用时间片的形式,每隔10ms运行一次状态机,即可实现消抖的目的,还可以对长按的时间精确控制。
运用状态机+时间片,大幅提升CPU的资源的利用率,而且效率高了不少。
时间片的话举个例子,比如我一个周期30ms,10ms需要执行一次按键扫描,20ms执行一次ADC,那么利用时间片的话程序就是:
注:Time是在定时器中断里每隔1ms自加一次。
if( Time %10 == 0 ){ KeyScan(); } if( Time %20 == 0 ){ ADC(); } if( Time > 30 ){ Time = 1; }
贴上我写的完整代码:
Key.h:
#ifndef _BSP_KEY_H #define _BSP_KEY_H #include "stm32f10x.h" #define KEY0_GPIO_PORT GPIOE #define KEY0_GPIO_PIN GPIO_Pin_0 #define KEY0_GPIO_CLOCK RCC_APB2Periph_GPIOE #define KEY1_GPIO_PORT GPIOE #define KEY1_GPIO_PIN GPIO_Pin_1 #define KEY1_GPIO_CLOCK RCC_APB2Periph_GPIOE #define KEY2_GPIO_PORT GPIOE #define KEY2_GPIO_PIN GPIO_Pin_2 #define KEY2_GPIO_CLOCK RCC_APB2Periph_GPIOE #define ON 1 #define OFF 0 #define LONGTIME 8000 //---------定义状态Sx的枚举类型 typedef enum { FsmState_1 = 1, FsmState_2 = 2, FsmState_3 = 3, FsmState_4 = 4, FsmState_5 = 5, }FsmState_x; //---------定义按键的结构体 typedef struct FsmTable_s{ uint8_t event; /* 触发事件 */ uint8_t CurState; /* 当前状态 */ void (*EventFunction)(void); /* 动作函数 */ uint16_t Time; /* 时间计数 */ uint16_t GpioPin; /* 按键引脚 */ GPIO_TypeDef * GpioPort; /* 引脚GPIO */ }Key; void key_GPIO_Init(void); void Key_1_EventFunction(void); void Key_1_LongEventFunction(void); void Key_2_EventFunction(void); void Key_2_LongEventFunction(void); void Key_Fsm(Key *key); #endif
Key.c:
/********************************************** * * 状态机相关 * **********************************************/ /********************************************** * * 按键1短按时的事件函数 * *********************************************/ void Key_1_EventFunction() { } /********************************************** * * 按键1长按时的事件函数 * *********************************************/ void Key_1_LongEventFunction() { } /********************************************** * * 按键2短按时的事件函数 * *********************************************/ void Key_2_EventFunction() { } /********************************************** * * 按键2长按时的事件函数 * *********************************************/ void Key_2_LongEventFunction() { } /********************************************** * * 基于状态机的按键扫描 * 输入:Key类型的指针变量 * 输出:无 * *********************************************/ void Key_Fsm(Key *key) { void (*EventFunction)(void); switch( key->CurState ) { case FsmState_1:{//--------状态1 if( GPIO_ReadInputDataBit(key->GpioPort,key->GpioPin) == ON ){ key->CurState = FsmState_2; } }break; case FsmState_2:{//--------状态2 if( GPIO_ReadInputDataBit(key->GpioPort,key->GpioPin) == ON ){ key->CurState = FsmState_3; } else{//--------干扰返回状态1 key->CurState = FsmState_1; } }break; case FsmState_3:{ if( GPIO_ReadInputDataBit(key->GpioPort,key->GpioPin) == ON ){ key->Time++;//--------变量自加 key->CurState = FsmState_3;//--------保持在状态3 } else{ key->CurState = FsmState_4; } }break; case FsmState_4:{ EventFunction = key->EventFunction;//--------短按函数 if( (key->Time > LONGTIME) && (key->GpioPin == KEY0_GPIO_PIN) ){ key->Time = 0; EventFunction = Key_1_LongEventFunction;//--------Key1的长按函数 } if( (key->Time > LONGTIME) && (key->GpioPin == KEY1_GPIO_PIN) ){ key->Time = 0; EventFunction = Key_2_LongEventFunction;//--------Key2的长按函数 } key->CurState = FsmState_1;//--------返回状态1 EventFunction();//--------执行对应的函数 }break; } }
main.c:
#include "bsp_key.h" extern uint16_t TimeSlice; int main() { Key *key_1,*key_2; Key key1,key2; key_1 = &key1; key_2 = &key2; TIM_TimeBase_Init(); key_GPIO_Init(); key_1->GpioPin = KEY0_GPIO_PIN; key_1->GpioPort = KEY0_GPIO_PORT; key_1->CurState = FsmState_2; key_1->EventFunction = Key_1_EventFunction; key_2->GpioPin = KEY1_GPIO_PIN; key_2->GpioPort = KEY1_GPIO_PORT; key_2->CurState = FsmState_1; key_2->EventFunction = Key_2_EventFunction; while(1) { //--------------按键扫描,10ms执行一次--------------// if( TimeSlice %10==0 ){ Key_Fsm(key_1); Key_Fsm(key_2); } } }
原文地址: https://blog.csdn.net/Unlimited_Bit/article/details/95811859