数码之家

 找回密码
 立即注册
搜索
查看: 4978|回复: 7

[C51] STC8H单片机硬件触摸按键之键值的获取方法

[复制链接]
发表于 2023-6-19 21:08:41 | 显示全部楼层 |阅读模式
本帖最后由 慕名而来 于 2023-6-19 21:08 编辑

STC8H***T、ST8H***T**型号的单片机内部带有触摸按键功能,经过一段时间的玩耍感觉挺有趣的,对此感兴趣的新手朋友可以弄个板子玩一玩,我在刚刚上手这个功能时也曾经在这里分享过一些不成熟的经验,
STC8H单片机硬件触摸按键的简单实现(1)——官方例程与配置软件
https://www.mydigit.cn/forum.php?mod=viewthread&tid=353279&fromuid=1505079
(出处: 数码之家)
STC8H单片机硬件触摸按键的简单实现(2)——代码分享
https://www.mydigit.cn/forum.php?mod=viewthread&tid=353464&fromuid=1505079
(出处: 数码之家)


--------------文归正题------------
单片机硬件触摸按键的实现就配置寄存器而言对于玩51单片机的人来说都是毫无难度的,无外乎就是按键对应通道的使能、按键电容充电频率的设置、放电时间的设置、参考比较电压的配置,至于工作原理此不赘述可详见数据手册或百度。
触摸按键的实现就程序而言最关键应该就是键值的获取,它由两个值组成即按键没有按下时的键值和按键按下时的键值,而这两个键值受PCB布局、按键面板材质以及最终制成品结构影响需要在整机装配完成的情况下进行测试,在上述链接的贴(1)中曾经提到了官方提供的按键参数测试软件,但因为当时我没有找到合适的配套例程所以没能玩明白,这里给出这个例程,你可以到STC新的官网参照下图按图索骥就能获得了:




这个软件包里既有配套的上位机软件也有测试用的代码,这个代码在使用时需要注意以下几点,一是烧录到你的芯片的时候一定要将时钟(新型STC单片机基本上都淘汰了外部晶振)设置为22.1184MHz。二是打开上位机软件时一定要将串口号码设置成与STC-ISP烧录软件中的串口号码一致,波特率要设置为115200。另外,软件包里还有一个上位机软件的使用说明,打开看一下就很容易操作了,烧录好了软件后打开上位机串口并点击软件中的“触摸数据”标签并设置好按键通道号并点击读“取数据”,此时如果软件下方表格中开始出现红色波形图了就说明一切可以正常操作了,接下来的操作就请详读说明书好了。
至此,就可以获取触摸键值了,如果你使用STC的例程中的按键判断模式来改编自己的代码的话,以上这些就够用了,但是本文如果到此结束则就有了抄书的嫌疑了,下面将我习惯使用的方法分享给大家,它是我用另一个官方例程实现的,没有使用官方的上位机软件,而是通过STC-ISP软件中的串口助手实现的,就是指定某个按键后在串口助手中发送改该按键的号码(16个按键编号为0-9-A-F不分大小写)就可以同时收到该键的键值,如果不触摸按键发送键号则得到是不触摸的键值,如果触摸按键并同时发送键号则得到的是触摸后的键值,每种状态发送10次就可以得到各自10个数据,各取平均值后就得到了一个按键的两个键值,如果只是DIY制作,我觉得这个方法看得见摸得着比较巴适。
用到的测试代码如下:使用时请详细阅读代码中的“功能说明”


  1. #include <STC8H.h>
  2. #define MAIN_Fosc                24000000L        //定义主时钟  串口波特率 300 ~ 4800
  3. /*************        功能说明        **************
  4. //代码源自STC官方例程
  5. 工程文件:TouchKey-V10-中断读取.c        

  6. 读取16个触摸按键

  7. 串口是用来读取触摸按键值, 不是必须的, 与触摸按键无关.
  8. 串口设置: 115200, 8, n, 1.
  9. 发送区以文本模式发送0~9与A~F(或a~f)键号
  10. 接收区以文本模式接收返回按键0~15(0~F)的键值.

  11. 注:
  12. 串口助手设置波特率为115200
  13. 1.串口助手“打开串口”后发送一个键号即可看到返回的该键未触摸的键值。
  14. 2.按住某个按键并发送键号后即可看到返回的该键触摸后的键值。

  15. 比如按键0, 不触摸时发送字符0, 返回不触摸的值, 然后触摸按键0时发送字符1, 返回触摸时的值,  两者差值就是下面表格T_KeyPress[]里的值(大约即可), 用于判断按键按下还是释放.

  16. K00=20143    未触摸读数
  17. K00=18527    已触摸读数

  18. 则20143-18527=1616, 此值就是T_KeyPress[0]的值1600, 接近即可.

  19. 所以, 用户将产品安装好之后, 读出每个键的未触摸与已触摸的读数, 计算出差值写于T_KeyPress[]中即可.
  20. 差值是未触摸的值的5%以上为合格, 达到10%以上为非常优秀. 占比小则灵敏度太低, 请重新审视硬件设计.


  21. 按键定义:
  22. P3.5 --> OLED SCL, P3.7 --> OLED SDA,  P3.0 --> RXD, P3.1 --> TXD.

  23. P1.0-->TK0,  P1.1-->TK1, P5.4-->TK2, P1.3-->TK3, P1.4-->TK4,  P1.5-->TK5, P1.6-->TK6, P1.7-->TK7,
  24. P5.0-->TK8,  P5.1-->TK9, P5.2-->TK1, P5.3-->TK1, P0.0-->TK1,  P0.1-->TK1, P0.2-->TK1, P0.3-->TK1,


  25. ******************************************/

  26. /*************        本地变量声明        **************/

  27. u16        xdata TK_cnt[16];        // 按键计数值, 16位
  28. u16        xdata TK_zero[16];        // 按键0点值, 16位
  29. u16        KeyState;                        // 按键状态, 每个bit对应一个键, 1为按下, 0为释放
  30. u8        read_cnt;                        // 读次数
  31. bit        B_TK_Lowpass;                // 低通允许, 1允许, 0禁止

  32. u8        cmd;        //串口命令
  33. bit        B_TX1_Busy;        // 串口发送忙标志

  34. /*************        本地函数声明        **************/
  35. void        DisplayRTC(void);
  36. void          delay_ms(u8 ms);

  37. void        UART1_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4
  38. void         UART1_PrintString(u8 *puts);
  39. void         UART1_TxByte(u8 dat);
  40. void        ReturnValue(u8 channel, u16 value);

  41. /****************  外部函数声明和外部变量声明 *****************/


  42. u16 code T_KeyState[16]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
  43. u16 code T_KeyPress[16]={1600,2200,1100,1200,1100,1400,1300,1600,1200,1500,1200,1500,900,1100,1300,1800};


  44. /********************* 主函数回调函数 *************************/
  45. void main(void)
  46. {
  47.         u8        i;
  48.         u16        j;

  49.         P1n_pure_input(0xff);        //设置所有触摸键的O为高阻
  50.         P5n_pure_input(0x0f);
  51.         P0n_pure_input(0x0f);

  52.         P_SW2 |= 0x80;                //允许访问扩展寄存器xsfr
  53.         EA = 1;

  54.         UART1_config(115200UL, 1, 0);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4
  55.         UART1_PrintString("STC8H系列触摸按键测试程序!\r\n");

  56.         TSCHEN1 = 0xff;                //TK0~TK7
  57.         TSCHEN2 = 0xff;                //TK8~TK15
  58.         TSCFG1  = (7<<4) + 6;        //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)
  59.         TSCFG2  = 1;                //B1~B0:配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)  1(1/2)  2(5/8)  3(3/4)
  60. //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, B7: TSGO,  B6: SINGLE,  B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
  61.         TSRT = 0x00;                //没有LED分时扫描
  62.         IE2 |= 0x80;                //允许触摸按键中断
  63.         
  64.         
  65.         delay_ms(50);                //延时一下

  66.         B_TK_Lowpass = 0;        //禁止低通滤波
  67.         for(read_cnt=0; read_cnt<10; read_cnt++)        //扫描10次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
  68.         {
  69.         //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均
  70.                 TSCTRL = (1<<7) + (1<<6);                //开始扫描, 无平均
  71.                 delay_ms(50);        //延时一下, 等待扫描完成
  72.         }
  73.         for(i=0; i<16; i++)               
  74.         TK_zero[i] = TK_cnt[i];        //保存0点
  75.         B_TK_Lowpass = 1;        //允许低通滤波
  76.         KeyState = 0;
  77.         read_cnt = 0;
  78.         while (1)
  79.         {
  80.                 TSCTRL = (1<<7) + (1<<6);                //开始扫描, 无平均
  81.                 delay_ms(20);                //延时一下, 根据实际扫描速度调整
  82.                
  83.                 if(++read_cnt >= 3)
  84.                 {
  85.                         read_cnt = 0;
  86.                         j = KeyState;
  87.                         for(i=0; i<16; i++)
  88.                         {
  89.                         //        if((TK_zero[i] >= TK_cnt[i]) && ((TK_zero[i] - TK_cnt[i]) >= 300))        ShowValue(i,TK_zero[i] - TK_cnt[i]);        //6ms  有键按下则显示差值
  90.                         //        else        ShowValue(i,TK_cnt[i]);        //无键按下则显示读数

  91.                                 if(TK_zero[i] > TK_cnt[i])        //0点值比当前值大, 则键按下, 缓慢0点跟踪
  92.                                 {
  93.                                         TK_zero[i]--;        //缓慢0点跟随
  94.                                                  if((TK_zero[i] - TK_cnt[i]) >= T_KeyPress[i]/2)        
  95.                                                          KeyState |=  T_KeyState[i];        //变化值大于最大变化值的1/2, 则判断键已触摸
  96.                                         else if((TK_zero[i] - TK_cnt[i]) <= T_KeyPress[i]/3)        
  97.                                                          KeyState &= ~T_KeyState[i];        //变化值小于最大变化值的1/3, 则判断键已释放
  98.                                 }
  99.                                 else        //0点值比当前值小, 则键释放
  100.                                 {
  101.                                         KeyState &= ~T_KeyState[i];        //键状态: 释放
  102.                                 //        TK_zero[i] = TK_cnt[i];        //快速0点回归(比如按着键上电)
  103.                                 //        TK_zero[i] += 50;                //比较快速0点回归(比如按着键上电)
  104.                                         if((TK_cnt[i] - TK_zero[i]) > 100)        TK_zero[i] += 100;        //差别很大, 则快速回0点
  105.                                         else                                                                TK_zero[i] += 10;        //差别不大, 则慢速回0点
  106.                                 }
  107.                         }

  108.                 }
  109.                
  110.                 if(cmd != 0)
  111.                 {
  112.                         if((cmd >= '0') && (cmd <= '9'))        ReturnValue(cmd-'0', TK_cnt[cmd-'0']);
  113.                         if((cmd >= 'a') && (cmd <= 'z'))        cmd = cmd -'a'+'A';        //小写转大写
  114.                         if((cmd >= 'A') && (cmd <= 'F'))        ReturnValue(cmd-'A'+10, TK_cnt[cmd-'A'+10]);
  115.                         cmd = 0;
  116.                 }
  117.                
  118.         }
  119. }
  120. /**********************************************/

  121. //========================================================================
  122. // 函数: void        ReturnValue(u8 channel, u16 value)
  123. // 描述: 返回按键值函数。
  124. // 参数: none.
  125. // 返回: none.
  126. // 版本: VER1.0
  127. // 日期: 2022-12-23
  128. // 备注:
  129. //========================================================================
  130. void        ReturnValue(u8 channel, u16 value)
  131. {
  132. //        value = value / 100;        //缩小为1/100, 数值小一些比较容易观察
  133.         UART1_TxByte('K');
  134.         UART1_TxByte(channel/10+'0');
  135.         UART1_TxByte(channel%10+'0');
  136.         UART1_TxByte('=');
  137.         UART1_TxByte(value / 10000 + '0');
  138.         UART1_TxByte((value % 10000)/1000 + '0');
  139.         UART1_TxByte((value % 1000)/100 + '0');
  140.         UART1_TxByte((value % 100)/10 + '0');
  141.         UART1_TxByte(value % 10 + '0');
  142.         UART1_TxByte(0x0d);
  143.         UART1_TxByte(0x0a);
  144. }


  145. //========================================================================
  146. // 函数: void  delay_ms(u8 ms)
  147. // 描述: 延时函数。
  148. // 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
  149. // 返回: none.
  150. // 版本: VER1.0
  151. // 日期: 2013-4-1
  152. // 备注:
  153. //========================================================================
  154. void  delay_ms(u8 ms)
  155. {
  156.      u16 i;
  157.          do
  158.          {
  159.                  i = MAIN_Fosc / 10000;
  160.                 while(--i)        ;
  161.      }while(--ms);
  162. }
  163.   


  164. /**********************************************/

  165. u8        isr_index;

  166. //========================================================================
  167. // 函数: void        AUXR_ISR(void) interrupt 13
  168. // 描述: 辅助中断函数
  169. // 参数: none.
  170. // 返回: none.
  171. // 版本: VER1.0
  172. // 日期: 2018-4-2
  173. // 备注: B_TK_Lowpass;// 低通允许, 1允许, 0禁止
  174. //========================================================================
  175. void        AUXR_ISR(void) interrupt 35           //用户中断处理代码
  176. {
  177.         u8        j;

  178.                         j = TSSTA2;
  179.                         
  180.                         if(j & 0x40)        //数据溢出, 错误处理(略)
  181.                         {
  182.                                 TSSTA2 |= 0x40;        //写1清零
  183.                         }
  184.                         if(j & 0x80)        //扫描完成
  185.                         {
  186.                                 j &= 0x0f;//TSSTA2的低4位数据对应0-15个按键通道号码
  187.                                 TSSTA2 |= 0x80;        //写1清零
  188.                                 if(!B_TK_Lowpass)        TK_cnt[j] = TSDAT;        //保存某个通道的读数, 无低通滤波
  189.                                 else                                TK_cnt[j] = (TK_cnt[j] >> 1) + (TSDAT >> 1);                //保存某个通道的读数        低通滤波 1/2

  190.                         }

  191. if(TK_cnt[4]<3000) P20=0;else P20=1;
  192. }
  193. //========================================================================
  194. // 函数: SetTimer2Baudraye(u16 dat)
  195. // 描述: 设置Timer2做波特率发生器。
  196. // 参数: dat: Timer2的重装值.
  197. // 返回: none.
  198. // 版本: VER1.0
  199. // 日期: 2018-4-2
  200. // 备注:
  201. //========================================================================
  202. void        SetTimer2Baudraye(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  203. {
  204.         AUXR &= ~(1<<4);        //Timer stop
  205.         AUXR &= ~(1<<3);        //Timer2 set As Timer
  206.         AUXR |=  (1<<2);        //Timer2 set as 1T mode
  207.         TH2 = (u8)(dat >> 8);
  208.         TL2 = (u8)dat;
  209.         IE2  &= ~(1<<2);        //禁止中断
  210.         AUXR |=  (1<<4);        //Timer run enable
  211. }


  212. //========================================================================
  213. // 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
  214. // 描述: UART1初始化函数。
  215. // 参数:   brt: 通信波特率.
  216. //       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
  217. //          io: 串口1切换到的IO,  io=1: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4
  218. // 返回: none.
  219. // 版本: VER1.0
  220. // 日期: 2018-4-2
  221. // 备注:
  222. //========================================================================
  223. void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =3: 切换到P4.3 P4.4
  224. {
  225.         brt = 65536UL - (MAIN_Fosc / 4) / brt;

  226.         if(timer == 2)        //波特率使用定时器2
  227.         {
  228.                 AUXR |= 0x01;                //S1 BRT Use Timer2;
  229.                 SetTimer2Baudraye((u16)brt);
  230.         }

  231.         else                //波特率使用定时器1
  232.         {
  233.                 TR1 = 0;
  234.                 AUXR &= ~0x01;                //S1 BRT Use Timer1;
  235.                 AUXR |=  (1<<6);        //Timer1 set as 1T mode
  236.                 TMOD &= ~(1<<6);        //Timer1 set As Timer
  237.                 TMOD &= ~0x30;                //Timer1_16bitAutoReload;
  238.                 TH1 = (u8)(brt >> 8);
  239.                 TL1 = (u8)brt;
  240.                 ET1 = 0;                        // 禁止Timer1中断
  241.                 INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
  242.                 TR1  = 1;                        // 运行Timer1
  243.         }

  244.                  if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
  245.         else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
  246.         else if(io == 3)        {S1_USE_P43P44();        P4n_standard(0x18);}        //切换到 P4.3 P4.4
  247.         else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

  248.         SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
  249. //        PS  = 1;        //高优先级中断
  250.         ES  = 1;        //允许中断
  251.         REN = 1;        //允许接收
  252. }

  253. //========================================================================
  254. // 函数: void UART1_TxByte(u8 dat)
  255. // 描述: 串口1发送一个字节函数
  256. // 参数: dat: 要发送的单字节数据.
  257. // 返回: none.
  258. // 版本: VER1.0
  259. // 日期: 2018-4-2
  260. // 备注:
  261. //========================================================================
  262. void UART1_TxByte(u8 dat)
  263. {
  264.         B_TX1_Busy = 1;                //标志发送忙
  265.         SBUF = dat;                        //发一个字节
  266.         while(B_TX1_Busy);        //等待发送完成
  267. }

  268. //========================================================================
  269. // 函数: void UART1_PrintString(u8 *puts)
  270. // 描述: 串口1字符串打印函数
  271. // 参数: puts: 字符串指针.
  272. // 返回: none.
  273. // 版本: VER1.0
  274. // 日期: 2018-4-2
  275. // 备注:
  276. //========================================================================
  277. void UART1_PrintString(u8 *puts)
  278. {
  279.     for (; *puts != 0;        puts++)
  280.         {
  281.                 UART1_TxByte(*puts);
  282.         }
  283. }


  284. //========================================================================
  285. // 函数: void UART1_ISR (void) interrupt UART1_VECTOR
  286. // 描述: 串口1中断函数
  287. // 参数: none.
  288. // 返回: none.
  289. // 版本: VER1.0
  290. // 日期: 2018-4-2
  291. // 备注:
  292. //========================================================================
  293. void UART1_ISR (void) interrupt UART1_VECTOR
  294. {
  295.         if(RI)
  296.         {
  297.                 RI = 0;
  298.                 cmd = SBUF;
  299.         }

  300.         if(TI)
  301.         {
  302.                 TI = 0;
  303.                 B_TX1_Busy = 0;
  304.         }
  305. }

复制代码


这段代码烧录到你的单片机中就可以获取键值了,需要注意的是烧录时需要设置时钟为24MHz,串口助手中的串口号要与左侧烧录用的串口好一致,波特率为115200。
演示入下图:






获取键值无论是用前一种标准方法还后一种变通方法,使用例程时只需要按要求烧录到你的单片机中就可以了,可以不用理会代码中写了什么,等到写你自己的代码时过来借用一下按键初始化、按键中断函数就可以了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
发表于 2023-6-19 21:45:47 | 显示全部楼层
延时函数跟计时器有什么区别?为什么用延时函数而不用计时器呢?
回复 支持 反对

使用道具 举报

发表于 2023-6-19 23:01:23 | 显示全部楼层
看了下STC触摸按键介绍,使用的是电荷搬移原理实现的,大致原理如下:

扫描前,SW3接通,将Cref上的电荷放掉,扫描开始时SW3断开,PWM信号高电平期间SW1接通,SW2断开:给按键Keyx寄生电容充电,PWM信号低电平期间SW1断开、SW2接通,把Keyx寄生电容上的电荷搬移到Cref上,如此反复,直到Cref上的电压超过设置的比较器翻转电压,按键扫描结束。假设Key0的初始寄生电容=10pF,扫描时间=t1,按按键后寄生电容增大,扫描时间=t2,t2<t1,根据两者的差值就可以检测按键动作。

根据上述原理,如果按键初始寄生电容很小,如线路断开,上述电荷搬移过程耗时很长,超过了测量定时器的定时时间,就发生扫描溢出故障。

Cref应选择温漂小的电容,STC资料推荐使用都独石电容,网上资料有的说它温漂小,有的说它温漂大,有的说独石电容有多种,军品的温度系数低至50ppm/℃,应按电容介质温度系数选择,对于个人实验来说,可以选择最低温漂的NPO(COG、C0G)介质的电容,温度系数低至30ppm/℃,容量精度也较高,其次可选择比较好找的涤纶电容。
相关知识:
独石电容的分类特点及规格命名

按键检测关键
STC举例按键按下前后的采样数据变化如下图:

实际使用中,无按键按下时的采样值线不是固定不变,如温度变化、湿度变化、装配形变等会导致无按键时的值偏离初始值很远,如正常初始值=2572,如温度变化、湿度变化、装配形变等导致无按键时的采样值变成2450,如果还以初始值=2572判断按键动作,很容易误判,应该用程序算法更新无按键时的采样值,如更新为前面举例的2450,在此基础上再变化一定数值才可认为按键按下,如阈值=100,则需采样值<(2450-100)=2350才可认为按键按下。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

发表于 2023-6-20 06:41:23 | 显示全部楼层
有了个T却没有了个U,不太好玩。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-20 19:23:01 | 显示全部楼层
猪小呆 发表于 2023-6-19 21:45
延时函数跟计时器有什么区别?为什么用延时函数而不用计时器呢?

二者的作用机理不同,软件延时是让“CPU”原地踏步消耗时间,一个任务需要停顿则整机都会陪同等待,而定时、计数器则是一种分时工作的控制模式,当那个任务需要停顿时则停止该任务的执行同时启动定时器,整机其他任务继续执行到了设定的时间后,重新启动停顿的任务就可以了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-20 19:29:51 | 显示全部楼层
mmxx2015 发表于 2023-6-19 23:01
看了下STC触摸按键介绍,使用的是电荷搬移原理实现的,大致原理如下:

扫描前,SW3接通,将Cref上的电荷放 ...

多谢层主在此补齐了触摸按键的工作原理,很多年的单片机业余应用使我对很多东西只注重用法与实现方法及最终的实现效果,很少深入研究相关的作用机理,多次在其他帖子里与层主交流学到了很多东西,真心感谢!
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2023-6-21 08:42:22 | 显示全部楼层
16个触摸按键,16个8段LED数码管大电流自动涮新
STC8H4K64TL-45MHz-LQFP48/32, 主要功能演示板, 详细的演示程序/原理图,可在本贴技术讨论
1,演示了16个触摸按键输入的效果,
2,演示了 大电流自动涮新 16个8段LED数码管,简化了硬件设计,减轻了CPU的压力,简化了程序设计
===STC8H4K64TL-45MHz-LQFP48 实际可以驱动 32个8段LED数码管自动涮新

驱动8个共阴、8个共阳数码管自动扫描显示, 读取16个触摸按键, 对应16个灯.
触摸按键的读数本来是16位的, 由于使用了滤波算法, 滤波后数据为14位的.
参考电容的选取, 未按键时读数是满量程的1/3~1/2比较好, 兼顾灵敏度, 量产时又允许一定的偏差.
程序会做缓慢的0点跟踪, 所以本例不合适长按处理, 长按处理还要有别的算法.





回复 支持 反对

使用道具 举报

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

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-3 14:10 , Processed in 0.109200 second(s), 9 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

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