【星云 Orbit-F4 开发板】03b. 按键玩法一:独立按键中断扫描法
概述
本教程基于STM32F407 HAL库,实现模块化的定时中断按键扫描功能,采用去抖动算法与自锁机制确保稳定检测。代码分为按键模块、蜂鸣器模块、定时器模块及主程序,结构清晰,便于移植扩展。
目录结构
- Project/
- ├── Inc/
- │ ├── key.h // 按键模块头文件
- │ ├── beep.h // 蜂鸣器模块头文件
- │ ├── timer.h // 定时器模块头文件
- ├── Src/
- │ ├── key.c // 按键模块实现
- │ ├── beep.c // 蜂鸣器模块实现
- │ ├── timer.c // 定时器模块实现
- │ ├── main.c // 主程序
复制代码 模块化代码实现
1. 按键模块 (key.h/key.c)
功能:封装按键初始化与扫描逻辑,支持多按键独立检测。
- // key.h
- #ifndef __KEY_H
- #define __KEY_H
- #include "stm32f4xx_hal.h"
- #define KEY_NUM 2 // 按键数量
- #define DEBOUNCE_TIME 20 // 去抖动时间阈值(单位:ms)
- // 按键结构体
- typedef struct {
- GPIO_TypeDef *port; // GPIO端口
- uint16_t pin; // GPIO引脚
- uint8_t is_pressed; // 当前按键状态(1:按下, 0:释放)
- uint8_t lock; // 自锁标志
- uint16_t debounce_cnt; // 去抖动计数器
- } Key_TypeDef;
- // 全局按键数组声明(在key.c中定义)
- extern Key_TypeDef keys[KEY_NUM];
- void KEY_Init(void); // 按键初始化
- void KEY_Scan(void); // 按键扫描(需在定时中断中调用)
- #endif
复制代码- // key.c
- #include "key.h"
- // 定义两个按键的硬件配置
- Key_TypeDef keys[KEY_NUM] = {
- {GPIOA, GPIO_PIN_0, 0, 0, 0}, // Key1: PA0(下拉输入)
- {GPIOA, GPIO_PIN_1, 0, 0, 0} // Key2: PA1(下拉输入)
- };
- // 按键初始化
- void KEY_Init(void) {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- // 使能GPIOA时钟
- __HAL_RCC_GPIOA_CLK_ENABLE();
-
- // 配置按键引脚为下拉输入
- GPIO_InitStruct.Pin = keys[0].pin | keys[1].pin;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_PULLDOWN;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- }
- // 按键扫描函数(需在1ms定时中断中调用)
- void KEY_Scan(void) {
- for (uint8_t i = 0; i < KEY_NUM; i++) {
- uint8_t current_state = HAL_GPIO_ReadPin(keys[i].port, keys[i].pin);
-
- if (current_state == GPIO_PIN_SET) { // 检测到高电平(按键按下)
- if (keys[i].lock == 0) { // 首次检测到按下
- keys[i].debounce_cnt++;
- if (keys[i].debounce_cnt >= DEBOUNCE_TIME) {
- keys[i].is_pressed = 1; // 标记按键按下
- keys[i].lock = 1; // 自锁,防止重复触发
- keys[i].debounce_cnt = 0;
- }
- }
- } else { // 按键释放
- keys[i].lock = 0;
- keys[i].debounce_cnt = 0;
- keys[i].is_pressed = 0; // 清除按下标记
- }
- }
- }
复制代码 2. 蜂鸣器模块 (beep.h/beep.c)
功能:控制蜂鸣器鸣叫时间,支持短鸣触发。
- // beep.h
- #ifndef __BEEP_H
- #define __BEEP_H
- #include "stm32f4xx_hal.h"
- #define BEEP_PORT GPIOB
- #define BEEP_PIN GPIO_PIN_0
- #define BEEP_SHORT_MS 40 // 短鸣持续时间(ms)
- void BEEP_Init(void); // 蜂鸣器初始化
- void BEEP_Trigger(uint16_t duration_ms); // 触发蜂鸣器
- #endif
复制代码- // beep.c
- #include "beep.h"
- static volatile uint16_t beep_counter = 0; // 蜂鸣器计时器
- // 蜂鸣器初始化
- void BEEP_Init(void) {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- // 使能GPIOB时钟
- __HAL_RCC_GPIOB_CLK_ENABLE();
-
- // 配置蜂鸣器引脚为推挽输出
- GPIO_InitStruct.Pin = BEEP_PIN;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(BEEP_PORT, &GPIO_InitStruct);
-
- HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_RESET); // 初始关闭
- }
- // 触发蜂鸣器(duration_ms: 持续时间)
- void BEEP_Trigger(uint16_t duration_ms) {
- beep_counter = duration_ms;
- HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_SET); // 启动蜂鸣器
- }
- // 更新蜂鸣器状态(需在1ms定时中断中调用)
- void BEEP_Update(void) {
- if (beep_counter > 0) {
- beep_counter--;
- if (beep_counter == 0) {
- HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_RESET); // 关闭
- }
- }
- }
复制代码 3. 定时器模块 (timer.h/timer.c)
功能:配置TIM3定时器,提供1ms中断用于按键扫描与蜂鸣器控制。
- // timer.h
- #ifndef __TIMER_H
- #define __TIMER_H
- #include "stm32f4xx_hal.h"
- void TIMER_Init(void); // 定时器初始化
- #endif
复制代码- // timer.c
- #include "timer.h"
- #include "key.h"
- #include "beep.h"
- TIM_HandleTypeDef htim3;
- // 定时器初始化
- void TIMER_Init(void) {
- TIM_ClockConfigTypeDef sClockSourceConfig = {0};
- TIM_MasterConfigTypeDef sMasterConfig = {0};
- htim3.Instance = TIM3;
- htim3.Init.Prescaler = 84 - 1; // 84MHz / 84 = 1MHz
- htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim3.Init.Period = 1000 - 1; // 1ms中断周期 (1MHz / 1000)
- htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- HAL_TIM_Base_Init(&htim3);
- sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
- HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
- HAL_TIM_Base_Start_IT(&htim3); // 启动定时器中断
- }
- // 定时器中断回调函数
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
- if (htim->Instance == TIM3) {
- KEY_Scan(); // 按键扫描
- BEEP_Update(); // 更新蜂鸣器状态
- }
- }
复制代码 4. 主程序 (main.c)
功能:模块初始化与按键服务处理。
- #include "main.h"
- #include "key.h"
- #include "beep.h"
- #include "timer.h"
- int main(void) {
- HAL_Init();
- KEY_Init(); // 初始化按键
- BEEP_Init(); // 初始化蜂鸣器
- TIMER_Init(); // 初始化定时器
- while (1) {
- // 检测按键触发
- for (uint8_t i = 0; i < KEY_NUM; i++) {
- if (keys[i].is_pressed) {
- BEEP_Trigger(BEEP_SHORT_MS); // 触发蜂鸣器
- keys[i].is_pressed = 0; // 清除按键状态
- }
- }
- }
- }
复制代码 逻辑详解
- 模块化筹划
- 按键模块:封装GPIO配置与扫描逻辑,支持多按键独立检测。
- 蜂鸣器模块:提供触发接口与状态更新,分离控制逻辑。
- 定时器模块:统一管理中断,确保1ms精准调度。
- 去抖动机制
- 在KEY_Scan()中,通过debounce_cnt累计中断次数,超过阈值后标志按键按下,避免抖动误触发。
- 自锁标志
- 按键按下后设置lock标志,防止长按重复触发;释放后自动复位。
- 蜂鸣器控制
- 触发时设置beep_counter,定时中断中递减至0后关闭,确保鸣叫时间正确。
总结
本代码通过模块化筹划,将按键扫描、蜂鸣器控制与定时器管理分离,提升了代码可读性与可维护性。采用HAL库标准接口,便于移植到其他STM32系列。实际应用中,可根据需求调整按键数目、去抖动时间及硬件配置。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |