单片机按键检测与长短按识别实现

最近一个项目中,需要实现单键多功能控制:

单击执行某个动作; 双击切换模式; 长按执行开关机。

下面是具体实现方式分享

一、按键

#define KEY_ONOFF PORTA0 //此IO内部开启上拉

二、按键结构体定义

按键设计了一个结构体 `KEY_HandleTypeDef`, 用来存储每个按键的各种状态信息:

typedef struct

{

u8 state; // 当前按键状态(0=松开,1=按下)

u8 pressed_ct; // 短按计数

u16 long_press_ct; // 长按计数

u8 release_time; // 松开延时检测

u8 click; // 按键事件标志:1=单击,2=双击,3=长按

u8 longpress_flag; // 长按触发标志(防止重复触发)

u16 longpress_cnt; // 长按连续动作计数器

} KEY_HandleTypeDef;

KEY_HandleTypeDef key0 = {0};

注:可支持后续拓展更多,比如3击,4击,或者长按连发、多键组合等。

三、核心扫描函数 k0_scan()

该函数建议每 10ms 调用一次,负责检测按键按下/松开状态,并进行计数和事件识别。

复制代码
void k0_scan(void)
{
    // ① 按下检测
    if (KEY_ONOFF == 0)
    {
        if (key0.state == 0)
        {
            key0.state = 1;
            if (key0.pressed_ct < 100) key0.pressed_ct++;
            key0.release_time = 30; // 释放延时(30*10ms=300ms)
        }

        // 长按计数
        if (key0.long_press_ct < 301) key0.long_press_ct++;

        // 超过3秒判定为长按
        if (key0.long_press_ct == 300)
        {
            key0.long_press_ct = 300;
            key0.click = 3;  // 标记长按事件
            key0.pressed_ct = 0;
            key0.longpress_cnt = 0;

            if (!key0.longpress_flag)
            {
                key0.longpress_flag = 1;
                //长按
            }
        }
    }
    // ② 松开检测
    else
    {
        key0.state = 0;
        key0.long_press_ct = 0;
        if (key0.release_time) key0.release_time--;
    }

    // ③ 松开后判断单击/双击
    if (key0.release_time == 0)
    {
        if (!key0.longpress_flag)
        {
            if (key0.pressed_ct == 1)
            {
                key0.click = 1; // 单击
                key0.pressed_ct = 0;
            }
            else if (key0.pressed_ct == 2)
            {
                key0.click = 2; // 双击
                key0.pressed_ct = 0;
            }
        }
        else
        {
            // 长按松开后清除标志
            key0.longpress_flag = 0;
            key0.pressed_ct = 0;
            key0.click = 0;
            key0.longpress_cnt = 0;
        }
    }
}

四、逻辑说明

功能 条件 判定逻辑 执行动作
单击 按下并快速松开一次 在 300ms 内没有再次按下 key0.click = 1
双击 在第一次松开后, 300ms 内再次按下 第二次松开时检测到 `pressed_ct == 2 key0.cl``ick = 2
长按 按住时间 ≥ 3 秒 long_press_ct` 计数达到 300(10ms × 300 = 3s) key0.click = 3,触发开关机逻辑

五、事件处理函数

在主循环中调用 KEY_handle() 进行按键事件分发处理:

复制代码
void KEY_handle(void)
{
    // 单击事件
    if (key0.click == 1)
    {
        key0.click = 0;
        // 执行单击动作
        // 比如:切换模式 / 调节亮度 / 唤醒设备 等
    }
    if (key0.click == 2) // 双击
    {

    }

    if (key0.click == 3) // 长按
    {
    
    }
}
相关推荐
坚持编程的菜鸟4 小时前
LeetCode每日一题——螺旋矩阵
c语言·算法·leetcode·矩阵
Zaki_gd4 小时前
GPIO 引脚速度(Speed)
单片机·嵌入式硬件
武文斌774 小时前
复习总结最终版:单片机
linux·单片机·嵌入式硬件·学习
机器视觉知识推荐、就业指导5 小时前
C语言中的预编译是什么?何时需要预编译?
c语言·开发语言
xiaofei5580085 小时前
CAN 波特率的几个参数说明和计算方式(以STM32为例)
单片机·嵌入式硬件·汽车
应用市场5 小时前
STM32运行原理深度解析:从软件到硬件的神奇之旅
stm32·单片机·嵌入式硬件
点灯小铭5 小时前
基于单片机的64位多模式流水灯控制系统设计
单片机·嵌入式硬件·毕业设计·课程设计
Winner13007 小时前
STM32 读取引脚状态 -按键输入
stm32·单片机·嵌入式硬件
点灯小铭7 小时前
基于单片机的PID调节脉动真空灭菌器上位机远程监控设计
数据库·单片机·嵌入式硬件·毕业设计·课程设计