找回密码
 立即注册
查看: 141|回复: 13

触摸按键零点追踪长按问题

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 6 天前 | 显示全部楼层 |阅读模式
  1. <div class="blockcode"><blockquote>// 方案001
  2. // 功能说明
  3. /*******************************************************
  4. *                器件引脚功能说明封装图
  5. * -----------------------------------------------------
  6. *                [ 上视图 - 引脚逻辑分布 ]
  7. *
  8. *                   ┌────────────────────┐
  9. *          电池电压检测 ──┤  1           16 ├─ 触摸按键 (TK)
  10. *          电机电流检测   ──┤  2           15 ├─ LED / 电解片电压检测
  11. *          电机开关     ──┤  3           14 ├─ LED
  12. *          电解片电流检测 ─┤  4           13 ├─ LED
  13. *          PWM-1MHz 输出  ─┤  5           12 ├─ 电解片开关
  14. *          VCC (电源正)  ──┤  6           11 ├─ 充电座检测
  15. *          ADC-VREF基准  ─┤  7           10 ├─ 充电开关 (充电时ON)
  16. *          GND (电源地)  ──┤  8            9 ├─ 充电锁控制 (充满/脱离锁住)
  17. *                   └────────────────────┘
  18. *
  19. * -----------------------------------------------------
  20. * 功能说明:
  21. * 1. 电池电压检测:ADC通道采样,用于监控电池电压。
  22. * 2. 充电座检测:底座接触检测信号,判断是否在充电底座上。
  23. * 3. 电机开关:控制电机通断。
  24. * 4. 电解片电流检测:ADC采样检测电解片实际工作电流。
  25. * 5. PWM-1MHz:输出高频PWM信号(1MHz)驱动或调制用。
  26. * 6. VCC:系统电源正极输入。
  27. * 7. ADC-VREF:ADC参考电压输入端。
  28. * 8. GND:电源地。
  29. *
  30. * 9.  充电锁控制:充满或脱离底座时锁定充电接口。
  31. * 10. 充电开关:充电过程中打开,非充电状态关闭。
  32. * 11. 电机电流检测:检测电机工作电流,防止过流。
  33. * 12. 电解片开关:控制电解片通断。
  34. * 13~15. LED:指示灯输出端,用于状态指示。
  35. * 15. 另作电解片电压检测输入。
  36. * 16. TK:触摸按键输入通道。
  37. *
  38. *******************************************************/
  39. // 头文件
  40. #include "STC8Hxxx.h"
  41. // 引脚定义
  42. sbit LEDR = P3^4;
  43. sbit LEDG = P3^5;
  44. sbit LEDB = P3^6;
  45. // 宏定义
  46. #define MAIN_Fosc        30000000L                // 定义主时钟  串口波特率 300 ~ 4800
  47. // 声明
  48. // 数组
  49. u16        xdata TK_cnt[16];        // 按键计数值, 16位
  50. u16        xdata TK_zero[16];        // 按键0点值, 16位
  51. //                         K0     K1     K2     K3     K4     K5      K6    K7     K8     K9     K10   K11    K12    K13    K14    K15
  52. // 触摸后的变化值
  53. u16 code T_KeyPress[16]={ 1300,  2000,  900,   800,   900,   1000,   1100, 1400,  1000,  1200,   900,  1200,  750,   900,   1300,  1800};
  54. // 16个键对应的状态, 0为未触摸,1为触摸       
  55. u16 code T_KeyState[16]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
  56. // 函数
  57. void delay_ms(u8 ms);
  58. void TouchKey_Init(void);
  59. void Timer2_Init(void);
  60. // 变量
  61. bit        B_TK_Lowpass;                // 低通允许, 1允许, 0禁止
  62. u8 i;
  63. u8 read_cnt;                        // 读次数
  64. u8 mode = 2;            // 初始待机模式 0:休眠, 1:恢复, 2:待机, 3:工作
  65. u16        j;
  66. u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放
  67. // 函数模块
  68. // 描述: 延时函数
  69. // 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
  70. void delay_ms(u8 ms)
  71. {
  72.      u16 i;
  73.          do
  74.          {
  75.                  i = MAIN_Fosc / 10000;
  76.                 while(--i)        ;
  77.      }while(--ms);
  78. }
  79. // 触摸按键初始化
  80. void TouchKey_Init(void)
  81. {
  82.     u8 i, read_cnt;
  83.     // ==== 启用触摸通道 ====
  84.     TSCHEN1 = 0x00;         // 关闭 TK0~TK7
  85.     TSCHEN2 = 0x80;         // 启用 TK15 (bit7)
  86.     // ==== 触摸参数配置 ====
  87.     TSCFG1  = (7<<4) + 6;   // 时钟、采样参数,根据实际硬件调
  88.     TSCFG2  = 1;
  89.     TSRT    = 0x00;
  90.     // ==== 开启触摸中断 ====
  91.     IE2 |= 0x80;
  92.     // ==== 采样建立初始零点 ====
  93.     delay_ms(50);
  94.     B_TK_Lowpass = 0;
  95.     for(read_cnt=0; read_cnt<10; read_cnt++)
  96.     {
  97.         TSCTRL = (1<<7) + (1<<6);  // 开始扫描
  98.         delay_ms(50);
  99.     }
  100.     for(i=0; i<16; i++) TK_zero[i] = TK_cnt[i];
  101.     B_TK_Lowpass = 1;
  102.     KeyState = 0;
  103.     // ==== 设置TK15唤醒阈值 ====
  104.     TSTH15 = TK_zero[15] - T_KeyPress[15]/2;
  105. }
  106. // 20ms心跳
  107. void Timer2_Init(void)                                                            // 20毫秒@30.000MHz
  108. {
  109.         AUXR &= 0xFB;                                                                    // 定时器时钟12T模式
  110.         T2L = 0xB0;                                                                            // 设置定时初始值
  111.         T2H = 0x3C;                                                                            // 设置定时初始值
  112.         AUXR |= 0x10;                                                                    // 定时器2开始计时
  113.         IE2 |= 0x04;                                                                    // 使能定时器2中断
  114. }
  115. // 主函数
  116. void main(void)
  117. {
  118.         P_SW2 |= 0x80;                                                                // 允许访问扩展寄存器xsfr
  119.     // 引脚初始化
  120.     P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出
  121.     P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
  122.     P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P30 31 33 34 35 36) 推挽输出
  123.     LEDR = 0;
  124.     LEDG = 0;
  125.     LEDB = 0;
  126.     EA = 1;
  127.     // 函数初始化
  128.     Timer2_Init();
  129.     TouchKey_Init();
  130.         while (1)
  131.         {
  132.         // 休眠模式
  133.         if(mode == 0)
  134.         {
  135.             TSCTRL = (1<<3) + (1<<2);               // 触摸唤醒使能
  136.             // 除去 外部中断唤醒以及TK唤醒 其他全部高阻输入 禁止数字输入 降低功耗
  137.             P1M0 &= ~0x0b; P1M1 |= 0x0b;     P1IE &= ~0x0b;
  138.             P5M0 &= ~0x10; P5M1 |= 0x10;     P5IE &= ~0x10;
  139.             P3M0 = 0x00; P3M1 = 0xff;        P3IE &= ~0x7b;
  140.             PCON |= 0x02;                           // MCU 睡眠
  141.             mode = 1;                               // 唤醒后自动跳出
  142.         }
  143.         if(mode == 1)
  144.         {
  145.             TSCTRL = (1<<7) + (1<<3) + (1<<2);      // 恢复TK扫描
  146.             // 引脚初始化
  147.             P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出
  148.             P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
  149.             P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P30 31 33 34 35 36) 推挽输出
  150.         }
  151.         if(mode == 2)
  152.         {
  153.         }
  154.         if(mode == 3)
  155.         {
  156.         }
  157.         }
  158. }
  159. // 中断服务函数
  160. // 描述: 触摸按键中断服务函数
  161. void TKSU_ISR(void) interrupt TKSU_VECTOR
  162. {
  163.         u8        j;
  164.         j = TSSTA2;
  165.         if(j & 0x40)                                                            // 数据溢出, 错误处理(略)
  166.         {
  167.                 TSSTA2 |= 0x40;                                                        // 写1清零
  168.         }
  169.         if(j & 0x80)                                                            // 扫描完成
  170.         {
  171.                 j &= 0x0f;
  172.                 TSSTA2 |= 0x80;                                                        // 写1清零
  173.                 if(!B_TK_Lowpass)        TK_cnt[j] = TSDAT;                                // 保存某个通道的读数        1.1us @24MHz
  174.         // 保存某个通道的读数        1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500
  175.                 else    TK_cnt[j] = (TK_cnt[j] >> 1) + (TSDAT >> 1);                    
  176.         }
  177. }
  178. // 20ms心跳
  179. void Timer2_Isr(void) interrupt 12
  180. {
  181.     TSCTRL = (1<<7) + (1<<6);                                                 // 开始扫描, 无平均
  182.     if(++read_cnt >= 3)
  183.     {
  184.         read_cnt = 0;
  185.         j = KeyState;
  186.         for(i=0; i<16; i++)
  187.         {
  188.             if(TK_zero[i] > TK_cnt[i])
  189.             {
  190.                 TK_zero[i]--;
  191.                      if((TK_zero[i] - TK_cnt[i]) >= T_KeyPress[i]/2)        KeyState |=  T_KeyState[i];
  192.                 else if((TK_zero[i] - TK_cnt[i]) <= T_KeyPress[i]/3)        KeyState &= ~T_KeyState[i];
  193.             }
  194.             else
  195.             {
  196.                 KeyState &= ~T_KeyState[i];
  197.                 if((TK_cnt[i] - TK_zero[i]) > 100)        TK_zero[i] += 100;
  198.                 else                                                                TK_zero[i] += 10;
  199.             }
  200.         }
  201.         // 触摸值判断
  202.         j = (j ^ KeyState) & KeyState;
  203.         B = (u8)j;
  204.         B = (u8)(j >> 8);
  205.         if(B7)        LEDG = ~LEDG;       // mode = 3;   else mode = 2;          // 触摸后开始工作 反之待机模式
  206.     }
  207. }
