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

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

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

下面是具体实现方式分享

一、按键

#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) // 长按
    {
    
    }
}
相关推荐
LDR0064 小时前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
✎ ﹏梦醒͜ღ҉繁华落℘5 小时前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
Luminous.5 小时前
C语言--day30
c语言·开发语言
玖玥拾6 小时前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
謓泽6 小时前
C语言不是语法,是通往机器的地图。
c语言·开发语言
不会C语言的男孩6 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
zd8451015006 小时前
RS485 总线详解
单片机·嵌入式硬件
2601_951643887 小时前
C语言长文整理,关键字和数据类型
c语言·数据类型·关键字·嵌入式开发·格式化输出
m0_5474866610 小时前
《C#语言程序设计与实践》 全套PPT课件
c语言·c#·c语言程序设计
✎ ﹏梦醒͜ღ҉繁华落℘10 小时前
编程基础 --高内聚,低耦合
c语言·单片机