huaruolong 发表于 2025-3-11 14:04:28

还不错,这适用于单独工作的按键,如果有多个工作似乎不实用,比如如果有称重模块,计数模块等等,那个延时函数就是个问题。

wszjw2 发表于 2025-3-11 16:40:48

Ayb_ice 发表于 2025-3-10 08:46
中断里还死等

中断只开机长按使用,应该没事吧

wszjw2 发表于 2025-3-11 16:41:37

huaruolong 发表于 2025-3-11 14:04
还不错,这适用于单独工作的按键,如果有多个工作似乎不实用,比如如果有称重模块,计数模块等等,那个延时 ...

多个模块就需要用定时器了,先做个最基础的起来,后面可以再加

Ayb_ice 发表于 2025-3-11 17:20:30

wszjw2 发表于 2025-3-11 16:40
中断只开机长按使用,应该没事吧

这样还好

手机刷机菜鸟 发表于 2025-3-11 23:44:34

谢谢分享

huaruolong 发表于 2025-3-12 07:07:05

wszjw2 发表于 2025-3-11 16:41
多个模块就需要用定时器了,先做个最基础的起来,后面可以再加

谢谢分享,静等楼主更好的模块。

tianjing818 发表于 2025-3-12 07:24:50

{:qiang:}

wszjw2 发表于 2025-3-19 17:12:30

这段程序测试感觉已经完成了,但是为什么把这段程序封装成BUTTON.C之后让main调用它就不稳定,会出现双击识别不了,关机后得多次长按才行


#include <STC8H.H>
#include <intrins.h>
// 硬件配置
sbit KEY_PIN = P3^2;      // 按键接P3.2
sbit LIGHT=P1^0;
//
typedef         unsigned char        u8;
typedef         unsigned int        u16;
typedef         unsigned long        u32;

// 宏定义
#define DEBOUNCE_MS   20       // 消抖时间20ms
#define DOUBLE_PRESS    300      // 双击间隔300ms
#define LONG_PRESS   10000
#define MAIN_LOOP_CYCLE 10       // 主循环周期10ms
#define MAIN_Fosc                24000000L        //定义主时钟

// 全局变量
static u8 key_event = 0;                // 按键事件(1=单击,2=双击)
static u8 key_state = 0;                // 按键状态机
static u8 power_flag=0;
static u8 wake_flag=0;
u8 mode=0;
void power_off();

voiddelay_ms(u16 ms)
{
   u16 i;
       do
       {
               i = MAIN_Fosc / 10000;
                while(--i)        ;
   }while(--ms);
}
void key_scan() {
    static u16 release_timer = 0;
    static u8click_count = 0;
    static bit last_pin_state = 1;
        static u16 press_counter=0;
    // 状态机处理
    switch(key_state) {
      case 0: // 初始状态
                       
                        if(KEY_PIN == 0 && last_pin_state == 1)// 检测到下降沿
                        {
                delay_ms(DEBOUNCE_MS);
                if(KEY_PIN == 0)
                                { // 确认按下
                  key_state = 1;
                  click_count+=1;
                                        press_counter=0;
                }
            }
            break;

      case 1: // 已按下,等待释放
                        press_counter+=MAIN_LOOP_CYCLE;
                       
            if(KEY_PIN == 1) // 检测到释放
                        {
                delay_ms(DEBOUNCE_MS);
                if(KEY_PIN == 1)
                                        {
                  key_state = 2;
                  release_timer = 0; // 启动双击检测窗口
                }
            }
                        else if(press_counter>LONG_PRESS)
                        {
                                key_event=3;                        //长按
                               
                                click_count=0;
                                key_state=0;
                                press_counter=0;
                        }
            break;

      case 2: // 释放状态,检测双击窗口
            release_timer += MAIN_LOOP_CYCLE;
            
            if(release_timer >= DOUBLE_PRESS) { // 超时处理
                if(click_count == 1) {
                  key_event = 1; // 单击
                }
                click_count = 0;
                key_state = 0;
            } else if(KEY_PIN == 0) { // 再次按下
                delay_ms(DEBOUNCE_MS);
                if(KEY_PIN == 0) {
                  click_count+=1;
                  key_state = 3;
                }
            }
            break;

      case 3: // 第二次按下,等待释放
            if(KEY_PIN == 1) {
                delay_ms(DEBOUNCE_MS);
                if(KEY_PIN == 1) {
                  if(click_count >= 2) {
                        key_event = 2; // 双击
                  }
                  click_count = 0;
                  key_state = 0;
                }
            }
            break;
    }

    last_pin_state = KEY_PIN; // 更新引脚状态
}
void power_off()
{
        power_flag=0;                        //关机标志置0
       
       
        P1IE=0X00;
        P2IE=0X00;
        P3IE=0X04;                                //关闭除P32外的数字输入
       
        IT0=1;
        EX0=1;
        EA=1;                                        //关机时打开外部中断,进行初始化,下降沿触发
       
        PCON |=PD;                                //进入掉电模式
        NOP1();

}
void wake_init()
{
       
        P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
        P3M0 = 0x00; P3M1 = 0x00;//初始化端口,设置为双向口
       
        EX0=0;
        EA=0;                                           //开机时关闭中断
       
        wake_flag=0;                        //唤醒初始化完成,唤醒标志置0
}
/**/
// 主函数
void main()
{
        power_off();                        //上电默认为低功耗模式
       
    while(1)
        {
                key_scan();
                if(power_flag==1)        //
                {
                        if(wake_flag==1)wake_init();

                        P25=0;
               
                        switch(key_event)
                        {
                        case 1:
                                P21=~P21;
                                key_event=0;
                                break;
                        case 2:
                                P24=~P24;
                                key_event=0;
                                break;
                        case 3:                       
                        P25=1;power_off();       
                        key_event=0;
                                break;
                        }
                }
                else{power_off();P25=1;}
                delay_ms(10);
        }
      
}
void exint0() interrupt 0
{
       u16 hold_cnt = 0;// 改为16位计数器
   
    // 长按检测(不依赖延时函数)
    while(KEY_PIN == 0) {
      if(++hold_cnt > (LONG_PRESS/10)) { // 每10ms计数
            power_flag = 1;
                        wake_flag=1;
                        P23=~P23;
            return;
      }
      delay_ms(10);// 仅用于粗略计时
    }
}
页: 1 [2]
查看完整版本: 关于独立按键的单击、双击、长按开关机