找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 801|回复: 5
收起左侧

STC32G12K128单片机使用P3.2/INT0,外部中断当按键怎么实现进入掉电模式后长按开机?

[复制链接]
ID:1153575 发表于 2025-10-9 10:25 | 显示全部楼层 |阅读模式
一个锂电产品,关机后要进入低功耗,用INT0(P3.2)引脚实现按键唤醒,现在情况是这样,我写的程序 在关机后能进入低功耗模式。但是在长按按键唤醒开机时出现下面两种情况
1.按键按下直接就开机了,没有经过检测长按
2.按键需要按两次,第一次按下唤醒,第二次按下可以实现长按开机
所以我想问问各位,怎么实现在 进入低功耗模式后,实现长按开机,麻烦各位给点思路
下面是我的代码
void INT0_Isr(void) interrupt 0
{

    delay_ms(20); // 消抖

}

void main() {
        
    bit key_flag = 0;  // 按键状态标志位
                u16        j;
        
                EAXFR = 1;                         // 使能访问XFR
                CKCON = 0x00;         // 设置外部数据总线速度为最快
                WTST = 0x00;                // 设置程序代码等待参数,0等待时钟,速度最快
        
    GPIO_Init();       // 初始化IO
                Timer0_Init();     // 初始化定时器(24MHz配置)
                ADC_config();                                //初始化ADC0
                PWM_config();                                
                Timer_config();
                TurnOffAllLights();//上电初始化关闭所有输出
        
                IT0 = 1;                                                                                // INT0下降沿中断
                EX0 = 1;                                                                                // 使能外部中断0
                EA = 1;                                                                                        // 使能EA总中断
        
          system_state = SYSTEM_OFF; // 假设上电默认是关机状态
    while(1) {
                        
                Check_USB();                        // 检查USB状态

                j = Get_ADCResult(0);                //读取ADC0检测的电压值               
                keyvalue = key_multi();                //读取键值
               
                        
                if(j >= 3500)   //只有当P1.0/ADC0,测到有电压,电机才会工作
                          {
                                        MOTO_PLAY();                        
                                }else{
                                        PWM8P_OUT_DIS();                        
                                }
                                                               
                        if(keyvalue != KEY_STATE_0)
                                {
                                         if (usb_state == USB_CONNECTED) {              
                beep_(1);  // 短鸣提示USB插入,禁止操作
                delay_ms(100);
            }
                                        else if(system_state == SYSTEM_OFF && keyvalue == Key1_Long_Click){
                                                                        system_state = SYSTEM_ON;  // 切换到开机状态
                                                                        press_count = 1;
                                                                        Timer3_Run(1);Timer0_Run(1);                                                         
                                                                        Display(); MODE_PLAY();UpdateTimer();
                                                                        LED = 0;
                                                                        beep_(2);                                                                                                                                
                                                                        timer_count = 0;           // 重置计时器
                                                                        timer_running = 1;         // 开始计时                                
                                } else if(system_state == SYSTEM_ON){
                                                                        if(keyvalue == Key1_Single_Click){
                                                                        press_count++;          // 模式计数加1
                                                                        if (press_count > 7) press_count = 1;        
                                                                        Display();         MODE_PLAY();             // 更新显示        
                                                                        beep_(1);                // 播放短按提示音                                                                                                                                
                                }else if(keyvalue == Key1_Long_Click){
                                                                        system_state = SYSTEM_OFF;  // 切换到关机状态
                                                                        TurnOffAllLights();        // 关闭所有灯光                                                                        
                                                                        beep_(3);                   // 播放关机音效                                                        
                                                                        timer_running = 0;          // 停止计时
                     IT0 = 1;
                  EX0 = 1;
                  EA = 1;
                        PD = 1;                                // 进入低功耗模式-IDLE空式                                                                                                        
                                                        }
                                        }               
                        }
                    UpdateTimer();   // 更新计时器状态
        Display();       // 更新显示(用于处理闪烁)
                                MODE_PLAY();
        delay_ms(1);    // 短暂延时,降低CPU占用
                        
    }
}
回复

使用道具 举报

ID:458247 发表于 2025-10-9 13:05 | 显示全部楼层
增加一个状态,在休眠时,置起一个标志位,然后在中断里面判断该标志位置起,若置起,则进入等待长安状态。在这个状态中,屏幕不显示、指示灯不亮,假装自己还在休眠,一直检测按键是否按下,按下持续2秒后,进入正常状态,并把休眠状态位取消。大概套路就是这样
回复

使用道具 举报

ID:1133081 发表于 2025-10-9 15:05 | 显示全部楼层
这个没有难度。一旦按键按下系统即被唤醒,首先判断长短按,长按即开机,小于长按预设值即算短按,再次进入低功耗睡眠。呈现的功能就是睡眠中短按无效,长按开机。实际短按也有效,只不过察觉不到。
回复

使用道具 举报

