找回密码
 立即注册
查看: 26|回复: 8

关于触摸按键唤醒阈值问题

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-06-27 13:45:29
已绑定手机

4

主题

39

回帖

170

积分

注册会员

积分
170
发表于 昨天 13:45 | 显示全部楼层 |阅读模式
用STC8H1K08T做了个触摸唤醒显示的模块
我该怎么更改程序,让系统自动去更新零点呢?
以下是程序,逻辑是:上电初始化零点后显示,N秒后关闭显示屏单片机进入睡眠,手指触摸后唤醒单片机重新显示。




#define yuzhi 900

u16        xdata TK_cnt[16];        // 按键计数值, 16位
u16        xdata TK_zero[16];        // 按键0点值, 16位
u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放
bit        B_KeyPress=1;

void main (void)
{       
        u8 i=0;
        u8 count1 = 0;
        u8 count2 = 0;
        u8 temp=0;
        u8 flag=1;
        u32 PowerOnTime=0;
       
        ADC_NTCInit();
        TouchKey_Init();
//        USER_ISPInit();
        LED_Init();
        //ADC 触摸按键等GPIO初始化
        P1M0 = 0x40; P1M1 = 0x30;  //P1.4高阻 P1.5高阻 P1.6推挽
       
        display_single_digit(0,0,0);

        while(1)
        {
               
                if(B_KeyPress==1)
                {
                        TSCTRL = (1<<3) + (1<<2) + 0;       
                        //关闭触摸模块, 允许16位数字比较器, 允许低功耗唤醒。
                        //B7: TSGO,  B6: SINGLE,  B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
                        //0000 1100
                        TR0 = 1;
                        ET0 = 1;
                        ADC_ON;
                       
                        delay_ms(10);
                        temp=(u8)NTC_Temperature();
                                               
                        count1=(u8)(temp/10%10);
                        count2=(u8)(temp%10);
                        delay_ms(10);
                        display_single_digit(0,count2,1);
                        display_single_digit(1,count1,0);
                        delay_ms(10);
                        ADC_OFF;
                        B_KeyPress=0;
                        flag=0;
                }
//                for(i=0; i<10; i++)        //扫描10次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
//                {
////                TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均
//                        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 无平均 1100 0000
////                        delay_ms(1);        //延时一下, 等待扫描完成
//                }
//               
//                TK_zero[4] = TK_cnt[4];        //保存0点
//                TSTH04 = TK_zero[4]  -  yuzhi/2;        //设置唤醒门槛值 = 0点(未触摸)值 - 触摸变化值/2
//               
                PowerOnTime++;
                delay_ms(1);
               
//                TSTH04 = TSDAT  -  10000/2;        //设置唤醒门槛值 = 0点(未触摸)值 - 触摸变化值/2
               
                if(PowerOnTime>=1000)
                {
                        //TSCTRL=00001100  
//                        TSCTRL = (1<<3) + (1<<2) + 0;        //关闭触摸模块, 允许16位数字比较器, 允许低功耗唤醒。 B7: TSGO,  B6: SINGLE,  B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP

                        TR0 = 0;                //先关闭数码管定时器,再配置高阻
                        ET0 = 0;

                        P1M0 = 0x00; P1M1 = 0x20;   //P15配置为高阻模式 并置为0
                        P3M0 = 0x7c; P3M1 = 0x00;         //P32 P33 P34 P35 P36配置为推挽输出,并置为0
                        P5M0 = 0x00; P5M1 = 0x00;                
//                        P15=1;         //不能拉低,不然电池会往里面灌电流       
                        P32=0;P33=0;P34=0;P35=0;P36=0;
                       
                        ADC_CONTR=0x7f; //关闭ADC电源
                       
                                _nop_();
                                _nop_();
                        PCON |= 0x02;        //睡眠
                                _nop_();
                                _nop_();
                                _nop_();
                                _nop_();
                                _nop_();
                                _nop_();
                                _nop_();
//                        delay_ms(20); //消抖
                       
                        //初始化一下触摸按键 ADC等GPIO
                        P1M0 = 0x40; P1M1 = 0x30;  //P1.4高阻 P1.5高阻 P1.6推挽
                               
                        ADC_CONTR = 0x85; //唤醒后需要重新使能一下ADC转换

//                        TSCHEN1 = 0x10;  //唤醒后重新使能一下触摸按键
//                        TSCHEN2 = 0x00;
//                        TR0 = 1;
//                        ET0 = 1;
                       
                        flag=1;
                        PowerOnTime=0;
                       
//                        TR0 = 1;
//                        ET0 = 1;
//                       
                        TSCTRL = (1<<7) + (1<<3) + (1<<2) + 0;       
                //开始扫描, 无平均,
                // B7: TSGO,  B6: SINGLE,  B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
                //1000 1100
                }
        }
}


