当前位置: 首页 > news >正文

单片机按键示例功能

一、简介

1.1 功能需求

  • 短按:按键按下时间 < 1s,触发一次短按事件;
  • 长按:按键按下时间 ≥ 1s,触发一次长按事件;
  • 3秒内统计按键次数:在3秒内统计短按次数(长按不计入)。

1.2 软件设计思路

  • 使用 状态机 检测按键状态(按下、释放、长按、短按);
  • 使用 滴答定时器 记录按下时间;
  • 使用 软件定时器 实现3秒统计窗口;

二、代码

2.1 按键驱动头文件 key.h

#ifndef __KEY_H
#define __KEY_H#include "main.h"          // HAL 头文件,提供 GPIO 口与 HAL_GetTick
#include <stdbool.h>/* 用户配置:引脚、电平、长按阈值、统计窗口时长 */
/* BUTTON_USER定义 */
#define RCC_BUTTON_USER_CLK       RCC_PERIPH_CLK_GPIOB
#define BUTTON_USER_PORT          GPIOB
#define BUTTON_USER_PIN           GPIO_PIN_10
#define KEY_PRESSED_LEVEL   	  0        		// 0 = 低电平为按下
#define KEY_LONG_MS         	  1000     		// ≥1 s 算长按
#define KEY_STAT_WINDOW_MS  	  3000     		// 3 s 统计窗口/* 状态机状态 */
typedef enum {KEY_STA_IDLE = 0,KEY_STA_PRESSED,KEY_STA_SHORT,KEY_STA_LONG
} KeyStateEnum;/* 按键结构体 */
typedef struct {/* 底层硬件信息 */GPIO_t        *port;uint16_t      pin;uint8_t       pressedLevel;   // 按下时的电平值uint32_t      longThd;        // 长按阈值 msuint32_t      winThd;         // 统计窗口 ms/* 运行期状态 */KeyStateEnum  state;uint32_t      tPress;         // 本次按下时刻uint32_t      tRelease;       // 本次释放时刻uint8_t       shortCnt;       // 窗口内短按计数uint32_t      winStart;       // 统计窗口起始时刻bool          winActive;      // 统计窗口是否打开
} Key_t;extern Key_t gKey;void KEY_Init(Key_t *k);
void KEY_Scan(Key_t *k);
void KEY_Process(Key_t *k);#endif

2.2 按键驱动源文件 key.c


