HyunYong_7782 发表于 2025-11-2 11:02:50

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

<div class="blockcode"><blockquote>// 方案001


// 功能说明
/*******************************************************
*                器件引脚功能说明封装图
* -----------------------------------------------------
*                [ 上视图 - 引脚逻辑分布 ]
*
*                   ┌────────────────────┐
*          电池电压检测 ──┤1         16 ├─ 触摸按键 (TK)
*          电机电流检测   ──┤2         15 ├─ LED / 电解片电压检测
*          电机开关   ──┤3         14 ├─ LED
*          电解片电流检测 ─┤4         13 ├─ LED
*          PWM-1MHz 输出─┤5         12 ├─ 电解片开关
*          VCC (电源正)──┤6         11 ├─ 充电座检测
*          ADC-VREF基准─┤7         10 ├─ 充电开关 (充电时ON)
*          GND (电源地)──┤8            9 ├─ 充电锁控制 (充满/脱离锁住)
*                   └────────────────────┘
*
* -----------------------------------------------------
* 功能说明:
* 1. 电池电压检测:ADC通道采样,用于监控电池电压。
* 2. 充电座检测:底座接触检测信号,判断是否在充电底座上。
* 3. 电机开关:控制电机通断。
* 4. 电解片电流检测:ADC采样检测电解片实际工作电流。
* 5. PWM-1MHz:输出高频PWM信号(1MHz)驱动或调制用。
* 6. VCC:系统电源正极输入。
* 7. ADC-VREF:ADC参考电压输入端。
* 8. GND:电源地。
*
* 9.充电锁控制:充满或脱离底座时锁定充电接口。
* 10. 充电开关:充电过程中打开,非充电状态关闭。
* 11. 电机电流检测:检测电机工作电流,防止过流。
* 12. 电解片开关:控制电解片通断。
* 13~15. LED:指示灯输出端,用于状态指示。
* 15. 另作电解片电压检测输入。
* 16. TK:触摸按键输入通道。
*
*******************************************************/


// 头文件
#include "STC8Hxxx.h"


// 引脚定义
sbit LEDR = P3^4;
sbit LEDG = P3^5;
sbit LEDB = P3^6;

// 宏定义
#define MAIN_Fosc        30000000L                // 定义主时钟串口波特率 300 ~ 4800