void TouchKey_Init(void)
{
        u8        i;
       
        P_SW2 |= 0x80;                //允许访问扩展寄存器xsfr
               
//  P1M0 = 0x00; P1M1 = 0x10;  //P1.4为高阻
       
  // 开启触摸按键功能
        TSCHEN1 = 0x10;              //使能触摸按键
        TSCHEN2 = 0x00;        //
        TSCFG1 = (5<<4) + 3;  //B6~B4:开关电容工作频率 = fosc/(2*(TSCFG1[6:4]+1)), B2~B0:放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最好大于等于3(1000)      
        //0111 0110
        TSCFG2 = 0x00;        // 配置触摸按键控制器的内部参考电压(AVCC的分压比)
        //3/4AVCC
        TSRT = 0x00;                                  //没有LED分时扫描
        TSWUTC =55;          //1ms扫描一次        唤醒频率 = F32K/(32*8*TSWUTC[7:0]) = 128/TSWUTC[7:0] Hz, TSWUTC = 1~255
        IE2 |= 0x80;                     //允许触摸按键中断
       
        EA = 1;                                //允许全局中断
       
        IRC32KCR = 0x80; //启用内部时钟32K IRC
        while (!(IRC32KCR & 1));                    //等待时钟稳定
       
        delay_ms(10);                //延时一下
       
        for(i=0; i<10; i++)        //扫描10次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
        {
//                TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均
                TSCTRL = (1<<7) + (1<<6);                //开始扫描, 无平均 1100 0000
                delay_ms(20);        //延时一下, 等待扫描完成
        }

        TK_zero[4] = TK_cnt[4];        //保存0点

       
        TSTH04 = TK_zero[4]  -  yuzhi/2;        //设置唤醒门槛值 = 0点(未触摸)值 - 触摸变化值/2
       
        WakeUpkey  = 0;
//        B_KeyPress = 0;
       
}

//========================================================================
// 函数: void        TKSU_ISR(void) interrupt TKSU_VECTOR
// 描述: 触摸按键中断服务函数  扫描完成后或者数据溢出后进入本次中断
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-11
// 备注:
void        TKSU_ISR(void) interrupt TKSU_VECTOR
{
        u8        j;

        j = TSSTA2;   //触摸按键状态寄存器

        if(j & 0x40)        //数据溢出, 错误处理(略)
        {
                TSSTA2 |= 0x40;        //写1清零
        }
        if(j & 0x80)        //扫描完成  判断 TSIF位
        {
                TSSTA2 |= 0x80;                //写1清零
                j &= 0x0f;
                WakeUpkey = j;
                B_KeyPress = 1;
                TK_cnt[j] = TSDAT;        //保存某个通道的读数
        }
}

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-06-27 13:45:29
已绑定手机

4

主题

39

回帖

170

积分

注册会员

积分
170
发表于 昨天 13:48 | 显示全部楼层
一旦初始化设置好零点,只要装配后,就会一直触发唤醒。

点评

必须装配后校准零点,装配操作会改变附近材料的介电常数 https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=18768&pid=173546 出厂组装好不触摸上电校准一次存EEPROM 使用过程中每次上电都读取一  详情 回复 发表于 昨天 13:58
回复 支持 反对

使用道具 举报 送花

3

主题

540

回帖

-209

积分

等待验证会员

积分
-209
发表于 昨天 13:48 | 显示全部楼层
关于触摸按键唤醒阈值问题,使用STC8H1K08T单片机实现触摸唤醒显示模块时,若希望系统在每次唤醒后自动更新零点(即重新校准触摸按键的基准值),需对程序逻辑进行适当调整。以下为具体分析与建议:

首先,当前程序逻辑为:上电初始化零点并显示,N秒后关闭显示屏进入睡眠,触摸唤醒后重新显示。该逻辑中,零点仅在初始化阶段被设定一次,未考虑环境变化或使用过程中零点漂移的问题。

为实现自动更新零点功能,应在每次唤醒后重新采集触摸按键的原始数据,并更新TKzero数组中的基准值。这可以通过在触摸唤醒中断处理函数中添加零点更新逻辑来实现。

具体步骤如下:

1. 修改触摸唤醒中断处理函数:在检测到触摸事件后,立即执行零点更新操作。可调用TouchKeyUpdateZero()函数,该函数负责重新采集所有按键的计数值并更新TKzero数组。

2. 优化主循环逻辑:确保在唤醒后能够正确执行零点更新,并根据新的零点值重新计算触摸状态。同时,应避免在零点更新过程中误触发按键状态。

3. 增加延时机制:在零点更新前加入短暂延时,以确保触摸传感器稳定,避免因瞬时波动导致的误差。

4. 调试与验证:通过实际测试验证零点更新效果,确保系统在不同环境条件下均能准确识别触摸输入。

综上所述,通过在触摸唤醒中断中添加零点更新逻辑,并优化主循环处理流程,可以有效提升系统的稳定性和准确性。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:480
  • 最近打卡:2025-06-28 00:00:59
已绑定手机

80

主题

5214

回帖

9305

积分

超级版主

DebugLab

积分
9305
发表于 昨天 13:58 | 显示全部楼层
STC*** 发表于 2025-6-27 13:48
一旦初始化设置好零点,只要装配后,就会一直触发唤醒。

必须装配后校准零点,装配操作会改变附近材料的介电常数
比较值不能是固定值,要根据环境动态调整
一直唤醒且超过长按超时时间,就认为是环境有固定的改变,把当前值当做零点,动态校准,零点跟踪
https://www.stcaimcu.com/forum.p ... id=18768&pid=173546
出厂组装好不触摸上电校准一次存EEPROM
使用过程中每次上电都读取一次实际值,和出厂值比较,如果没有触摸,就用上电值代替出厂值(RAM中代替,EEPROM中的出厂值永不擦除)
上电过程中使用零点跟踪算法
触摸按键程序:
https://www.stcaimcu.com/forum.p ... Dg5Mzg3MnwxfDQ4MzU=

DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2025-06-27 08:53:15
已绑定手机

40

主题

2078

回帖

7159

积分

论坛元老

积分
7159
发表于 昨天 14:18 | 显示全部楼层
可参考例子进行追零,如果零值小于当前值则快速追零:
截图202506271416374640.jpg

如果零值大于当前值,则缓慢跟踪:
截图202506271417583180.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-06-27 13:45:29
已绑定手机

4

主题

39

回帖

170

积分

注册会员

积分
170
发表于 昨天 14:20 | 显示全部楼层
乘风*** 发表于 2025-6-27 14:18
可参考例子进行追零,如果零值小于当前值则快速追零:

好的,我移植一下
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-06-27 13:45:29
已绑定手机

4

主题

39

回帖

170

积分

注册会员

积分
170
发表于 昨天 14:21 | 显示全部楼层
乘风*** 发表于 2025-6-27 14:18
可参考例子进行追零,如果零值小于当前值则快速追零:

这个还需要把某些键值保存到EEPROM中吗
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2025-06-27 08:53:15
已绑定手机

40

主题

2078

回帖

7159

积分

论坛元老

积分
7159
发表于 昨天 14:24 | 显示全部楼层
STC*** 发表于 2025-6-27 14:21
这个还需要把某些键值保存到EEPROM中吗

每个按键的判断阈值可提前测好,用常量保存的Flash里面。那就可以不用EEPROM保存。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-06-27 13:45:29
已绑定手机

4

主题

39

回帖

170

积分

注册会员

积分
170
发表于 昨天 14:56 | 显示全部楼层
乘风*** 发表于 2025-6-27 14:24
每个按键的判断阈值可提前测好,用常量保存的Flash里面。那就可以不用EEPROM保存。 ...

就是我这模块需要休眠的,那我在手指按下唤醒后去进行零点追踪,那会不会出现零点会改变到我不管怎么接触都无法触发的情况,毕竟它无法在休眠的情况下自动追踪零点呀
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-6-28 17:29 , Processed in 1.113389 second(s), 104 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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