电子DIY小家 发表于 2024-3-15 16:04:06

8H4K64TLCD驱动段码LCD屏教程(二)触摸按键

8H4K64TLCD驱动段码LCD屏教程(一)点亮段码LCD屏
8H4K64TLCD驱动段码LCD屏教程(二)触摸按键

前言:
   上一章《STC8H4K64TLCD驱动段码LCD屏教程(一)点亮段码LCD屏》
(链接:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=7070)

主要讲了怎么去点亮段码屏,当然这颗芯片不止段码驱动这一个亮点,还有自带的触摸按键驱动。
实际在用的时候触摸也是非常好用的功能之一,下面开始介绍触摸按键功能。

一、原理分析
   
    参考手册说明,如上图,其实触摸的本质类似ADC,只是ADC是侦测电压或电流,而出米的本质是检测电容大小,当然虽然实现的原理类似,但是我们一般都会用最简单好用的办法,能用硬件实现的就绝对不会用软件去做,所以这一节我们要重点讲触摸,当然正式开始前还是要分析下电路配置的

   
    这里手册给出了参考电路图,这里讲下重点,注意听:
    1.C为电容灵敏度调节电容,如果对环境要求较高一定要用低温漂的独石或涤纶电容等!感觉触摸不灵敏可以调小电容,建议容值10nf-47nf之间
    2.R为ESD保护电阻,和电容均要靠近IC,电阻组织推荐470Ω到1KΩ之间
    3.如果增加了亚克力等面板之后触摸不灵敏,可以尝试增大弹簧的顶面和放大弹簧之间的间距,触摸走线避免从别的弹簧底下穿过
    4.如果没有按下的时候,触摸数值波动很大,检查下触摸走线边上是否存在功率型器件(开关电源)或电感等感性负载
    5.最终触摸按下和抬起的变化值要在5%以上为宜


二、寄存器分析


手册告诉我们,要作为普通的触摸按键需要配置这些寄存器
1.TSCHEN1和TSCHEN2设置,这个寄存器主要是将对应的触摸按键的引脚配置为触摸输入,不设置的话他就是普通的IO口



2.TSRT判断时候开始LED分时复用,我们这个信号没有LED驱动,只有LCD驱动,所以不用管,直接0即可



3.配置开关频率SCR,放电时间,以及比较电压。一般来说开管电容工作频率低一点抗干扰性会稍微强一点,但是伴随而来的就是灵敏度会降低,这里我们对这个没有要求,直接选择最大的放电时间,也就是工作频率最低的档位即可,参考电压也选择最高的。



4.配置SINGLE来选择是否连续,以及单通道采样次数和等待时间




这里对功耗什么的无要求,为了程序方便处理,这里就可以直接一直自动运行,没必要单次扫描。这里没有什么别的外部干扰源,可以直接就单次检测了,实际上做产品的时候这些可以根据自己的需要适当修改。

5.数字比较功能,这个功能的话是往对应的通道里写入比较阈值,让硬件自动去判断也没有比这个数值小,小于这个数值硬件自动置位标志位,这个功能在低功耗下比较常用,实际在这里用处不大,这里先用普通的软件比较(低功耗章节再讲这个功能)



6.TSGO置位开始扫描(注意:以上部分配置必须要在TSGO没有写1之前设置,所以以防万一TSGO放最后在设置即可)



7.SINGEL为1时硬件扫描完成自动清除TSGO并结束扫描,这里因为SINGEL设置了0,是连续扫描的所以不用管
8.想停触摸扫描的话讲TSGO置0即可。(进入低功耗前必须关闭)
9.最后还要在补充一点,在触摸通道需要配置为高阻输入!