// 声明
// 数组
u16        xdata TK_cnt;        // 按键计数值, 16位
u16        xdata TK_zero;        // 按键0点值, 16位
//                         K0   K1   K2   K3   K4   K5      K6    K7   K8   K9   K10   K11    K12    K13    K14    K15
// 触摸后的变化值
u16 code T_KeyPress={ 1300,2000,900,   800,   900,   1000,   1100, 1400,1000,1200,   900,1200,750,   900,   1300,1800};
// 16个键对应的状态, 0为未触摸,1为触摸       
u16 code T_KeyState={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// 函数
void delay_ms(u8 ms);
void TouchKey_Init(void);
void Timer2_Init(void);
// 变量
bit        B_TK_Lowpass;                // 低通允许, 1允许, 0禁止

u8 i;
u8 read_cnt;                        // 读次数
u8 mode = 2;            // 初始待机模式 0:休眠, 1:恢复, 2:待机, 3:工作

u16        j;
u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放


// 函数模块
// 描述: 延时函数
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
void delay_ms(u8 ms)
{
   u16 i;
       do
       {
               i = MAIN_Fosc / 10000;
                while(--i)        ;
   }while(--ms);
}

// 触摸按键初始化
void TouchKey_Init(void)
{
    u8 i, read_cnt;

    // ==== 启用触摸通道 ====
    TSCHEN1 = 0x00;         // 关闭 TK0~TK7
    TSCHEN2 = 0x80;         // 启用 TK15 (bit7)

    // ==== 触摸参数配置 ====
    TSCFG1= (7<<4) + 6;   // 时钟、采样参数,根据实际硬件调
    TSCFG2= 1;
    TSRT    = 0x00;

    // ==== 开启触摸中断 ====
    IE2 |= 0x80;

    // ==== 采样建立初始零点 ====
    delay_ms(50);
    B_TK_Lowpass = 0;
    for(read_cnt=0; read_cnt<10; read_cnt++)
    {
      TSCTRL = (1<<7) + (1<<6);// 开始扫描
      delay_ms(50);
    }
    for(i=0; i<16; i++) TK_zero = TK_cnt;
    B_TK_Lowpass = 1;
    KeyState = 0;

    // ==== 设置TK15唤醒阈值 ====
    TSTH15 = TK_zero - T_KeyPress/2;
}

// 20ms心跳
void Timer2_Init(void)                                                            // 20毫秒@30.000MHz
{
        AUXR &= 0xFB;                                                                    // 定时器时钟12T模式
        T2L = 0xB0;                                                                            // 设置定时初始值
        T2H = 0x3C;                                                                            // 设置定时初始值
        AUXR |= 0x10;                                                                    // 定时器2开始计时
        IE2 |= 0x04;                                                                    // 使能定时器2中断
}

// 主函数
void main(void)
{
        P_SW2 |= 0x80;                                                                // 允许访问扩展寄存器xsfr

    // 引脚初始化
    P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出
    P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
    P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P30 31 33 34 35 36) 推挽输出

    LEDR = 0;
    LEDG = 0;
    LEDB = 0;

    EA = 1;

    // 函数初始化
    Timer2_Init();
    TouchKey_Init();

        while (1)
        {
      // 休眠模式
      if(mode == 0)
      {
            TSCTRL = (1<<3) + (1<<2);               // 触摸唤醒使能

            // 除去 外部中断唤醒以及TK唤醒 其他全部高阻输入 禁止数字输入 降低功耗
            P1M0 &= ~0x0b; P1M1 |= 0x0b;   P1IE &= ~0x0b;
            P5M0 &= ~0x10; P5M1 |= 0x10;   P5IE &= ~0x10;
            P3M0 = 0x00; P3M1 = 0xff;      P3IE &= ~0x7b;

            PCON |= 0x02;                           // MCU 睡眠

            mode = 1;                               // 唤醒后自动跳出
      }

      if(mode == 1)
      {
            TSCTRL = (1<<7) + (1<<3) + (1<<2);      // 恢复TK扫描

            // 引脚初始化
            P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出
            P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
            P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P30 31 33 34 35 36) 推挽输出
      }

      if(mode == 2)
      {
      }

      if(mode == 3)
      {
      }
        }
}


// 中断服务函数
// 描述: 触摸按键中断服务函数
void TKSU_ISR(void) interrupt TKSU_VECTOR
{
        u8        j;

        j = TSSTA2;

        if(j & 0x40)                                                          // 数据溢出, 错误处理(略)
        {
                TSSTA2 |= 0x40;                                                        // 写1清零
        }
        if(j & 0x80)                                                          // 扫描完成
        {
                j &= 0x0f;
                TSSTA2 |= 0x80;                                                        // 写1清零
                if(!B_TK_Lowpass)        TK_cnt = TSDAT;                                // 保存某个通道的读数        1.1us @24MHz
      // 保存某个通道的读数        1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500
                else    TK_cnt = (TK_cnt >> 1) + (TSDAT >> 1);                  
        }
}

// 20ms心跳
void Timer2_Isr(void) interrupt 12
{
    TSCTRL = (1<<7) + (1<<6);                                                 // 开始扫描, 无平均

    if(++read_cnt >= 3)
    {
      read_cnt = 0;
      j = KeyState;
      for(i=0; i<16; i++)
      {
            if(TK_zero > TK_cnt)
            {
                TK_zero--;
                     if((TK_zero - TK_cnt) >= T_KeyPress/2)        KeyState |=T_KeyState;
                else if((TK_zero - TK_cnt) <= T_KeyPress/3)        KeyState &= ~T_KeyState;
            }
            else
            {
                KeyState &= ~T_KeyState;
                if((TK_cnt - TK_zero) > 100)        TK_zero += 100;
                else                                                                TK_zero += 10;
            }
      }

      // 触摸值判断
      j = (j ^ KeyState) & KeyState;
      B = (u8)j;
      B = (u8)(j >> 8);
      if(B7)        LEDG = ~LEDG;       // mode = 3;   else mode = 2;          // 触摸后开始工作 反之待机模式
    }
}
参考了零点追踪的触摸按键 但是发现貌似只适合单点触摸

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

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


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

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

HyunYong_7782 发表于 2025-11-2 11:10:20

还有个问题
这里的数字输入关闭 当我在恢复引脚状态的时候需要处理它吗

DebugLab 发表于 2025-11-2 20:35:20

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

HyunYong_7782 发表于 2025-11-3 02:05:15

DebugLab 发表于 2025-11-2 20:35
零点追踪用于没有按键按下时修正缓慢飘移的零点
零点追踪例程不支持长按,程序需要修改
由于按下按键时键值 ...

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

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

HyunYong_7782 发表于 2025-11-3 12:02:32

// 方案001-2


// 功能说明


// 头文件
#include "STC8Hxxx.h"


// 引脚定义
sbit LEDR = P3^4;
sbit LEDG = P3^5;
sbit LEDB = P3^6;


// 宏定义
#define MAIN_Fosc      30000000L                // 定义主时钟串口波特率 300 ~ 4800


// 声明
// 数组
u16 xdata TK_last;
u16 xdata TK_slope;
u16 xdata TK_Pressed;
u16      xdata TK_cnt;      // 按键计数值, 16位
u16      xdata TK_zero;      // 按键0点值, 16位
//                         K0   K1   K2   K3   K4   K5      K6    K7   K8   K9   K10   K11    K12    K13    K14    K15
// 触摸后的变化值
u16 code T_KeyPress={ 1300,2000,900,   800,   900,   1000,   1100, 1400,1000,1200,   900,1200,750,   900,   1300,1800};
// 16个键对应的状态, 0为未触摸,1为触摸      
u16 code T_KeyState={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// 函数
void delay_ms(u8 ms);
void TouchKey_Init(void);
void Timer2_Init(void);
void Ext_Init(void);
void IO_Sleep(void);
void IO_Wakeup(void);
// 变量
bit      B_TK_Lowpass;                // 低通允许, 1允许, 0禁止

u8 i;
u8 read_cnt;                        // 读次数
u8 mode = 0;                // mode 0:休眠/恢复模式 2:待机模式 3:工作模式

u16      j;
u16      KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放


// 函数模块
// ms延时函数-自适应主时钟
void delay_ms(u8 ms)
{
    u16 i;
      do
      {
                i = MAIN_Fosc / 10000;
            while(--i)      ;
    }
    while(--ms);
}

// 触摸初始化
void TouchKey_Init(void)
{
    u8 i, read_cnt;

    TSCHEN1 = 0x00;
    TSCHEN2 = 0x80;         // 启用TK15
    TSCFG1= (7<<4) + 6;
    TSCFG2= 1;
    TSRT    = 0x00;

    IE2 |= 0x80;
    delay_ms(50);

    B_TK_Lowpass = 0;
    for(read_cnt=0; read_cnt<10; read_cnt++)
    {
      TSCTRL = (1<<7) + (1<<6);
      delay_ms(50);
    }

    for(i=0; i<16; i++)
    {
      TK_zero = TK_cnt;
      TK_last = TK_cnt;
      TK_Pressed = 0;
    }

    B_TK_Lowpass = 1;
    KeyState = 0;
    TSTH15 = TK_zero - T_KeyPress/2;
}

// 20ms心跳
void Timer2_Init(void)                                                            // 20毫秒@30.000MHz
{
      AUXR &= 0xFB;                                                                  // 定时器时钟12T模式
      T2L = 0xB0;                                                                            // 设置定时初始值
      T2H = 0x3C;                                                                            // 设置定时初始值
      AUXR |= 0x10;                                                                  // 定时器2开始计时
      IE2 |= 0x04;                                                                  // 使能定时器2中断
}

// 外部中断0配置
void Ext_Init(void)
{
      IT0 = 0;                                                                        // INT0(P3.2)上升沿+下降沿中断
      EX0 = 1;                                                                        // 使能INT0中断
}

// IO休眠
void IO_Sleep(void)
{
    // 休眠模式
    P5M0 &= ~0x10; P5M1 |= 0x10;   P5IE &= ~0x10;
    P1M0 &= ~0x0b; P1M1 |= 0x0b;   P1IE &= ~0x0b;
    P3M0 = 0x00; P3M1 = 0xff;      P3IE &= ~0x7b;

    // 引脚状态
    LEDR = 0;   LEDG = 0;LEDB = 0;

    // 允许 TK15 唤醒 MCU,其它按键可根据需要修改
    TSCHEN1 = 0x00;                                                   // TK0~TK7 禁用唤醒
    TSCHEN2 = 0x80;                                                   // TK8~TK15 允许 TK15 唤醒
    TSCTRL= (1<<3) + (1<<2);                                          // 数字比较器 + 低功耗唤醒使能
}

// IO唤醒
void IO_Wakeup(void)
{
    // 恢复模式
    P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P3 0 31 33 34 35 36) 推挽输出
    P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
    P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出

    // 引脚状态
    LEDR = 0;   LEDG = 0;LEDB = 0;
}