复制代码

参考了零点追踪的触摸按键 但是发现貌似只适合单点触摸

测试长按的时候会跳到绿光回到红光 看起来无法检测长按 可能是达到阈值以后触发之后就重置了

应该怎么能让它识别长按  因为需要触摸按键一直按着才能工作 松开就不工作了


并且mode = 2 的时候触摸是正常的

一旦mode = 0 那么无法唤醒或者唤醒后绿灯不能正常开关
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 6 天前 | 显示全部楼层
还有个问题
这里的数字输入关闭 当我在恢复引脚状态的时候需要处理它吗
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:608
  • 最近打卡:2025-11-08 00:00:02
已绑定手机

87

主题

6482

回帖

1万

积分

超级版主

积分
12280
发表于 6 天前 | 显示全部楼层
零点追踪用于没有按键按下时修正缓慢飘移的零点
零点追踪例程不支持长按,程序需要修改
由于按下按键时键值的斜率大,缓慢漂移时键值的斜率小
斜率即单位时间内键值的变化量,可以使用定时器或其他方式计时,计算出单位时间内键值的变化量
可以根据键值的斜率判断是否按下,当按下时屏蔽零点追踪,只有在没按下时进行零点追踪,就可以避免长按被误判为漂移
触摸按键和ADC等模拟信号的IO,初始化时直接关闭数字输入,不需要再打开
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 5 天前 | 显示全部楼层
Debu*** 发表于 2025-11-2 20:35
零点追踪用于没有按键按下时修正缓慢飘移的零点
零点追踪例程不支持长按,程序需要修改
由于按下按键时键值 ...

