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

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

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

下面是具体实现方式分享

一、按键

#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) // 长按
    {
    
    }
}
相关推荐
xingke1 小时前
C 语言多文件编程:(一)头文件、extern、编译链接
c语言·开发语言·多文件
ACP广源盛139246256732 小时前
IX8024 PCIe4.0 交换芯片@ACP# RK3588:嵌入式 AI PC 标准化扩展方案
大数据·人工智能·分布式·单片机·嵌入式硬件
淘晶驰AK2 小时前
组态屏上车,三分钟解决卡线
单片机·嵌入式硬件
wuyk5552 小时前
38.什么是C语言?从语法到工程落地的工程师视角解读
c语言·开发语言·stm32·单片机·mcu·51单片机
ACP广源盛139246256736 小时前
IX9104 PCIe5.0 交换芯片@ACP#国产高端 AI PC 全搭配方案
大数据·人工智能·分布式·单片机·嵌入式硬件
某不知名網友6 小时前
C/C++动态内存管理,智能指针及RAlI思想。
java·c语言·c++
一杯奶茶¥6 小时前
c语言程序设计大学期末考试考研知识点重点笔记题库复习资料C语言重点考点题库资料合集
c语言·笔记·考研·c语言程序设计·c语言笔记
张海森-1688207 小时前
两个char 类型变量,如何相互赋值
单片机
SUNNYSPY0017 小时前
75N120-ASEMI户用储能PCS专用75N120
单片机
piaoyiren8 小时前
单片机串口控制单路共阳极数码管
单片机·嵌入式硬件·51单片机