一个实用的按键扫描方案

由于项目需要外置一个控制盒通过按键来控制系统移动、启动功能,其中感觉所写的按键部分还算实用就分享出来,如果更好的方案不妨给出指点和分享出来大家都学习学习 以下文章按键弹起状态为1 按下状态为0 

基本原理 机械按键由于其特殊性在按下或者弹起的时刻会有机械抖动引起误差,会出现采集状态在0和1之间来回切换,直到稳定状态。我所设计的系统中有4个按键上行按键UpKey,停止按键StopKey,下行按键DownKey活启动/停止按键OnOffKey,设计思路就是不停的扫描对应的IO口状态

步骤1,开启一个定时器频率为1000Hz(周期为1ms)的定时器,在其回调函数中进行对应的IO口扫描

 //开启定时器中断 频率1000Hz

  HAL_TIM_Base_Start_IT(&htim6);

步骤二定义一个按键标志数组,和一个按键灵敏度控制变量

uint8_t KeyMask[4] = {0x0}; //分别对应上行按键 停止按键 下行按键 启动/关闭按键状态 0x01对应按键按下 0x00对应无按键按下状态

#define KEYMASK 0x0000ffff   //定义按键灵敏度,即当按键按下处于稳定状态0达到多少ms后才算按键按下 16ms可以根据自己所需要进行调节

步骤三编写中断定时器回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){

//缓存32次按键扫描结果,每次扫描保存左移一位

static uint32_t KeyUpCoder = 0xffffffff; //按键没有按下时刻为高电平状态

static uint32_t KeyStopCoder = 0xffffffff;

static uint32_t KeyDownCoder = 0xffffffff;

static uint32_t KeySysCoder = 0xffffffff;

if(htim->Instance == htim6.Instance){                //判断定时器中断触发源

//左移一位,剔除最早采集的状态准备加入最新的采集状态

KeyUpCoder   <<= 1;

KeyStopCoder <<= 1;

KeyDownCoder <<= 1;

KeySysCoder  <<= 1;

//采样按键值

KeyUpCoder   |= HAL_GPIO_ReadPin(KeyUp_GPIO_Port,KeyUp_Pin);

KeyStopCoder |= HAL_GPIO_ReadPin(KeyStop_GPIO_Port,KeyStop_Pin);

KeyDownCoder |= HAL_GPIO_ReadPin(KeyDown_GPIO_Port,KeyDown_Pin);

KeySysCoder  |= HAL_GPIO_ReadPin(KeySys_GPIO_Port,KeySys_Pin);

//进行按键解析是否存在按键,

//首先判断之前是否发生过按键按下情况,且主程序是否完成了对应按键的程序处理

//如果主程序还未完成相关程序处理,则本次按键无效

//KeyMask代表按键是否有效,且表达了主程序是否完成了相关服务程序的 

                //通过判断只有连续出现了大于等于灵敏度次稳定状态电平,才会判断定按键按下一般机械抖动在10ms左右,可根据自己需要调动

                //在主程序中通过判断KeyMask来识别是否有按键按下 完成相关服务函数处理同时需要释放KeyMask,来开始新的一次扫描

//判断上行按键

if((!KeyMask[0])&&((KeyUpCoder&KEYMASK)== 0x00000000)) //完成消抖判断

KeyMask[0] = 0x01;

//判断停止按键

if((!KeyMask[1])&&((KeyStopCoder&KEYMASK)== 0x00000000))

KeyMask[1] = 0x01;

//判断下行按键

if((!KeyMask[2])&&((KeyDownCoder&KEYMASK)== 0x00000000))

KeyMask[2] = 0x01;

//判断系统按键

if((!KeyMask[3])&&((KeySysCoder&KEYMASK)== 0x00000000))

KeyMask[3] = 0x01;

}

}

by 荒野大嫖客

3 个评论

不错

谢谢分享

good

要回复文章请先登录注册