也就是因为进行零点追踪导致无法使用长按
那么当按下时屏蔽零点追踪,只有在没按下时进行零点追踪这个触摸按键方式有案例吗?

触摸按键 ADC 比较器 外部中断这些都可以在初始化的时候就直接关闭数字输入
那么例如推挽输出的引脚 需要初始化为推挽输出 然后关闭数字输入吗?

点评

长按和零点追踪共存的例程暂无 外部中断是数字功能,且是输入,不能关闭数字输入 推挽输出可以关闭数字输入功能 关闭数字输入是为了防止省电模式时IO处于临界状态会有额外的功耗  详情 回复 发表于 4 天前
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 5 天前 | 显示全部楼层
  1. // 方案001-2
  2. // 功能说明
  3. // 头文件
  4. #include "STC8Hxxx.h"
  5. // 引脚定义
  6. sbit LEDR = P3^4;
  7. sbit LEDG = P3^5;
  8. sbit LEDB = P3^6;
  9. // 宏定义
  10. #define MAIN_Fosc        30000000L                // 定义主时钟  串口波特率 300 ~ 4800
  11. // 声明
  12. // 数组
  13. u16 xdata TK_last[16];
  14. u16 xdata TK_slope[16];
  15. u16 xdata TK_Pressed[16];
  16. u16        xdata TK_cnt[16];        // 按键计数值, 16位
  17. u16        xdata TK_zero[16];        // 按键0点值, 16位
  18. //                         K0     K1     K2     K3     K4     K5      K6    K7     K8     K9     K10   K11    K12    K13    K14    K15
  19. // 触摸后的变化值
  20. u16 code T_KeyPress[16]={ 1300,  2000,  900,   800,   900,   1000,   1100, 1400,  1000,  1200,   900,  1200,  750,   900,   1300,  1800};
  21. // 16个键对应的状态, 0为未触摸,1为触摸        
  22. u16 code T_KeyState[16]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
  23. // 函数
  24. void delay_ms(u8 ms);
  25. void TouchKey_Init(void);
  26. void Timer2_Init(void);
  27. void Ext_Init(void);
  28. void IO_Sleep(void);
  29. void IO_Wakeup(void);
  30. // 变量
  31. bit        B_TK_Lowpass;                // 低通允许, 1允许, 0禁止
  32. u8 i;
  33. u8 read_cnt;                        // 读次数
  34. u8 mode = 0;                // mode 0:休眠/恢复模式 2:待机模式 3:工作模式
  35. u16        j;
  36. u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放
  37. // 函数模块
  38. // ms延时函数-自适应主时钟
  39. void delay_ms(u8 ms)
  40. {
  41.     u16 i;
  42.         do
  43.         {
  44.                 i = MAIN_Fosc / 10000;
  45.             while(--i)        ;
  46.     }
  47.     while(--ms);
  48. }
  49. // 触摸初始化
  50. void TouchKey_Init(void)
  51. {
  52.     u8 i, read_cnt;
  53.     TSCHEN1 = 0x00;
  54.     TSCHEN2 = 0x80;         // 启用TK15
  55.     TSCFG1  = (7<<4) + 6;
  56.     TSCFG2  = 1;
  57.     TSRT    = 0x00;
  58.     IE2 |= 0x80;
  59.     delay_ms(50);
  60.     B_TK_Lowpass = 0;
  61.     for(read_cnt=0; read_cnt<10; read_cnt++)
  62.     {
  63.         TSCTRL = (1<<7) + (1<<6);
  64.         delay_ms(50);
  65.     }
  66.     for(i=0; i<16; i++)
  67.     {
  68.         TK_zero[i] = TK_cnt[i];
  69.         TK_last[i] = TK_cnt[i];
  70.         TK_Pressed[i] = 0;
  71.     }
  72.     B_TK_Lowpass = 1;
  73.     KeyState = 0;
  74.     TSTH15 = TK_zero[15] - T_KeyPress[15]/2;
  75. }
  76. // 20ms心跳
  77. void Timer2_Init(void)                                                            // 20毫秒@30.000MHz
  78. {
  79.         AUXR &= 0xFB;                                                                    // 定时器时钟12T模式
  80.         T2L = 0xB0;                                                                            // 设置定时初始值
  81.         T2H = 0x3C;                                                                            // 设置定时初始值
  82.         AUXR |= 0x10;                                                                    // 定时器2开始计时
  83.         IE2 |= 0x04;                                                                    // 使能定时器2中断
  84. }
  85. // 外部中断0配置
  86. void Ext_Init(void)
  87. {
  88.         IT0 = 0;                                                                        // INT0(P3.2)上升沿+下降沿中断
  89.         EX0 = 1;                                                                        // 使能INT0中断
  90. }
  91. // IO休眠
  92. void IO_Sleep(void)
  93. {
  94.     // 休眠模式
  95.     P5M0 &= ~0x10; P5M1 |= 0x10;     P5IE &= ~0x10;
  96.     P1M0 &= ~0x0b; P1M1 |= 0x0b;     P1IE &= ~0x0b;
  97.     P3M0 = 0x00; P3M1 = 0xff;        P3IE &= ~0x7b;
  98.     // 引脚状态
  99.     LEDR = 0;   LEDG = 0;  LEDB = 0;
  100.     // 允许 TK15 唤醒 MCU,其它按键可根据需要修改
  101.     TSCHEN1 = 0x00;                                                     // TK0~TK7 禁用唤醒
  102.     TSCHEN2 = 0x80;                                                     // TK8~TK15 允许 TK15 唤醒
  103.     TSCTRL  = (1<<3) + (1<<2);                                          // 数字比较器 + 低功耗唤醒使能
  104. }
  105. // IO唤醒
  106. void IO_Wakeup(void)
  107. {
  108.     // 恢复模式
  109.     P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P3 0 31 33 34 35 36) 推挽输出
  110.     P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
  111.     P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出
  112.     // 引脚状态
  113.     LEDR = 0;   LEDG = 0;  LEDB = 0;
  114. }
  115. // 主函数
  116. void main(void)
  117. {
  118.     P_SW2 |= 0x80;                                                                // 允许访问扩展寄存器xsfr
  119.     IO_Wakeup();                                                        // IO唤醒
  120.     EA = 1;                                                             // 开总中断
  121.     IRCDB = 0x10;                                                       // 配置唤醒
  122.     IAP_TPS = 0x30;                                                     // 30Mhz晶振
  123.     // 启动32k内部振荡器,用于触摸按键低功耗唤醒
  124.     IRC32KCR = 0x80;
  125.     while (!(IRC32KCR & 1));                                            // 等待时钟稳定
  126.    
  127.    
  128.     // 函数初始化
  129.     Ext_Init();                                                         // 外部中断0初始化
  130.     TouchKey_Init();                                                    // 触摸按键初始化--No.1
  131.     Timer2_Init();                                                      // 定时器2初始化--No.2
  132.    
  133.     // 主循环
  134.     while(1)
  135.     {
  136.         // 休眠/恢复模式
  137.         if(mode == 0)
  138.         {
  139.             IO_Sleep();                                                 // IO休眠
  140.             // 寄存器初始化
  141.             PCON = 0x02;                                                // MCU进入掉电模式
  142.             IO_Wakeup();                                                // IO唤醒
  143.             mode = 2;                                                   // 自动跳转待机
  144.         }
  145.         // 待机模式
  146.         if(mode == 2)
  147.         {
  148.             LEDR = 1;
  149.             LEDG = 0;
  150.         }
  151.         // 工作模式
  152.         if(mode == 3)
  153.         {
  154.             LEDR = 0;
  155.             LEDG = 1;
  156.         }
  157.     }
  158. }
  159. // 中断服务函数
  160. // 外部中断0服务函数
  161. void INT0_Isr(void) interrupt 0
  162. {
  163. }
  164. // 描述: 触摸按键中断服务函数
  165. void TKSU_ISR(void) interrupt TKSU_VECTOR
  166. {
  167.         u8        j;
  168.         j = TSSTA2;
  169.         if(j & 0x40)                                                            // 数据溢出, 错误处理(略)
  170.         {
  171.                 TSSTA2 |= 0x40;                                                        // 写1清零
  172.         }
  173.         if(j & 0x80)                                                            // 扫描完成
  174.         {
  175.                 j &= 0x0f;
  176.                 TSSTA2 |= 0x80;                                                        // 写1清零
  177.                 if(!B_TK_Lowpass)        TK_cnt[j] = TSDAT;                                // 保存某个通道的读数        1.1us @24MHz
  178.         // 保存某个通道的读数        1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500
  179.                 else    TK_cnt[j] = (TK_cnt[j] >> 1) + (TSDAT >> 1);                    
  180.         }
  181. }
  182. // 定时器2中断(20ms心跳)
  183. void Timer2_Isr(void) interrupt 12
  184. {
  185.     TSCTRL = (1<<7) + (1<<6);
  186.     if(++read_cnt >= 3)
  187.     {
  188.         read_cnt = 0;
  189.         j = KeyState;
  190.         for(i=0; i<16; i++)
  191.         {
  192.             if (TK_cnt[i] > TK_last[i])
  193.                 TK_slope[i] = TK_cnt[i] - TK_last[i];
  194.             else
  195.                 TK_slope[i] = TK_last[i] - TK_cnt[i];
  196.             TK_last[i] = TK_cnt[i];
  197.             if (TK_slope[i] > 200)
  198.                 TK_Pressed[i] = 1;
  199.             else if ((TK_zero[i] > TK_cnt[i]) ?
  200.                      ((TK_zero[i] - TK_cnt[i]) < T_KeyPress[i]/4) :
  201.                      ((TK_cnt[i] - TK_zero[i]) < T_KeyPress[i]/4))
  202.                 TK_Pressed[i] = 0;
  203.             if (TK_Pressed[i])
  204.             {
  205.                 if ((TK_zero[i] - TK_cnt[i]) >= T_KeyPress[i]/2)
  206.                     KeyState |=  T_KeyState[i];
  207.             }
  208.             else
  209.             {
  210.                 if (TK_zero[i] > TK_cnt[i])
  211.                     TK_zero[i]--;
  212.                 else if (TK_zero[i] < TK_cnt[i])
  213.                     TK_zero[i]++;
  214.                 if ((TK_zero[i] - TK_cnt[i]) <= T_KeyPress[i]/3)
  215.                     KeyState &= ~T_KeyState[i];
  216.             }
  217.         }
  218.     }
  219.     // 扫描触摸按键判断
  220.     // 按下按键
  221.     if (KeyState & T_KeyState[15])
  222.     {
  223.         mode = 3;                                                           // 工作模式
  224.     }
  225.     // 松开按键
  226.     else
  227.     {
  228.         mode = 2;                                                           // 待机模式
  229.     }
  230. }
复制代码




现在这个程序的问题是
进入省电模式的时候 功耗达到了0.568mA 原来没有配置触摸按键唤醒的时候只有0.340mA
为什么功耗会变这么高 命名已经全部都关掉了

然后外部中断唤醒是正常的 但是触摸按键唤醒的时候会有问题 触碰以后 会变成红灯亮一下 然后 绿灯常亮 触摸按键功能不起作用了

点评

300多μA和500多μA好像都不太正常,检查省电模式时IO是否有电流,IO要设置为没有电流的状态,注意外部的上下拉电阻  详情 回复 发表于 4 天前
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:608
  • 最近打卡:2025-11-08 00:00:02
已绑定手机

87

主题

6482

回帖

1万

积分

超级版主

积分
12280
发表于 4 天前 | 显示全部楼层
HyunYon*** 发表于 2025-11-3 02:05
也就是因为进行零点追踪导致无法使用长按
那么当按下时屏蔽零点追踪,只有在没按下时进行零点追踪这个触 ...

长按和零点追踪共存的例程暂无
外部中断是数字功能,且是输入,不能关闭数字输入
推挽输出可以关闭数字输入功能
关闭数字输入是为了防止省电模式时IO处于临界状态会有额外的功耗
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:608
  • 最近打卡:2025-11-08 00:00:02
