蓝桥杯独立按键状态机
时间: 2025-05-08 19:32:26 浏览: 21
### 关于蓝桥杯竞赛中的独立按键状态机设计实现
在嵌入式系统开发中,尤其是针对像蓝桥杯这样的比赛环境,采用有限状态机(FSM)模型来管理按键输入是一种常见且有效的方法。这种方法不仅能够提高系统的响应速度和稳定性,还能简化复杂逻辑的设计。
#### 使用定时器与GPIO组合检测按键动作
为了准确捕捉到用户的每一次操作而不遗漏任何一次按下行为,在硬件层面上通常会配置一个外部中断用于触发事件;而在软件层面,则通过设置一定时间间隔内的轮询机制配合去抖动算法以区分短按、长按以及连击等情况[^1]。
```c
#include <stdint.h>
#include "stm32f10x.h"
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_Pin_0
volatile uint8_t button_state = 0; // 当前按钮的状态
volatile uint8_t last_button_state = 0; // 上次记录的按钮状态
uint16_t press_duration = 0;
uint8_t click_count = 0;
void Button_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = BUTTON_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(BUTTON_PORT,&GPIO📐⚗⚗
GPIO_InitStructure);
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void EXTI0_IRQHandler(void){
if (EXTI_GetITStatus(EXTI_Line0)!= RESET){
last_button_state = button_state;
button_state ^= 1;
if(button_state == 1){
press_duration = 0;
click_count++;
}
// 清除标志位
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
```
此部分代码实现了基本的初始化工作并设置了当检测到下降沿时进入中断服务函数`EXTI0_IRQHandler()`,其中包含了改变当前按键状态的操作,并重置了计数器以便后续判断具体的按键类型。
#### 定义状态转换规则
接下来定义几个主要变量用来跟踪按键的变化情况:
- `button_state`: 表示当前按键是否被按下;
- `last_button_state`: 记录上一时刻按键的状态,用于比较是否有变化发生;
- `press_duration`: 统计持续按下的毫秒数,以此作为判定长时间按压的标准;
- `click_count`: 对快速连续点击次数进行累加统计。
基于上述准备好的基础之上,可以在主循环里加入如下所示的状态转移逻辑:
```c
while(1){
if(last_button_state != button_state){
if(button_state == 0 && press_duration >= LONG_PRESS_THRESHOLD){
// 长按时执行的动作
Do_LongPress_Action();
}else if(click_count==DOUBLE_CLICK_COUNT){
// 双击时执行的动作
Do_DoubleClick_Action();
click_count=0;
}else{
// 单击时执行的动作
Do_SingleClick_Action();
}
delay_ms(DEBOUNCE_DELAY); // 去抖延迟
last_button_state = button_state;
press_duration = 0;
click_count = 0;
}else if(button_state == 1){
press_duration += SYSTEM_TICK_INTERVAL_MS;
Delay(SYSTEM_TICK_INTERVAL_MS);
}
}
```
这里假设已经存在了一个全局周期性的延时函数`delay_ms()`,它负责提供必要的等待时间给去抖处理过程以及其他需要的时间测量功能。同时还需要设定好两个重要的阈值常量LONG_PRESS_THRESHOLD 和 DOUBLE_CLICK_COUNT 来分别表示多长时间算作长按以及几次点击构成双击。
阅读全文
相关推荐


















