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

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

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

下面是具体实现方式分享

一、按键

#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) // 长按
    {
    
    }
}
相关推荐
祈安_2 天前
C语言内存函数
c语言·后端
norlan_jame4 天前
C-PHY与D-PHY差异
c语言·开发语言
czy87874754 天前
除了结构体之外,C语言中还有哪些其他方式可以模拟C++的面向对象编程特性
c语言
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
m0_531237174 天前
C语言-数组练习进阶
c语言·开发语言·算法
Lester_11014 天前
STM32霍尔传感器输入口设置为复用功能输入口时,还能用GPIO函数直接读取IO的状态吗
stm32·单片机·嵌入式硬件·电机控制
三佛科技-187366133974 天前
120W小体积碳化硅电源方案(LP8841SC极简方案12V10A/24V5A输出)
单片机·嵌入式硬件
z20348315204 天前
STM32F103系列单片机定时器介绍(二)
stm32·单片机·嵌入式硬件
Z9fish4 天前
sse哈工大C语言编程练习23
c语言·数据结构·算法
代码无bug抓狂人4 天前
C语言之单词方阵——深搜(很好的深搜例题)
c语言·开发语言·算法·深度优先