已绑定手机

87

主题

6482

回帖

1万

积分

超级版主

积分
12280
发表于 4 天前 | 显示全部楼层
HyunYon*** 发表于 2025-11-3 12:02
现在这个程序的问题是
进入省电模式的时候 功耗达到了0.568mA 原来没有配置触摸按键唤醒的时候只有0.34 ...

300多μA和500多μA好像都不太正常,检查省电模式时IO是否有电流,IO要设置为没有电流的状态,注意外部的上下拉电阻
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 4 天前 | 显示全部楼层
Debu*** 发表于 2025-11-4 06:28
长按和零点追踪共存的例程暂无
外部中断是数字功能,且是输入,不能关闭数字输入
推挽输出可以关闭数字输 ...

长按和外部中断的数字输入已经打开了
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 4 天前 | 显示全部楼层
  1. // 方案001-2
  2. // 头文件
  3. #include "STC8Hxxx.h"
  4. // 引脚定义
  5. sbit LEDR = P3^4;
  6. sbit LEDG = P3^5;
  7. sbit LEDB = P3^6;
  8. sbit base = P3^2;
  9. // 宏定义
  10. #define MAIN_Fosc        30000000L                // 定义主时钟  串口波特率 300 ~ 4800
  11. // 声明
  12. // 数组
  13. u16 xdata TK_last[16];
  14. u16 xdata TK_slope[16];
  15. u16 xdata TK_Pressed[16];
  16. u16        xdata TK_cnt[16];        // 按键计数值, 16位
  17. u16        xdata TK_zero[16];        // 按键0点值, 16位
  18. //                         K0     K1     K2     K3     K4     K5      K6    K7     K8     K9     K10   K11    K12    K13    K14    K15
  19. // 触摸后的变化值
  20. u16 code T_KeyPress[16]={ 1300,  2000,  900,   800,   900,   1000,   1100, 1400,  1000,  1200,   900,  1200,  750,   900,   1300,  1800};
  21. // 16个键对应的状态, 0为未触摸,1为触摸       
  22. u16 code T_KeyState[16]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
  23. // 函数
  24. void delay_ms(u8 ms);
  25. void TouchKey_Init(void);
  26. void Timer2_Init(void);
  27. void Ext_Init(void);
  28. void IO_Sleep(void);
  29. void IO_Wakeup(void);
  30. // 变量
  31. bit        B_TK_Lowpass;                // 低通允许, 1允许, 0禁止
  32. bit base_now;           // 充电底座状态 1为充电底座上, 0为非充电底座上
  33. u8 i;
  34. u8 read_cnt;                        // 读次数
  35. u8 mode = 2;                // mode 0:休眠/恢复模式 2:待机模式 3:工作模式
  36. u16        j;
  37. u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放
  38. u16 count;
  39. // 函数模块
  40. // ms延时函数-自适应主时钟
  41. void delay_ms(u8 ms)
  42. {
  43.     u16 i;
  44.         do
  45.         {
  46.                 i = MAIN_Fosc / 10000;
  47.             while(--i)        ;
  48.     }
  49.     while(--ms);
  50. }
  51. // 触摸初始化
  52. void TouchKey_Init(void)
  53. {
  54.     u8 i, read_cnt;
  55.     TSCHEN1 = 0x00;
  56.     TSCHEN2 = 0x80;         // 启用TK15
  57.     TSCFG1  = (7<<4) + 6;
  58.     TSCFG2  = 1;
  59.     TSRT    = 0x00;
  60.     IE2 |= 0x80;
  61.     delay_ms(50);
  62.     B_TK_Lowpass = 0;
  63.     for(read_cnt=0; read_cnt<10; read_cnt++)
  64.     {
  65.         TSCTRL = (1<<7) + (1<<6);
  66.         delay_ms(50);
  67.     }
  68.     for(i=0; i<16; i++)
  69.     {
  70.         TK_zero[i] = TK_cnt[i];
  71.         TK_last[i] = TK_cnt[i];
  72.         TK_Pressed[i] = 0;
  73.     }
  74.     B_TK_Lowpass = 1;
  75.     KeyState = 0;
  76.     TSTH15 = TK_zero[15] - T_KeyPress[15]/2;
  77. }
  78. // 20ms心跳
  79. void Timer2_Init(void)                                                            // 20毫秒@30.000MHz
  80. {
  81.         AUXR &= 0xFB;                                                                    // 定时器时钟12T模式
  82.         T2L = 0xB0;                                                                            // 设置定时初始值
  83.         T2H = 0x3C;                                                                            // 设置定时初始值
  84.     AUXR |= 0x10;                                                                    // 定时器2开始计时
  85.     IE2 |= 0x04;                                                                    // 使能定时器2中断
  86. }
  87. // 外部中断0配置
  88. void Ext_Init(void)
  89. {
  90.         IT0 = 0;                                                                        // INT0(P3.2)上升沿+下降沿中断
  91.         EX0 = 1;                                                                        // 使能INT0中断
  92. }
  93. // IO休眠
  94. void IO_Sleep(void)
  95. {
  96.     // 休眠模式
  97.     P5M0 &= ~0x10; P5M1 |= 0x10;     P5IE &= ~0x10;
  98.     P1M0 &= ~0x0b; P1M1 |= 0x0b;     P1IE &= ~0x0b;
  99.     P3M0 = 0x00; P3M1 = 0xff;        P3IE &= ~0x7b;
  100.     // 引脚状态
  101.     LEDR = 0;   LEDG = 0;  LEDB = 0;
  102.     // 允许 TK15 唤醒 MCU,其它按键可根据需要修改
  103.     TSCHEN1 = 0x00;                                                     // TK0~TK7 禁用唤醒
  104.     TSCHEN2 = 0x80;                                                     // TK8~TK15 允许 TK15 唤醒
  105.     TSCTRL  = (1<<3) + (1<<2);                                          // 数字比较器 + 低功耗唤醒使能
  106. }
  107. // IO唤醒
  108. void IO_Wakeup(void)
  109. {
  110.     // 恢复模式
  111.     P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P3 0 31 33 34 35 36) 推挽输出
  112.     P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
  113.     P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出
  114.     // 引脚状态
  115.     LEDR = 0;   LEDG = 0;  LEDB = 0;
  116. }
  117. // 主函数
  118. void main(void)
  119. {
  120.     P_SW2 |= 0x80;                                                                // 允许访问扩展寄存器xsfr
  121.     IO_Wakeup();                                                        // IO唤醒
  122.     EA = 1;                                                             // 开总中断
  123.     IRCDB = 0x10;                                                       // 配置唤醒
  124.     IAP_TPS = 0x30;                                                     // 30Mhz晶振
  125.     // 启动32k内部振荡器,用于触摸按键低功耗唤醒
  126.     IRC32KCR = 0x80;
  127.     while (!(IRC32KCR & 1));                                            // 等待时钟稳定
  128.    
  129.    
  130.     // 函数初始化
  131.     Ext_Init();                                                         // 外部中断0初始化
  132.     TouchKey_Init();                                                    // 触摸按键初始化--No.1
  133.     Timer2_Init();                                                      // 定时器2初始化--No.2
  134.    
  135.     // 主循环
  136.     while(1)
  137.     {
  138.         if(base == 1)                                                   // 在充电底座上
  139.         {
  140.             base_now = 1;
  141.             LEDR = 0;
  142.             LEDG = 0;
  143.         }
  144.         else                                                            // 不在充电底座上
  145.         {
  146.             base_now = 0;
  147.             // 休眠/恢复模式
  148.             if(mode == 0)
  149.             {
  150.                 IO_Sleep();                                                 // IO休眠
  151.                 // 寄存器初始化
  152.                 PCON = 0x02;                                                // MCU进入掉电模式
  153.                 IO_Wakeup();                                                // IO唤醒
  154.                 mode = 2;                                                   // 自动跳转待机
  155.             }
  156.             // 待机模式
  157.             if(mode == 2)
  158.             {
  159.                 LEDR = 1;
  160.                 LEDG = 0;
  161.             }
  162.             // 工作模式
  163.             if(mode == 3)
  164.             {
  165.                 LEDR = 0;
  166.                 LEDG = 1;
  167.             }
  168.         }
  169.     }
  170. }
  171. // 中断服务函数
  172. // 外部中断0服务函数
  173. void INT0_Isr(void) interrupt 0
  174. {
  175. }
  176. // 描述: 触摸按键中断服务函数
  177. void TKSU_ISR(void) interrupt TKSU_VECTOR
  178. {
  179.         u8        j;
  180.         j = TSSTA2;
  181.         if(j & 0x40)                                                            // 数据溢出, 错误处理(略)
  182.         {
  183.                 TSSTA2 |= 0x40;                                                        // 写1清零
  184.         }
  185.         if(j & 0x80)                                                            // 扫描完成
  186.         {
  187.                 j &= 0x0f;
  188.                 TSSTA2 |= 0x80;                                                        // 写1清零
  189.                 if(!B_TK_Lowpass)        TK_cnt[j] = TSDAT;                                // 保存某个通道的读数        1.1us @24MHz
  190.         // 保存某个通道的读数        1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500
  191.                 else    TK_cnt[j] = (TK_cnt[j] >> 1) + (TSDAT >> 1);                    
  192.         }
  193. }
  194. // 定时器2中断(20ms心跳)
  195. void Timer2_Isr(void) interrupt 12
  196. {
  197.     if(base_now == 0)                                                   // 不在充电底座上才能判断触摸按键
  198.     {
  199.         // =========== 触摸按键数据读取 =========== //
  200.         TSCTRL = (1<<7) + (1<<6);
  201.         if(++read_cnt >= 3)
  202.         {
  203.             read_cnt = 0;
  204.             j = KeyState;
  205.             for(i=0; i<16; i++)
  206.             {
  207.                 if (TK_cnt[i] > TK_last[i])
  208.                     TK_slope[i] = TK_cnt[i] - TK_last[i];
  209.                 else
  210.                     TK_slope[i] = TK_last[i] - TK_cnt[i];
  211.                 TK_last[i] = TK_cnt[i];
  212.                 if (TK_slope[i] > 200)
  213.                     TK_Pressed[i] = 1;
  214.                 else if ((TK_zero[i] > TK_cnt[i]) ?
  215.                          ((TK_zero[i] - TK_cnt[i]) < T_KeyPress[i]/4) :
  216.                          ((TK_cnt[i] - TK_zero[i]) < T_KeyPress[i]/4))
  217.                     TK_Pressed[i] = 0;
  218.                 if (TK_Pressed[i])
  219.                 {
  220.                     if ((TK_zero[i] - TK_cnt[i]) >= T_KeyPress[i]/2)
  221.                         KeyState |=  T_KeyState[i];
  222.                 }
  223.                 else
  224.                 {
  225.                     if (TK_zero[i] > TK_cnt[i])
  226.                         TK_zero[i]--;
  227.                     else if (TK_zero[i] < TK_cnt[i])
  228.                         TK_zero[i]++;
  229.                     if ((TK_zero[i] - TK_cnt[i]) <= T_KeyPress[i]/3)
  230.                         KeyState &= ~T_KeyState[i];
  231.                 }
  232.             }
  233.         }
  234.         // =========== 触摸按键数据读取 =========== //
  235.         // ========== 触摸按键扫描判断 ========== //
  236.         // 按下按键
  237.         if (KeyState & T_KeyState[15])
  238.         {
  239.             count = 0;
  240.             mode = 3;                                                           // 工作模式
  241.         }
  242.         // 松开按键
  243.         else
  244.         {
  245.             count++;
  246.             if(count >= 150)
  247.             {
  248.                 count = 0;
  249.                 mode = 0;                                                       // 进入休眠
  250.             }
  251.             else
  252.             {
  253.                 mode = 2;                                                       // 待机模式
  254.             }
  255.         }
  256.         // ========== 触摸按键扫描判断 ========== //
  257.     }
  258. }
复制代码



我现在是做成这样 问题出现在触摸按键无法唤醒,只有外部中断引脚 base可以唤醒
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-11-07 15:42:21
已绑定手机

22

主题

76

回帖

251

积分

中级会员

积分
251
发表于 4 天前 | 显示全部楼层
Debu*** 发表于 2025-11-4 06:30
300多μA和500多μA好像都不太正常,检查省电模式时IO是否有电流,IO要设置为没有电流的状态,注意外部的 ...

我现在用的STC8H1K08T
会不会是P54不支持关闭数字输入引脚所导致的

点评

看一下电流的波形,是持续稳定的还是PWM的  详情 回复 发表于 4 天前
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-11-8 00:08 , Processed in 0.126279 second(s), 88 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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