返回列表 发新帖我要提问本帖赏金: 80.00元(功能说明)

[麦麦茶水间] 【每周分享】使用CVD技术实现按键和滑条触摸控制

[复制链接]
 楼主| mxkw0514 发表于 2025-4-8 10:19 | 显示全部楼层 |阅读模式
<
本帖最后由 mxkw0514 于 2025-4-11 09:39 编辑

#申请原创# @21小跑堂
触摸技术按照维度来分,有1D、2D和3D触摸技术(如图1),1D触摸技术的对象主要有按键、滑条、滑轮等;2D触摸技术的对象主要是触摸屏,是对x,y坐标的判断;3D触摸技术主要应用在手势的识别场景。


图1 Touch技术的分类

触摸技术根据工作原理来划分,包括自容式和互容式技术,自容式就是某个引脚自发自收,互容式技术是一个引脚激励另外一个引脚接受信号进行检测。


图2 自容和互容技术示意图

触摸技术基于检测的物理量来划分,涵盖了电阻式触摸、电感式触摸和电容式触摸技术等,目前来看,电容式技术是用得最多的,在低成本、高可靠性和干扰能力等方面有较大的优势。


图3 电容式静电场感应

目前很多通用型单片机内部都集成了Touch外设(如图4),在汽车电子、消费类电子和工业控制领域扮演者重要的角色,既降低了外部元器件的使用,缩小了PCB的尺寸,又减少了生产成本,提高了产品的竞争力和公司效益。

图4 通用MCU的Touch检测

刚好手上有一块DIP封装的PIC单片机,今天打算利用PIC单片机内部的Touch外设来做一个触摸按键和触摸滑条。PIC单片机的Touch外设是一个CVD(Capative Voltage Divide)电路,在早些年的PIC单片机中,就是一个HCVD外设,在最新的PIC单片机中,CVD电路被放在了ADCC外设中,不过就是PIC单片机中没有硬件CVD电路,只要有ADC外设,还是能基于官方的mTouch库实现软件CVD算法。既然谈到了CVD技术,那么就来简单介绍一下。

打开PIC单片机的数据手册,直接搜索CVD关键词,就能很快定位到CVD的框图,这个框图以及工作原理如图5所示。总的来说,就是利用外部等效触摸电容和内部采样电容之间的来回充放电,利用来回充放电的差分电压为触摸进行判断和检测。采样保持电容和外部触摸等效电容在一个周期的充放电波形图如图6所示。

图5 CVD技术原理

图6 CVD充放电波形示意图

使用示波器的探头捕捉了Touch Sensor上的实际充放电波形如图7所示,与图6中的外部等效电容的充放电波形示意图(红色虚线)基本一致。ADCC一次性在硬件上进行16次充放电并进行硬件上的处理计算,大大降低了软件上资源的消耗。

图7 实测CVD充放电波形图

今天使用手上的PIC单片机加一个Touch小板(如图8),来实现LED灯的触摸控制。Touch小板包含了两个Button和一个Wheel,该小板的PCB三维图如图9所示,如果想学习Touch的布局和布线,可以从官方网站下载这个PCB源文件。
图8 触摸控制电路板

图9 按键+滑条触摸小板

在熟悉了前面讲述的CVD的工作原理之后,就可以使用官方的mTouch库来编写程序了,首先,利用MPLAB的MCC插件(如图10)来建立Button和Wheel对象,编辑相应的Touch引脚,设置单片机的配置字,通过MCC插件生成底层代码。然后,基于MCC生成的Touch driver程序来编写应用层代码,实现对Button和Wheel触摸事件的检测和判断,实现对LED灯的控制;最后,利用MPLAB软件和PICkit工具对应用层程序调试、编译何下载。

图10 Touch外设的可视化配置界面

