【星云 Orbit-F4 开发板】03a. 按键玩法一:独立按键定时中断扫描法 ...

打印 上一主题 下一主题

主题 871|帖子 871|积分 2613

【星云 Orbit-F4 开发板】03b. 按键玩法一:独立按键中断扫描法

概述

本教程基于STM32F407 HAL库,实现模块化的定时中断按键扫描功能,采用去抖动算法与自锁机制确保稳定检测。代码分为按键模块、蜂鸣器模块、定时器模块及主程序,结构清晰,便于移植扩展。

目录结构

  1. Project/  
  2. ├── Inc/  
  3. │   ├── key.h          // 按键模块头文件  
  4. │   ├── beep.h         // 蜂鸣器模块头文件  
  5. │   ├── timer.h        // 定时器模块头文件  
  6. ├── Src/  
  7. │   ├── key.c          // 按键模块实现  
  8. │   ├── beep.c         // 蜂鸣器模块实现  
  9. │   ├── timer.c        // 定时器模块实现  
  10. │   ├── main.c         // 主程序  
复制代码

模块化代码实现

1. 按键模块 (key.h/key.c)

功能:封装按键初始化与扫描逻辑,支持多按键独立检测。
  1. // key.h
  2. #ifndef __KEY_H
  3. #define __KEY_H
  4. #include "stm32f4xx_hal.h"
  5. #define KEY_NUM         2       // 按键数量
  6. #define DEBOUNCE_TIME   20      // 去抖动时间阈值(单位:ms)
  7. // 按键结构体
  8. typedef struct {
  9.     GPIO_TypeDef *port;         // GPIO端口
  10.     uint16_t pin;               // GPIO引脚
  11.     uint8_t is_pressed;         // 当前按键状态(1:按下, 0:释放)
  12.     uint8_t lock;               // 自锁标志
  13.     uint16_t debounce_cnt;      // 去抖动计数器
  14. } Key_TypeDef;
  15. // 全局按键数组声明(在key.c中定义)
  16. extern Key_TypeDef keys[KEY_NUM];
  17. void KEY_Init(void);            // 按键初始化
  18. void KEY_Scan(void);            // 按键扫描(需在定时中断中调用)
  19. #endif
复制代码
  1. // key.c
  2. #include "key.h"
  3. // 定义两个按键的硬件配置
  4. Key_TypeDef keys[KEY_NUM] = {
  5.     {GPIOA, GPIO_PIN_0, 0, 0, 0}, // Key1: PA0(下拉输入)
  6.     {GPIOA, GPIO_PIN_1, 0, 0, 0}  // Key2: PA1(下拉输入)
  7. };
  8. // 按键初始化
  9. void KEY_Init(void) {
  10.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  11.    
  12.     // 使能GPIOA时钟
  13.     __HAL_RCC_GPIOA_CLK_ENABLE();
  14.    
  15.     // 配置按键引脚为下拉输入
  16.     GPIO_InitStruct.Pin = keys[0].pin | keys[1].pin;
  17.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  18.     GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  19.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  20. }
  21. // 按键扫描函数(需在1ms定时中断中调用)
  22. void KEY_Scan(void) {
  23.     for (uint8_t i = 0; i < KEY_NUM; i++) {
  24.         uint8_t current_state = HAL_GPIO_ReadPin(keys[i].port, keys[i].pin);
  25.         
  26.         if (current_state == GPIO_PIN_SET) { // 检测到高电平(按键按下)
  27.             if (keys[i].lock == 0) {         // 首次检测到按下
  28.                 keys[i].debounce_cnt++;
  29.                 if (keys[i].debounce_cnt >= DEBOUNCE_TIME) {
  30.                     keys[i].is_pressed = 1;  // 标记按键按下
  31.                     keys[i].lock = 1;        // 自锁,防止重复触发
  32.                     keys[i].debounce_cnt = 0;
  33.                 }
  34.             }
  35.         } else { // 按键释放
  36.             keys[i].lock = 0;
  37.             keys[i].debounce_cnt = 0;
  38.             keys[i].is_pressed = 0;         // 清除按下标记
  39.         }
  40.     }
  41. }
复制代码

2. 蜂鸣器模块 (beep.h/beep.c)

功能:控制蜂鸣器鸣叫时间,支持短鸣触发。
  1. // beep.h
  2. #ifndef __BEEP_H
  3. #define __BEEP_H
  4. #include "stm32f4xx_hal.h"
  5. #define BEEP_PORT       GPIOB
  6. #define BEEP_PIN        GPIO_PIN_0
  7. #define BEEP_SHORT_MS   40      // 短鸣持续时间(ms)
  8. void BEEP_Init(void);           // 蜂鸣器初始化
  9. void BEEP_Trigger(uint16_t duration_ms);  // 触发蜂鸣器
  10. #endif