ID:1133081 发表于 2025-10-9 15:16 | 显示全部楼层
给你一个示例,稍改一下即可满足需求
  1. //一键开/关机(掉电唤醒)
  2. //适合STC15/STC8系列,测试平台 TX-1C 开发板
  3. #include <STC8H.H>
  4. #include "intrins.h"
  5. #define uchar unsigned char
  6. #define uint unsigned int

  7. sbit key  = P3^2;//S14
  8. sbit GND  = P3^4;//矩阵键盘模拟接地

  9. uchar Temp;
  10. uchar Key_value; //键值
  11. uint  keyTim;    //按键时长
  12. bit   flag1ms;   //1ms中断标志
  13. bit   on_off;    //开关标志
  14. bit   allow;     //允许关机标志

  15. void Timer0Init(void)//1毫秒@11.0592MHz
  16. {
  17.         AUXR |= 0x80;                //定时器时钟1T模式
  18.         TMOD &= 0xF0;                //设置定时器自动重载模式
  19.         TL0 = 0xCD;                        //设置定时初始值
  20.         TH0 = 0xD4;                        //设置定时初始值
  21.         TF0 = 0;                                //清除TF0标志
  22.         TR0 = 1;                                //定时器0开始计时
  23.         ET0 = 1;                                //允许T0中断
  24. //        EA  = 1;                                //开总中断
  25. }
  26. void Delay20ms()                //@11.0592MHz
  27. {
  28.         unsigned char i, j;

  29.         i = 216;
  30.         j = 37;
  31.         do
  32.         {
  33.                 while (--j);
  34.         } while (--i);
  35. }

  36. void key_scan()    //按键扫描函数
  37. {
  38.         if(flag1ms)  //1ms时间标志
  39.         {
  40.                 flag1ms = 0;//1ms时间标志清0
  41.                 if(!key && !on_off)
  42.                 {
  43.                         if(++keyTim>1000)keyTim=1001;//防止溢出

  44.                         if(keyTim==20) //大于20ms小于1s算短按
  45.                         {
  46.                                 Key_value=0x01;
  47.                         }
  48.                         if(keyTim==1000) //达到1s算长按
  49.                         {
  50.                                 Key_value|=0x10;
  51.                         }
  52.                 }
  53.                 else
  54.                 {
  55.                         keyTim=0;        //按键松手keyTim清0
  56.                 }
  57.         }
  58. }

  59. void key_service()//按键服务函数
  60. {//短按等松手响应,长按达1s不论是否松手即响应
  61.         if((keyTim==0||keyTim==1000) && Key_value!=0x00)
  62.         {
  63.                 if(Key_value==0x01)//短按任务
  64.                 {
  65.                         Temp++;
  66.                         P1=~Temp;//演示,LED低电平亮
  67.                 }
  68.                 if(Key_value==0x11)//长按关机
  69.                 {
  70.                         allow=1;//允许休眠
  71.                 }
  72.                 Key_value=0x00;//任务完成后键值清0
  73.         }
  74. }

  75. void Shutdown()//掉电模式函数
  76. {
  77.         if(allow)
  78.         {
  79.                 P1=0xff;                //关闭LED显示
  80.                 //关闭所有在用硬件,减小能耗
  81.                 while(!key);//等待按键松手
  82.                 Delay20ms();//消抖防止误动作
  83.                 EX0 = 1;                //开外部中断
  84.                 PCON = 0x02;//MCU进入掉电模式
  85. /************************************************/
  86.                 _nop_();    //掉电模式被唤醒后,首先执行此语句,然后再进入中断服务程序
  87.                 _nop_();    //中断服务程序执行完再接着此句继续执行
  88.                 while(!key);//等待按键松手,防止按键扫描程序误读
  89.                 Delay20ms();//消抖防止误动作
  90.                 //打开所有在用硬件,恢复正常运行
  91.                 allow=0;                //清0
  92.                 on_off=0;        //开关标志清0
  93.                 P1=~Temp;        //恢复LED显示
  94.         }
  95. }

  96. void main()
  97. {
  98.         P0M0 = 0x00;//初始化IO
  99.         P0M1 = 0x00;
  100.         P1M0 = 0x00;
  101.         P1M1 = 0x00;
  102.         P2M0 = 0x00;
  103.         P2M1 = 0x00;
  104.         P3M0 = 0x00;
  105.         P3M1 = 0x00;
  106.         P4M0 = 0x00;
  107.         P4M1 = 0x00;
  108.         P5M0 = 0x00;
  109.         P5M1 = 0x00;
  110.         P6M0 = 0x00;
  111.         P6M1 = 0x00;
  112.         P7M0 = 0x00;
  113.         P7M1 = 0x00;
  114.         GND  = 0;
  115.         IT0 = 1;//设置INT0的中断类型为下降沿唤醒
  116. //        EX0 = 1;//使能INT0中断
  117.         EA  = 1;//开总中断                                                        
  118.         Timer0Init();//定时器初始化函数
  119.         while (1)
  120.         {
  121.                 key_scan();                //按键扫描函数
  122.                 key_service(); //按键服务函数
  123.                 Shutdown();                //掉电模式函数
  124.         }
  125. }
  126. //INT0中断服务程序
  127. void exint0() interrupt 0
  128. {
  129.         EX0 = 0;                //关外部中断
  130.         on_off=1;//开关标志置1
  131. }
  132. //T0中断服务程序
  133. void interruptTimer0() interrupt 1
  134. {
  135.         flag1ms = 1;    //1ms标志
  136. }
复制代码
回复

使用道具 举报

ID:1153575 发表于 2025-10-9 15:50 | 显示全部楼层
谢谢各位工程提供的建议,根据你们的建议,我已经实现了该功能!!
回复

使用道具 举报

ID:57657 发表于 2025-10-9 17:28 | 显示全部楼层
此长按开机与手机开机原理类似:
半唤醒:关机状态开机键有按下,控制芯片开始工作并检测电池电量是否符合开机条件,对开机键按住时间毫秒计数,松开后计数清零并重新休眠,计数满后全唤醒:正式开机、屏幕等模块开始工作。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表