#include "key.h"
#include <stdio.h>/**
* @brief  EXTI初始化
* @retval 无
*/
void KeyExtiInit(void)
{std_exti_init_t exti_init_config = {0};std_gpio_init_t button_init_config = {0};    /* 使能BUTTON_USER对应的GPIO时钟 */std_rcc_gpio_clk_enable(RCC_BUTTON_USER_CLK);/* 配置BUTTON_USER的GPIO */button_init_config.pin = BUTTON_USER_PIN;button_init_config.mode = GPIO_MODE_INPUT;button_init_config.pull = GPIO_PULLUP;std_gpio_init(BUTTON_USER_PORT, &button_init_config);/* 配置BUTTON_USER的EXTI */exti_init_config.line_id = BUTTON_USER_EXTI_LINE;exti_init_config.mode = EXTI_MODE_INTERRUPT;exti_init_config.trigger = EXTI_TRIGGER_FALLING;	exti_init_config.gpio_id = BUTTON_USER_EXTI_PORT;std_exti_init(&exti_init_config);/* 配置中断优先级 */NVIC_SetPriority(EXTI4_15_IRQn, NVIC_PRIO_0); /* 使能中断 */NVIC_EnableIRQ(EXTI4_15_IRQn);
}Key_t gKey;/* 读引脚,返回 true = 当前处于按下状态 */
static bool KEY_Read(const Key_t *k) {return std_gpio_get_input_pin(k->port, k->pin) == k->pressedLevel;
}/* 初始化,把用户配置填进去 */
void KEY_Init(Key_t *k) {k->port        = BUTTON_USER_PORT;k->pin         = BUTTON_USER_PIN;k->pressedLevel= KEY_PRESSED_LEVEL;      // 0 = 低电平为按下k->longThd     = KEY_LONG_MS;            // ≥1 s 算长按k->winThd      = KEY_STAT_WINDOW_MS;     // 3 s 统计窗口k->state       = KEY_STA_IDLE;k->tPress      = 0;                      // 本次按下时刻k->tRelease    = 0;                      // 本次释放时刻k->shortCnt    = 0;                      // 窗口内短按计数k->winStart    = 0;                      // 统计窗口起始时刻k->winActive   = false;                  // 统计窗口是否打开
}/* 状态机扫描,1 ms 周期调用 */
void KEY_Scan(Key_t *k) 
{static bool lastRaw = false;bool        raw     = KEY_Read(k);uint32_t    now     = osKernelGetTickCount();switch (k->state) {case KEY_STA_IDLE:if (raw && !lastRaw)           // 刚按下{          k->tPress = now;k->state  = KEY_STA_PRESSED;}break;case KEY_STA_PRESSED:             // 释放if (!raw) {                     k->tRelease = now;if ((k->tRelease - k->tPress) < k->longThd)k->state = KEY_STA_SHORT;elsek->state = KEY_STA_IDLE;} else if ((now - k->tPress) >= k->longThd) {k->state = KEY_STA_LONG;}break;case KEY_STA_SHORT:/* 打开或延续统计窗口 */if (!k->winActive) {k->winActive = true;k->winStart  = now;k->shortCnt  = 1;} else {k->shortCnt++;}k->state = KEY_STA_IDLE;break;case KEY_STA_LONG:/* 长按事件触发,不计入统计 */k->state = KEY_STA_IDLE;break;}lastRaw = raw;
}/* 业务层:3 s 到点后打印统计值,并重置窗口 */
void KEY_Process(Key_t *k) 
{if (!k->winActive) return;uint32_t now = osKernelGetTickCount();if ((now - k->winStart) >= k->winThd) {printf("3 s 内短按次数:%d\n", k->shortCnt);k->state       = KEY_STA_IDLE;k->tPress      = 0;                      // 本次按下时刻k->tRelease    = 0;                      // 本次释放时刻k->shortCnt    = 0;                      // 窗口内短按计数k->winStart    = 0;                      // 统计窗口起始时刻k->winActive   = false;                  // 统计窗口是否打开		if(system_info.flags.key_isr_flag == 1){if(KeyIsPressed() == false){	printf("KeyIsPressed-2 \r\n");system_info.flags.key_isr_flag = 0;}}		}
}

2.3 主循环中调用

void AppTaskStart(void *argument)
{const uint16_t usFrequency = 10; /* 延迟周期 */uint32_t tick;/* 获取当前时间 */tick = osKernelGetTickCount(); KEY_Init(&gKey);while(1){KEY_Scan(&gKey);     // 10 ms 周期KEY_Process(&gKey);/* 相对延迟 */tick += usFrequency;                          osDelayUntil(tick);}
}

2.4 示例输出(串口):

在这里插入图片描述


文章转载自:

http://RbxICuIX.mmddw.cn
http://GX2pckNG.mmddw.cn
http://fQ5SiJNG.mmddw.cn
http://UsxzxmWr.mmddw.cn
http://WlQd06d7.mmddw.cn
http://f5fwlSq3.mmddw.cn
http://1GPJjRJX.mmddw.cn
http://VeQ2wG6E.mmddw.cn
http://dD1zWMUO.mmddw.cn
http://cbfPKZWu.mmddw.cn
http://n6hVx6QJ.mmddw.cn
http://3UKbH7hE.mmddw.cn
http://n4IpGIbf.mmddw.cn
http://t7SWVDfp.mmddw.cn
http://g3BoCvJu.mmddw.cn
http://5pbAzK2j.mmddw.cn
http://KBlYqg68.mmddw.cn
http://rqvloKNV.mmddw.cn
http://ZMk0yXSY.mmddw.cn
http://pR6w8naA.mmddw.cn
http://PVRjJ5KT.mmddw.cn
http://ok4NkgJw.mmddw.cn
http://94BW4Nft.mmddw.cn
http://liipbQrt.mmddw.cn
http://OfLE5S5b.mmddw.cn
http://iK7bfd4t.mmddw.cn
http://TDXPE76S.mmddw.cn
http://dSBso1yv.mmddw.cn
http://UknEJvck.mmddw.cn
http://pf6H4H0c.mmddw.cn
http://www.dtcms.com/a/374097.html

相关文章:

  • Enable FIPS in ubuntu (by quqi99)
  • OpenAI的开源王牌:gpt-oss上手指南与深度解析
  • 使用nvidia-ml-py监控与管理GPU资源
  • 鹧鸪云光储流程系统全新升级:视频指引与分阶段模块使用指南
  • qx-13 开发数据服务总线
  • GD32入门到实战44--LVGL使用外部SRAM
  • 硬件驱动芯片——I.MX6ULL芯片(1)
  • MV190E0M-N10 工业广视角液晶模组技术白皮书
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年9月8日第173弹
  • 机器视觉的手机柔性屏贴合应用
  • 【PyTorch】图像二分类-部署
  • 纵向循环缓慢滚动图片
  • 项目日记 -日志系统 -明确目标、规划模块并完成项目文档
  • 【C++上岸】C++常见面试题目--网络篇(第二十二期)
  • 数据治理系列(一):数据治理的整体框架与发展趋势
  • 【LeetCode 每日一题】1504. 统计全 1 子矩形
  • FastGPT源码解析 Agent知识库文本资料处理详解和代码分析
  • php 实现 导入excel 带图片导入
  • JP4-7-MyLesson后台前端(五)
  • 【系统分析师】第17章-关键技术:嵌入式系统分析与设计(核心总结)
  • Centos9安装rocketmq
  • Docker | 一种使用 docker-compose 命令将 YAML 定义的配置文件导入到 Docker 的方法
  • 编译器构造:模拟器,汇编与反汇编
  • 自由学习记录(96)
  • Cy5-Tyramide, Cyanine 5 Tyramide;1431148-26-3
  • JMeter接口测试全流程解析
  • ARM处理器的小常识
  • Go语言极速入门与精要指南从零到精通的系统化学习路径
  • RK3576 android14 usb_audio_policy_configuration.xml解析
  • 本地安装部署svn服务,并设置外网远程访问内网svn,含路由器转发和端口映射工具教程