三、代码编写
P1n_pure_input(0x38);      //Touch Key设置为高阻
      P5n_pure_input(0x10);

      TSRT = 0x00;                //没有LED分时扫描
      TSCHEN1 = 0x3c;      //TK00~TK07
      TSCHEN2 = 0x00;      //TK08~TK15
      
      TSCFG1= (7<<4) + 3;      //开关电容工作频率 = fosc/(2*(TSCFG1+1)), 放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最小3
      TSCFG2= 2;                              //配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)1(1/2)2(5/8)3(3/4)
      TSCTRL = 0xA0;                        //开始自动扫描, 无平均, B7: TSGO,B6: SINGLE,B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP

      IE2 |= 0x80;                        //使能触摸中断
    EA = 1;
   
      TSCTRL = 0xA0;    最后触摸按键配置完就几行代码,非常的简单,就是上述的那些配置,这里就不在描述这些了。主要讲下这个触摸按键的阈值怎么设置;
    因为上面其实讲过,这个触摸的数值按下之后会有5%的差值,实际上可以直接在开机之后自动采集一次,然后直接取0.03*该数值作为这个通道的出发比较阈值,这个是最方便的,当然也可以用软件取抓取按下和抬起的时候的数值然后自动去计算阈值,当然方法很多,这里为了方便大家理解直接用了最简单的一个办法,就是采集出每个通道的常态数值(采集八次取平均),然后通过这个数值减去1500的值作为比较阈值,代码如下
    for(i=0;i<16;i++)
      TK_zero=0;      
    while(j<8)
    {
      if( B_ReadKeyOk )
      {
            for(i=0;i<16;i++)
                TK_zero += TK_cnt;
            B_ReadKeyOk = 0;
            j++;
      }
      delay_ms(50);
    }
    for(i=0;i<16;i++)
    {
      TK_zero=(TK_zero>>3);
//      printf("%u\t",(u16)TK_zero);
      T_KeyCmp = 1500;
    }    上述代码就已经实现了触摸的初始化,然后就可以编写程序来实时检测这个按键也没有按下了
void KEY_Deal(void)                        //检查所有的按键状态 10ms执行一次
{
      u8 i = 0;
   
//    printf("(%u,%u,%u)\r\n",(u16)TK_cnt,(u16)TK_cnt,(u16)TK_cnt);
   
      for(i=0;i<16;i++)                                        //循环8次 i的取值范围是0-7代表了P30-P37的状态查询
      {
                if( TK_cnt< (TK_zero-T_KeyCmp))                        //持续按下,变量+1
//                if( TK_cnt> (TK_zero+T_KeyCmp))                        //持续按下,变量+1                        
                {
                        if( Count<60000 )
                              Count ++;                        //按键按下,这个计数变量+1
                }
                else                                                      //按键松开了,变量清0
                {
                        if( Count>0 )                        //如果这个变量是按下过的
                        {
                              LastState |= (1<<i);      //这个变量相应的标志位置位
                        }
                        else
                        {
                              LastState &= ~(1<<i);      //这个变量相应的标志位清0
                        }
                        Count = 0;                              //按键按下,这个计数变量清0
                }
      }
}这里循环检测了16次(触摸最大16个通道,用到哪个打开哪个即可),TK_cnt为该通道的当前数值,这个会自动在中断里实时更新的,TK_zero是该通道没有按下时候的零点基准,T_KeyCmp为该通道的比较差值,所以TK_cnt(当前值)小于 TK_zero-T_KeyCmp(差即为阈值)时就是按键按下了,否则及时按键松开了,当按键按下时一个变量连续计数,计数到3次为短按,松开了就立马清0,这个按键逻辑如果不理解的haul可以参考我论坛的另一篇帖子(链接:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=7023)
最终按键状态的检测函数如下
u8 KEY_ReadState(u8 keynum)      //读取指定的按键的状态 10ms执行一次
{
      if( Count>0 )                                        //按键是按下的各种状态返回
      {
                if( Count<3 )                              //按下<30ms 返回消抖状态
                {
                        return KEY_FILCKER;
                }
                else if( Count==3 )                        //按下正好30ms 返回单击
                {
                        return KEY_PRESS;
                }
                else if( Count<150 )                //按下不到3000ms 返回单击结束
                {
                        return KEY_PRESSOVER;
                }               
                else if( Count==150 )                //按下正好3000ms 返回长按状态
                {
                        return KEY_LONGPRESS;
                }      
                else                                                                //长按结束
                {
                        return KEY_LONGOVER;
                }                        
               
      }
      else                                                                        //按键已经松开了,返回各种状态
      {
                if( LastState &( 1<<keynum ) )                //按键之前按下过
                {
                        return KEY_RELAX;               
                }
                else                                                                //按键之前没有按下
                {
                        return KEY_NOPRESS;
                }
      }
}

