基于状态机的按键扫描程序


前言

一开始在执行按键扫描是都会使用延时来进行消抖,使用这种方式的消抖会严重的浪费单片机的性能,这里介绍使用使用有限状态机的方式来扫描按键。


一、简介

按键扫描的消抖一般会延时10ms,按键扫描程序的状态一般分为:
状态一、判断按键是否按下,如果按下则跳转到状态二。
状态二、再次判断按键是否按下,如果有就跳转到状态三,否则跳转到状态一。
状态三、等待按键释放,并累加时间判断是否是长按,如果超过设置的长按的时间,跳转到状态四,否则跳转到状态一,并返回键值。
状态四、继续累加长按时间,连续触发按键并返回键值,否则跳转到状态一。

二、程序代码

1.扫描俺键

/**
 * @brief 获取IO口的值
 * @param 
 * @retval 
 */
static uint8_t IndependentKey_Get(void)
{
    uint8_t key = 0x00;
    if(HAL_GPIO_Read(&KEY1)) key = 0x01;
    else if(HAL_GPIO_Read(&KEY2)) key = 0x02;
    else if(HAL_GPIO_Read(&KEY3)) key = 0x04;
    else if(HAL_GPIO_Read(&KEY4)) key = 0x08;
    return key;
} 

2.获取键值

/** 
 * @brief 扫描按键
 * @param 
 * @retval 约定返回的低8位为按键按下的编号,高8位bit0为长按标志
 */
uint16_t IndependentKey_Scan(void) 
{
	static uint8_t state = 0;
	static uint16_t clickTime = 0;
	static uint16_t keyValue;//按键值
	uint16_t tempKeyValue = 0;//临时按键
	uint16_t reValue = 0;//返回值

	tempKeyValue = IndependentKey_Get();//获取键值
	
	switch (state)
	{
		case 0://状态0  等待按键按下
			if (tempKeyValue != 0)//检测按键是否按下,不为0表示有按键按下
			{
				state = 1;//迁移到状态1
				keyValue = tempKeyValue;//保存当前键值
			}
			break;
		case 1://状态1  消抖
			if (tempKeyValue == keyValue)//检测按键是否改变,如果没有改变迁移到状态2,否则迁移到状态0重新检测
			{
				clickTime = 0;
				state = 2;
				
			}
			else
				state = 0;
		break;
		case 2://状态2  已确认按下,判断是否是长按
			if (tempKeyValue == keyValue)//当前键值没有释放并且并且键值相同,开始累加长按计时
			{
				if (++clickTime > LONG_CLICK_TIME_1)//还在按下,计时判断是否是长按
				{
					state = 3;//长按条件成立,迁移到状态3,
					clickTime = 0;
					reValue = keyValue | 0x0100;//放回长按键值
				}
			}
			else//按键已释放或键值改变,返回当前键值
			{
				state = 0;
				reValue = keyValue;
			}
		break;
		case 3://状态三,长按中
			if (tempKeyValue == keyValue)//键值未改变,累加长按计时
			{
				if (++clickTime > LONG_CLICK_TIME_2)//还在按下,计时判断是否是长按
				{
					clickTime = 0;
					reValue = keyValue | 0x0100;//触发长按,返回键值
				}
			}
			else
			{
				state = 0;
			}
		break;
	}
	return reValue;
}

三、IndependentKey.h

/** 
 * @Author: 时间世纪
 * @Date: 2022-08-14 20:34:43
 * @Description: 
 */
#ifndef _INDEPENDENT_KEY_H_
#define _INDEPENDENT_KEY_H_

#include "stm32f4xx.h"
#include "HAL_Driver.h"

#define LONG_CLICK_TIME_1 100 //第一次触发长按,为IndependentKey_Scan函数调用的间隔时间*LONG_CLICK_TIME_1
#define LONG_CLICK_TIME_2 50//触发长按后的连续触发时间


/** 
 * @brief 扫描按键,应每10ms调用一次
 * @param 
 * @retval 约定返回的低8位为按键按下的编号,高8位bit0为长按标志
 */
extern uint16_t IndependentKey_Scan(void);

#endif

程序代码

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32矩阵键盘扫描方法用于检测矩阵键盘上的按键是否被按下。在实际应用中,我们常常需要使用矩阵键盘来进行人机交互,例如输入密码、控制设备等。因此,对于STM32的开发者而言,了解STM32矩阵键盘扫描方法是必不可少的。 STM32矩阵键盘扫描方法一般有两种:基于中断和基于轮询。 1. 基于中断 在基于中断的方法中,矩阵键盘的每个按键都被连接到STM32微控制器的一个GPIO引脚上。通过配置GPIO引脚为中断引脚,可以在按键按下或松开时触发中断。在中断服务程序中,可以读取相应的GPIO引脚状态,以确定哪个按键被按下或松开。 基于中断的方法具有响应速度快、实时性强的优点,适用于对键盘响应速度要求较高的应用场景。但是需要注意的是,如果中断处理程序过于复杂,可能会导致系统运行速度变慢或者出现死锁等问题。 2. 基于轮询 在基于轮询的方法中,程序以一定的时间间隔循环读取每个GPIO引脚的状态,以确定哪个按键被按下或松开。该方法需要占用一定的CPU资源,但实现相对简单。 基于轮询的方法具有代码简单、易于理解的优点,适用于对键盘响应速度要求不高的应用场景。但是需要注意的是,如果轮询间隔过长,可能会导致按键响应速度变慢或者漏检按键等问题。 两种方法都需要进行矩阵键盘的扫描,一般采用行列扫描的方法,即将键盘按键组成的矩阵分为若干行和列,通过逐行或逐列扫描,确定哪些按键被按下或松开。具体实现可以参考相关的STM32开发文档或示例代码。 总的来说,STM32矩阵键盘扫描方法需要根据具体应用场景进行选择,对于响应速度要求高的应用场景,可以选择基于中断的方法;对于代码简单、易于理解的应用场景,可以选择基于轮询的方法。在实际开发中,需要根据具体需求进行选择,并适当优化程序,以保证系统的稳定性和响应速度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值