触摸事件检测和LED灯控制放在的主程序的While循环中,内层任务实现是采用轮询的机理。的仍无Button事件的判断和任务的处理使用了if和else语句,Whell事件的处理稍微复杂一点,主要是使用状态机对手在滑轮上的位置的检测和判断。
  1. #include "mcc_generated_files/mcc.h"

  2. void main(void)
  3. {
  4.     // initialize the device
  5.     SYSTEM_Initialize();

  6.     // Enable the Global Interrupts
  7.     INTERRUPT_GlobalInterruptEnable();

  8.     // Enable the Peripheral Interrupts
  9.     INTERRUPT_PeripheralInterruptEnable();

  10.     while (1)
  11.     {
  12.         // Add your application code
  13.         if(MTOUCH_Service_Mainloop())
  14.         {
  15.             /* Button API*/
  16.             if (MTOUCH_Button_isPressed(0))
  17.             {
  18.                 /* process if button is pressed */
  19.                 /* LED_SetHigh();*/
  20.                 Button_LED1_SetLow() ;
  21.             }
  22.             else
  23.             {
  24.                 /* process if button is not pressed */
  25.                 /* LED_SetLow();*/
  26.                Button_LED1_SetHigh() ;
  27.             
  28.             }
  29.         }
  30.         
  31.         /* Button API*/
  32.         if (MTOUCH_Button_isPressed(1))
  33.         {
  34.             /* process if button is pressed */
  35.             /* LED_SetHigh();*/
  36.            Butto_LED2_SetLow() ;
  37.         }
  38.         else
  39.         {
  40.             /* process if button is not pressed */
  41.             /* LED_SetLow();*/
  42.            Butto_LED2_SetHigh() ;
  43.         }
  44.         
  45.         if(MTOUCH_Slider_isPositionChanged(0))
  46.         {
  47.             uint8_t sliderPostion = MTOUCH_Slider_Position_Get(0);
  48.             sliderPostion = sliderPostion >> 5;
  49.             // process slider position
  50.             switch(sliderPostion)
  51.             {
  52.                 case 0:
  53.                     Slider_LED1_SetHigh();
  54.                     Slider_LED2_SetHigh();
  55.                     Slider_LED3_SetHigh();
  56.                     Slider_LED4_SetHigh();
  57.                     Slider_LED5_SetHigh();
  58.                     Slider_LED6_SetHigh();
  59.                     break;
  60.                 case 1:
  61.                     Slider_LED1_SetHigh();
  62.                     Slider_LED2_SetHigh();
  63.                     Slider_LED3_SetHigh();
  64.                     Slider_LED4_SetHigh();
  65.                     Slider_LED5_SetLow();
  66.                     Slider_LED6_SetLow();
  67.                     break;
  68.                 case 2:
  69.                     Slider_LED1_SetHigh();
  70.                     Slider_LED2_SetHigh();;
  71.                     Slider_LED3_SetHigh();
  72.                     Slider_LED4_SetLow();
  73.                     Slider_LED5_SetLow();
  74.                     Slider_LED6_SetLow();
  75.                     break;
  76.                 case 3:
  77.                     Slider_LED1_SetHigh();
  78.                     Slider_LED2_SetHigh();
  79.                     Slider_LED3_SetHigh();
  80.                     Slider_LED4_SetLow();
  81.                     Slider_LED5_SetLow();
  82.                     Slider_LED6_SetLow();
  83.                     break;
  84.                 case 4:
  85.                     Slider_LED1_SetHigh();
  86.                     Slider_LED2_SetHigh();
  87.                     Slider_LED3_SetLow();
  88.                     Slider_LED4_SetLow();
  89.                     Slider_LED5_SetLow();
  90.                     Slider_LED6_SetLow();
  91.                     break;
  92.                 case 5:
  93.                     Slider_LED1_SetHigh();
  94.                     Slider_LED2_SetLow();
  95.                     Slider_LED3_SetLow();
  96.                     Slider_LED4_SetLow();
  97.                     Slider_LED5_SetLow();
  98.                     Slider_LED6_SetLow();
  99.                     break;
  100.                 case 6:
  101.                     Slider_LED1_SetLow();
  102.                     Slider_LED2_SetLow();
  103.                     Slider_LED3_SetLow();
  104.                     Slider_LED4_SetLow();
  105.                     Slider_LED5_SetLow();
  106.                     Slider_LED6_SetLow();
  107.                     break;
  108.                 case 7:
  109.                     break;
  110.                 default:
  111.                     Slider_LED1_SetHigh();
  112.                     Slider_LED2_SetHigh();
  113.                     Slider_LED3_SetHigh();
  114.                     Slider_LED4_SetHigh();
  115.                     Slider_LED5_SetHigh();
  116.                     Slider_LED6_SetHigh();
  117.                     break;
  118.             }
  119.             
  120.         }

  121.     }
  122. }

按键和滑条触摸板的实现效果如下所示,编写的应用层的程序如下所示。Button每按下一次,控制一个LED灯的点亮;Whell从上到下划过,LED灯点亮的数量逐渐增加,往上划过,LED灯逐渐熄灭。



使用Touch调试助手可以获取单片机上传的触摸信号值,可以结合实际应用产品对Touch的相关参数进行设置和调试。从图11可以看到两个重要的参数,一个Deviation,是是实际的经过量化的信号值;另外一个是Threhold,这是事先设置的判断阈值,可以通过改变判断阈值来调节Touch的灵敏度。



图11 Touch调试助手


MCC插件生成的driver方便了用户的代码编写工作量,缩减了开发时间,但是研究一下CVD工作原理还是比较有意思的。由于本人水平有限,在Touch技术的分享上难免存在纰漏,希望专业领域内的朋友批评指正。





本帖子中包含更多资源

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

×

打赏榜单

21小跑堂 打赏了 80.00 元 2025-04-11
理由:恭喜通过原创审核!期待您更多的原创作品~~

评论

从触摸识别的工作原理出发,借助PIC单片机内部的Touch外设和Touch调试助手开发滑条触摸控制。实现效果较好,原理介绍清晰。  发表于 2025-4-11 14:45
wuliangu 发表于 2025-4-22 18:34 | 显示全部楼层
学习了, 感谢楼主的分享!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

38

主题

735

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部