【蓝桥杯嵌入式】状态机按键

        按键作为人机交互中重要的一环,是必需掌握的部分。比赛板子上一共有4个按键,分别连接到不同的IO口上(B1----PB0,B2----PB1,B3----PB2,B4----PA0)。如下图所示,按键在松开(空闲)状态时,IO口检测到电平为高电平,按键按下时,IO口检测到的为低电平。我们把相应IO口设置为输入模式,那么捕捉到低电平,我们就可以认为按键被按下了。由于物理按键存在一些抖动、振动等不确定因素,所以需要添加软件消抖(在检测到按下信号后,隔10~20ms后再次确认状态,排除干扰)。我们选择结合定时器轮询,同时使用状态机检测方法(将在下面的编程部分进行介绍),这样既可以实现消抖、多按键检测、单次起效,还可以拓展实现长短按、双按等等。

一、STM32Cube 按键的设置

复制上次的2_TIM工程文件夹,并命名为“3_KEY”,打开TEST.ioc。

Cube中将PB0,PB1,PB2,PA0设置为输入模式,上拉(Pull-up),并进行命名。按键外接上拉电阻,在空闲状态下,IO口被拉至高电平,所以选择上拉模式。

轮询用的定时器我们沿用上次设置的总控定时器TIM4,这样基本设置就好了,按“GENERATE CODE”更新工程。

二、按键(状态机)程序的实现

用Keil 5打开TEST.uvprojx,再打开USER中用于中断的interrupt.c。

我们计划通过按键来控制按钮,各按键效果:

B1:亮LD1、LD2

B2:亮LD3、LD4

B3:LD5、LD6状态翻转

B4:熄灭LD1~LD6

其他LED灯效果:LD7始终熄灭,LD8每0.5s翻转一次状态。

1、基本的状态机编程

首先,我们为状态机定义三个状态:空闲状态,未按下(IDLE)、按下待执行相应功能(PRESSED_READY)、按下功能已执行等待松开按键回到空闲状态(PRESSED_FINISH)。

我们定义了一个枚举类型变量 ButtonState,来记录这些状态。

typedef enum 
{
	IDLE,						//未按下,空闲状态
	PRESSED_READY,	//按下,待执行相应功能
	PRESSED_FINISH,	//按下,功能已执行,等待松开按键回到空闲状态
	//PRESSED_COUNT		//按下,处于计时状态(用于长短按)
}ButtonState;			//状态机状态

枚举类型的用法:

enum 枚举类型名 {
    枚举常量1,
    枚举常量2,
<think>嗯,用户想要蓝桥杯嵌入式竞赛中实现长按按键功能的解决方案或示例代码。我需要先回忆相关的知识,比如按键检测通常需要消抖,状态机处理不同事件,比如按下、释放、长按等。蓝桥杯可能使用的硬件平台是STM32,所以需要结合HAL库或者寄存器操作。 首先,按键检测的基本流程是消抖,通常用定时器中断或者滴答定时器来周期性检测按键状态。然后,状态机处理不同的按键事件,比如按下、保持、释放,以及长按的判断。长按需要计时,比如当按键保持超过一定时间(比如1秒)后触发长按事件。 记得用户提供的引用中提到了滴答定时器的方法,比如使用uwTick来管理时间,这可能涉及到SysTick或者HAL库的定时器函数。另外,按钮响应时间需要在0.1秒以内,所以消抖时间可能设置为20ms左右,避免过长的延时影响响应速度。 可能需要使用状态机模型,将按键的状态分为初始态、消抖检测态、按下态、长按态等。每个状态下根据时间间隔检测按键的当前状态,并更新状态变量。例如,当检测到按键按下后,进入消抖状态,等待一段时间后再次检测,确认按下后进入按下态,并开始计时,如果超过长按时间阈值,则标记长按事件。 示例代码可能需要初始化GPIO,配置按键为输入模式,开启上拉或下拉电阻。然后,在定时中断或主循环中调用按键处理函数,使用状态机进行状态转换。同时,处理长按事件时,需要记录按键按下的起始时间,并在每次处理时检查当前时间是否超过阈值。 另外,引用中的LED处理函数使用了uwTick来管理非阻塞延时,这可以借鉴到按键处理中,避免使用阻塞延时函数。比如,使用类似的方法记录时间戳,比较当前时间与上次处理的时间差,判断是否达到消抖或长按的时间要求。 需要确保代码符合蓝桥杯嵌入式组的要求,可能使用STM32G4系列芯片,HAL库函数。代码结构要清晰,主循环中调用各个处理函数,如LED_Process和Key_Process,保持模块化设计。 可能还需要考虑多任务处理,比如按键处理与其他任务(如LED显示、通信等)的协调,确保系统实时性。使用非阻塞方式可以避免影响其他任务的执行。 最后,生成示例代码时,需要包含必要的头文件,定义按键的GPIO端口和引脚,定义按键状态枚举,以及状态变量和时间变量。在按键处理函数中实现状态转换逻辑,并触发相应的事件处理函数,如长按回调函数。</think>在蓝桥杯嵌入式竞赛中,实现长按按键功能需要结合状态机和定时器消抖技术。以下是基于STM32 HAL库的解决方案: ### 长按按键实现方案 ```c // 按键状态枚举 typedef enum { KEY_STATE_RELEASED, // 按键释放 KEY_STATE_DEBOUNCE, // 消抖检测 KEY_STATE_PRESSED, // 短按确认 KEY_STATE_LONG_PRESS // 长按确认 } Key_State; // 按键结构体定义 typedef struct { GPIO_TypeDef* GPIOx; // 按键端口 uint16_t GPIO_Pin; // 按键引脚 Key_State state; // 当前状态 uint32_t pressTime; // 按下时间戳 } Key_Handle; // 长按时间阈值(1秒) #define LONG_PRESS_THRESHOLD 1000 // 按键处理函数 void Key_Process(Key_Handle* key) { uint8_t currentState = HAL_GPIO_ReadPin(key->GPIOx, key->GPIO_Pin); switch(key->state) { case KEY_STATE_RELEASED: if(currentState == GPIO_PIN_RESET) { // 检测到按下 key->state = KEY_STATE_DEBOUNCE; key->pressTime = HAL_GetTick(); // 记录按下时间[^2] } break; case KEY_STATE_DEBOUNCE: if(HAL_GetTick() - key->pressTime > 20) { // 消抖20ms[^1] if(currentState == GPIO_PIN_RESET) { key->state = KEY_STATE_PRESSED; } else { key->state = KEY_STATE_RELEASED; } } break; case KEY_STATE_PRESSED: if(currentState == GPIO_PIN_SET) { // 释放检测 key->state = KEY_STATE_RELEASED; // 触发短按事件 ShortPress_Callback(); } else if(HAL_GetTick() - key->pressTime > LONG_PRESS_THRESHOLD) { key->state = KEY_STATE_LONG_PRESS; // 触发长按事件 LongPress_Callback(); } break; case KEY_STATE_LONG_PRESS: if(currentState == GPIO_PIN_SET) { // 释放检测 key->state = KEY_STATE_RELEASED; } break; } } // 示例初始化 Key_Handle key1 = { .GPIOx = GPIOB, .GPIO_Pin = GPIO_PIN_0, .state = KEY_STATE_RELEASED }; // 主循环调用 while(1) { Key_Process(&key1); LED_Process(); // 结合引用[2]的LED处理 } ``` ### 实现要点 1. **状态机设计**:通过4种状态实现精准检测 2. **消抖处理**:采用20ms硬件消抖时间[^1] 3. **非阻塞检测**:使用`HAL_GetTick()`实现时间戳记录[^2] 4. **长按判定**:设置1秒阈值检测持续按压
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值