复制代码
  1. // beep.c
  2. #include "beep.h"
  3. static volatile uint16_t beep_counter = 0;  // 蜂鸣器计时器
  4. // 蜂鸣器初始化
  5. void BEEP_Init(void) {
  6.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  7.    
  8.     // 使能GPIOB时钟
  9.     __HAL_RCC_GPIOB_CLK_ENABLE();
  10.    
  11.     // 配置蜂鸣器引脚为推挽输出
  12.     GPIO_InitStruct.Pin = BEEP_PIN;
  13.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  14.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  15.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  16.     HAL_GPIO_Init(BEEP_PORT, &GPIO_InitStruct);
  17.    
  18.     HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_RESET); // 初始关闭
  19. }
  20. // 触发蜂鸣器(duration_ms: 持续时间)
  21. void BEEP_Trigger(uint16_t duration_ms) {
  22.     beep_counter = duration_ms;
  23.     HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_SET); // 启动蜂鸣器
  24. }
  25. // 更新蜂鸣器状态(需在1ms定时中断中调用)
  26. void BEEP_Update(void) {
  27.     if (beep_counter > 0) {
  28.         beep_counter--;
  29.         if (beep_counter == 0) {
  30.             HAL_GPIO_WritePin(BEEP_PORT, BEEP_PIN, GPIO_PIN_RESET); // 关闭
  31.         }
  32.     }
  33. }
复制代码

3. 定时器模块 (timer.h/timer.c)

功能:配置TIM3定时器,提供1ms中断用于按键扫描与蜂鸣器控制。
  1. // timer.h
  2. #ifndef __TIMER_H
  3. #define __TIMER_H
  4. #include "stm32f4xx_hal.h"
  5. void TIMER_Init(void);  // 定时器初始化
  6. #endif
复制代码
  1. // timer.c
  2. #include "timer.h"
  3. #include "key.h"
  4. #include "beep.h"
  5. TIM_HandleTypeDef htim3;
  6. // 定时器初始化
  7. void TIMER_Init(void) {
  8.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  9.     TIM_MasterConfigTypeDef sMasterConfig = {0};
  10.     htim3.Instance = TIM3;
  11.     htim3.Init.Prescaler = 84 - 1;       // 84MHz / 84 = 1MHz
  12.     htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  13.     htim3.Init.Period = 1000 - 1;       // 1ms中断周期 (1MHz / 1000)
  14.     htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  15.     HAL_TIM_Base_Init(&htim3);
  16.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  17.     HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);
  18.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  19.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  20.     HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
  21.     HAL_TIM_Base_Start_IT(&htim3); // 启动定时器中断
  22. }
  23. // 定时器中断回调函数
  24. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  25.     if (htim->Instance == TIM3) {
  26.         KEY_Scan();     // 按键扫描
  27.         BEEP_Update();  // 更新蜂鸣器状态
  28.     }
  29. }
复制代码

4. 主程序 (main.c)

功能:模块初始化与按键服务处理。
  1. #include "main.h"
  2. #include "key.h"
  3. #include "beep.h"
  4. #include "timer.h"
  5. int main(void) {
  6.     HAL_Init();
  7.     KEY_Init();     // 初始化按键
  8.     BEEP_Init();    // 初始化蜂鸣器
  9.     TIMER_Init();   // 初始化定时器
  10.     while (1) {
  11.         // 检测按键触发
  12.         for (uint8_t i = 0; i < KEY_NUM; i++) {
  13.             if (keys[i].is_pressed) {
  14.                 BEEP_Trigger(BEEP_SHORT_MS); // 触发蜂鸣器
  15.                 keys[i].is_pressed = 0;      // 清除按键状态
  16.             }
  17.         }
  18.     }
  19. }
复制代码

逻辑详解


  • 模块化筹划

    • 按键模块:封装GPIO配置与扫描逻辑,支持多按键独立检测。
    • 蜂鸣器模块:提供触发接口与状态更新,分离控制逻辑。
    • 定时器模块:统一管理中断,确保1ms精准调度。

  • 去抖动机制

    • 在KEY_Scan()中,通过debounce_cnt累计中断次数,超过阈值后标志按键按下,避免抖动误触发。

  • 自锁标志

    • 按键按下后设置lock标志,防止长按重复触发;释放后自动复位。

  • 蜂鸣器控制

    • 触发时设置beep_counter,定时中断中递减至0后关闭,确保鸣叫时间正确。


总结

本代码通过模块化筹划,将按键扫描、蜂鸣器控制与定时器管理分离,提升了代码可读性与可维护性。采用HAL库标准接口,便于移植到其他STM32系列。实际应用中,可根据需求调整按键数目、去抖动时间及硬件配置。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

知者何南

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表