四、最终程序
    while(1)
    {
                KEY_Deal();      
//               
                if( KEY_ReadState(2)==KEY_PRESS )                //模式设置按钮
                        LED_R = !LED_R;
               
                if( KEY_ReadState(3)==KEY_PRESS )                //模式设置按钮
                        LED_G = !LED_G;               
               
                if( KEY_ReadState(5)==KEY_PRESS )                //模式设置按钮
                        LED_B = !LED_B;      
               
               
                dat = TK_cnt;
//               
                for( i=0;i<6;i++ )
                {
                        LCD_load(6-i,dat%10);
                        dat /=10;
                }
                LoadToLcd();
                delay_ms(10);
      
      }最终测试的主循环代码如上,第一个按键按下的时候,背光灯红灯取反,第二个按键按下的时候绿灯取反,第三个按键按下的时候,蓝灯取反,并在数字上显示这一路的触摸数值~
完整代码可以在群文件下载,最终发货版的代码就是这个带触摸的代码{:5_284:}有任何问题可以下面留言交流~

需要买成品的可以直接从如下链接购买:
https://item.taobao.com/item.htm ... 97.7.40763d46EWIlaN


段码LCD及触摸按键演示程序-20240525:



梁工 发表于 2024-3-18 17:16:11

触摸按键的处理,很讲究经验:

首先是排板,必须尽量减小分布电容、尽量避免别的信号影响触摸读数,
                   尽量减小相邻键的相互影响。

其次是产品装配要注意减小分布电容和周围信号的影响。

然后是软件处理,这个非常重要。

分布电容无处不在,大的分布电容,会让你的按键灵敏度减小,
铜箔走线20cm跟2cm比,分布电容大得多,灵敏度会低很多。
手指按上去后,电容改变通常只有0点几pF,如果分布电容大,
灵敏度会很低的。

干扰(空间射频干扰、传导干扰、感应干扰)无处不在,干扰会让触摸按键读数抖动不停,
周期干扰可以平均值滤波(或一阶低通滤波)减弱抖动。

产品工作后,或工作时间长后,0点(即不按按键时的读数)会有比较大的变化,
甚至超过10%(即超过按键的幻化),所以0点跟踪是必须的。

一般产品上电时,先检测一下按键,并将此时的读数作为起始的0点。
当检测到按键读数值急剧变大,则认为是释放按键,此时要重新快速判断是否要重新定0点,
比如按着键上电,之后释放再按,比如能重新定0点并识别到按键动作。

由于有缓慢的0点跟踪,一般触摸按键支持的长按是有时间限制的,比如最长30秒。

NTC 发表于 2024-3-16 22:51:34

先占个楼,有问题再提

xxxevery 发表于 2024-3-18 18:36:21

不知溅了水的情况能否很好识别出来

Anijin 发表于 2024-3-20 21:06:30

触摸按键的处理确实需要很多经验,产品定型需要一个较长时间的沉淀。整个产品测试效果较为稳定,瑕不掩瑜。

dnajx 发表于 2024-4-3 09:56:16

有机会试一下

zys0797 发表于 2024-5-11 21:21:43

麻烦楼主分享下整个项目代码。。新手小白没有研究透。

神农鼎 发表于 2024-5-27 12:57:34

zys0797 发表于 2024-5-11 21:21
麻烦楼主分享下整个项目代码。。新手小白没有研究透。

见顶楼附件,已放最新演示程序

ryj870925 发表于 2024-6-5 10:39:47

学习了,有几个字需要改一下{:lol:}

hua7718534 发表于 2024-7-12 10:31:01

静止时间长点,触摸时会不会一直在执行。相当于数码管一直闪。
页: [1]
查看完整版本: 8H4K64TLCD驱动段码LCD屏教程(二)触摸按键