// 主函数
void main(void)
{
    P_SW2 |= 0x80;                                                                // 允许访问扩展寄存器xsfr

    IO_Wakeup();                                                      // IO唤醒

    EA = 1;                                                             // 开总中断
    IRCDB = 0x10;                                                       // 配置唤醒
    IAP_TPS = 0x30;                                                   // 30Mhz晶振

    // 启动32k内部振荡器,用于触摸按键低功耗唤醒
    IRC32KCR = 0x80;
    while (!(IRC32KCR & 1));                                          // 等待时钟稳定
   
   
    // 函数初始化
    Ext_Init();                                                         // 外部中断0初始化
    TouchKey_Init();                                                    // 触摸按键初始化--No.1
    Timer2_Init();                                                      // 定时器2初始化--No.2
   

    // 主循环
    while(1)
    {
      // 休眠/恢复模式
      if(mode == 0)
      {
            IO_Sleep();                                                 // IO休眠

            // 寄存器初始化
            PCON = 0x02;                                                // MCU进入掉电模式

            IO_Wakeup();                                                // IO唤醒

            mode = 2;                                                   // 自动跳转待机
      }

      // 待机模式
      if(mode == 2)
      {
            LEDR = 1;
            LEDG = 0;
      }

      // 工作模式
      if(mode == 3)
      {
            LEDR = 0;
            LEDG = 1;
      }
    }
}


// 中断服务函数
// 外部中断0服务函数
void INT0_Isr(void) interrupt 0
{

}

// 描述: 触摸按键中断服务函数
void TKSU_ISR(void) interrupt TKSU_VECTOR
{
      u8      j;

      j = TSSTA2;

      if(j & 0x40)                                                            // 数据溢出, 错误处理(略)
      {
                TSSTA2 |= 0x40;                                                      // 写1清零
      }
      if(j & 0x80)                                                            // 扫描完成
      {
                j &= 0x0f;
                TSSTA2 |= 0x80;                                                      // 写1清零
                if(!B_TK_Lowpass)      TK_cnt = TSDAT;                              // 保存某个通道的读数      1.1us @24MHz
      // 保存某个通道的读数      1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500
                else    TK_cnt = (TK_cnt >> 1) + (TSDAT >> 1);                  
      }
}

// 定时器2中断(20ms心跳)
void Timer2_Isr(void) interrupt 12
{
    TSCTRL = (1<<7) + (1<<6);

    if(++read_cnt >= 3)
    {
      read_cnt = 0;
      j = KeyState;

      for(i=0; i<16; i++)
      {
            if (TK_cnt > TK_last)
                TK_slope = TK_cnt - TK_last;
            else
                TK_slope = TK_last - TK_cnt;
            TK_last = TK_cnt;

            if (TK_slope > 200)
                TK_Pressed = 1;
            else if ((TK_zero > TK_cnt) ?
                     ((TK_zero - TK_cnt) < T_KeyPress/4) :
                     ((TK_cnt - TK_zero) < T_KeyPress/4))
                TK_Pressed = 0;

            if (TK_Pressed)
            {
                if ((TK_zero - TK_cnt) >= T_KeyPress/2)
                  KeyState |=T_KeyState;
            }
            else
            {
                if (TK_zero > TK_cnt)
                  TK_zero--;
                else if (TK_zero < TK_cnt)
                  TK_zero++;
                if ((TK_zero - TK_cnt) <= T_KeyPress/3)
                  KeyState &= ~T_KeyState;
            }
      }
    }


    // 扫描触摸按键判断
    // 按下按键
    if (KeyState & T_KeyState)
    {
      mode = 3;                                                         // 工作模式
    }
    // 松开按键
    else
    {
      mode = 2;                                                         // 待机模式
    }
}



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

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

DebugLab 发表于 2025-11-4 06:28:55

HyunYong_7782 发表于 2025-11-3 02:05
也就是因为进行零点追踪导致无法使用长按
那么当按下时屏蔽零点追踪,只有在没按下时进行零点追踪这个触 ...

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

DebugLab 发表于 2025-11-4 06:30:38

HyunYong_7782 发表于 2025-11-3 12:02
现在这个程序的问题是
进入省电模式的时候 功耗达到了0.568mA 原来没有配置触摸按键唤醒的时候只有0.34 ...

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

HyunYong_7782 发表于 2025-11-4 10:16:48

DebugLab 发表于 2025-11-4 06:28
长按和零点追踪共存的例程暂无
外部中断是数字功能,且是输入,不能关闭数字输入
推挽输出可以关闭数字输 ...

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

HyunYong_7782 发表于 2025-11-4 10:19:42

// 方案001-2


// 头文件
#include "STC8Hxxx.h"


// 引脚定义
sbit LEDR = P3^4;
sbit LEDG = P3^5;
sbit LEDB = P3^6;
sbit base = P3^2;


// 宏定义
#define MAIN_Fosc        30000000L                // 定义主时钟串口波特率 300 ~ 4800


// 声明
// 数组
u16 xdata TK_last;
u16 xdata TK_slope;
u16 xdata TK_Pressed;
u16        xdata TK_cnt;        // 按键计数值, 16位
u16        xdata TK_zero;        // 按键0点值, 16位
//                         K0   K1   K2   K3   K4   K5      K6    K7   K8   K9   K10   K11    K12    K13    K14    K15
// 触摸后的变化值
u16 code T_KeyPress={ 1300,2000,900,   800,   900,   1000,   1100, 1400,1000,1200,   900,1200,750,   900,   1300,1800};
// 16个键对应的状态, 0为未触摸,1为触摸       
u16 code T_KeyState={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// 函数
void delay_ms(u8 ms);
void TouchKey_Init(void);
void Timer2_Init(void);
void Ext_Init(void);
void IO_Sleep(void);
void IO_Wakeup(void);
// 变量
bit        B_TK_Lowpass;                // 低通允许, 1允许, 0禁止
bit base_now;         // 充电底座状态 1为充电底座上, 0为非充电底座上

u8 i;
u8 read_cnt;                        // 读次数
u8 mode = 2;                // mode 0:休眠/恢复模式 2:待机模式 3:工作模式

u16        j;
u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放
u16 count;

// 函数模块
// ms延时函数-自适应主时钟
void delay_ms(u8 ms)
{
    u16 i;
        do
        {
                i = MAIN_Fosc / 10000;
          while(--i)        ;
    }
    while(--ms);
}

// 触摸初始化
void TouchKey_Init(void)
{
    u8 i, read_cnt;

    TSCHEN1 = 0x00;
    TSCHEN2 = 0x80;         // 启用TK15
    TSCFG1= (7<<4) + 6;
    TSCFG2= 1;
    TSRT    = 0x00;

    IE2 |= 0x80;
    delay_ms(50);

    B_TK_Lowpass = 0;
    for(read_cnt=0; read_cnt<10; read_cnt++)
    {
      TSCTRL = (1<<7) + (1<<6);
      delay_ms(50);
    }

    for(i=0; i<16; i++)
    {
      TK_zero = TK_cnt;
      TK_last = TK_cnt;
      TK_Pressed = 0;
    }

    B_TK_Lowpass = 1;
    KeyState = 0;
    TSTH15 = TK_zero - T_KeyPress/2;
}

// 20ms心跳
void Timer2_Init(void)                                                            // 20毫秒@30.000MHz
{
        AUXR &= 0xFB;                                                                    // 定时器时钟12T模式
        T2L = 0xB0;                                                                            // 设置定时初始值
        T2H = 0x3C;                                                                            // 设置定时初始值

    AUXR |= 0x10;                                                                    // 定时器2开始计时
    IE2 |= 0x04;                                                                    // 使能定时器2中断
}

// 外部中断0配置
void Ext_Init(void)
{
        IT0 = 0;                                                                        // INT0(P3.2)上升沿+下降沿中断
        EX0 = 1;                                                                        // 使能INT0中断
}

// IO休眠
void IO_Sleep(void)
{
    // 休眠模式
    P5M0 &= ~0x10; P5M1 |= 0x10;   P5IE &= ~0x10;
    P1M0 &= ~0x0b; P1M1 |= 0x0b;   P1IE &= ~0x0b;
    P3M0 = 0x00; P3M1 = 0xff;      P3IE &= ~0x7b;

    // 引脚状态
    LEDR = 0;   LEDG = 0;LEDB = 0;

    // 允许 TK15 唤醒 MCU,其它按键可根据需要修改
    TSCHEN1 = 0x00;                                                   // TK0~TK7 禁用唤醒
    TSCHEN2 = 0x80;                                                   // TK8~TK15 允许 TK15 唤醒
    TSCTRL= (1<<3) + (1<<2);                                          // 数字比较器 + 低功耗唤醒使能
}

// IO唤醒
void IO_Wakeup(void)
{
    // 恢复模式
    P3M0 = 0x7b; P3M1 = 0x84;                                           // P32 37 高阻输入      (P3 0 31 33 34 35 36) 推挽输出
    P5M0 |= 0x10; P5M1 &= ~0x10;                                        // (P54) 推挽输出
    P1M0 = (P1M0 & ~0x03) | 0x08; P1M1 = (P1M1 & ~0x08) | 0x03;         // (P10 11) 高阻输入    (P13) 推挽输出

    // 引脚状态
    LEDR = 0;   LEDG = 0;LEDB = 0;
}


// 主函数
void main(void)
{
    P_SW2 |= 0x80;                                                                // 允许访问扩展寄存器xsfr

    IO_Wakeup();                                                      // IO唤醒

    EA = 1;                                                             // 开总中断
    IRCDB = 0x10;                                                       // 配置唤醒
    IAP_TPS = 0x30;                                                   // 30Mhz晶振

    // 启动32k内部振荡器,用于触摸按键低功耗唤醒
    IRC32KCR = 0x80;
    while (!(IRC32KCR & 1));                                          // 等待时钟稳定
   
   
    // 函数初始化
    Ext_Init();                                                         // 外部中断0初始化
    TouchKey_Init();                                                    // 触摸按键初始化--No.1
    Timer2_Init();                                                      // 定时器2初始化--No.2
   

    // 主循环
    while(1)
    {
      if(base == 1)                                                   // 在充电底座上
      {
            base_now = 1;

            LEDR = 0;
            LEDG = 0;
      }
      else                                                            // 不在充电底座上
      {
            base_now = 0;

            // 休眠/恢复模式
            if(mode == 0)
            {
                IO_Sleep();                                                 // IO休眠

                // 寄存器初始化
                PCON = 0x02;                                                // MCU进入掉电模式

                IO_Wakeup();                                                // IO唤醒

                mode = 2;                                                   // 自动跳转待机
            }

            // 待机模式
            if(mode == 2)
            {
                LEDR = 1;
                LEDG = 0;
            }

            // 工作模式
            if(mode == 3)
            {
                LEDR = 0;
                LEDG = 1;
            }
      }
    }
}


// 中断服务函数
// 外部中断0服务函数
void INT0_Isr(void) interrupt 0
{

}

// 描述: 触摸按键中断服务函数
void TKSU_ISR(void) interrupt TKSU_VECTOR
{
        u8        j;

        j = TSSTA2;

        if(j & 0x40)                                                          // 数据溢出, 错误处理(略)
        {
                TSSTA2 |= 0x40;                                                        // 写1清零
        }
        if(j & 0x80)                                                          // 扫描完成
        {
                j &= 0x0f;
                TSSTA2 |= 0x80;                                                        // 写1清零
                if(!B_TK_Lowpass)        TK_cnt = TSDAT;                                // 保存某个通道的读数        1.1us @24MHz
      // 保存某个通道的读数        1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500
                else    TK_cnt = (TK_cnt >> 1) + (TSDAT >> 1);                  
        }
}

// 定时器2中断(20ms心跳)
void Timer2_Isr(void) interrupt 12
{
    if(base_now == 0)                                                   // 不在充电底座上才能判断触摸按键
    {
      // =========== 触摸按键数据读取 =========== //
      TSCTRL = (1<<7) + (1<<6);

      if(++read_cnt >= 3)
      {
            read_cnt = 0;
            j = KeyState;

            for(i=0; i<16; i++)
            {
                if (TK_cnt > TK_last)
                  TK_slope = TK_cnt - TK_last;
                else
                  TK_slope = TK_last - TK_cnt;
                TK_last = TK_cnt;

                if (TK_slope > 200)
                  TK_Pressed = 1;
                else if ((TK_zero > TK_cnt) ?
                         ((TK_zero - TK_cnt) < T_KeyPress/4) :
                         ((TK_cnt - TK_zero) < T_KeyPress/4))
                  TK_Pressed = 0;

                if (TK_Pressed)
                {
                  if ((TK_zero - TK_cnt) >= T_KeyPress/2)
                        KeyState |=T_KeyState;
                }
                else
                {
                  if (TK_zero > TK_cnt)
                        TK_zero--;
                  else if (TK_zero < TK_cnt)
                        TK_zero++;
                  if ((TK_zero - TK_cnt) <= T_KeyPress/3)
                        KeyState &= ~T_KeyState;
                }
            }
      }
      // =========== 触摸按键数据读取 =========== //

      // ========== 触摸按键扫描判断 ========== //
      // 按下按键
      if (KeyState & T_KeyState)
      {
            count = 0;
            mode = 3;                                                         // 工作模式
      }
      // 松开按键
      else
      {
            count++;
            if(count >= 150)
            {
                count = 0;
                mode = 0;                                                       // 进入休眠
            }
            else
            {
                mode = 2;                                                       // 待机模式
            }
      }
      // ========== 触摸按键扫描判断 ========== //
    }
}


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

HyunYong_7782 发表于 2025-11-4 10:21:46

DebugLab 发表于 2025-11-4 06:30
300多μA和500多μA好像都不太正常,检查省电模式时IO是否有电流,IO要设置为没有电流的状态,注意外部的 ...

我现在用的STC8H1K08T
会不会是P54不支持关闭数字输入引脚所导致的
页: [1] 2
查看完整版本: 触摸按键零点追踪长按问题