ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

STC单片机玻璃面板电容触摸按键:RC充放电与ADC标定

STC单片机玻璃面板电容触摸按键:RC充放电与ADC标定

简介:面向单片机开发初学者与家电控制方案设计者的技术文档,聚焦玻璃面板家电中电容感应式触摸按键的实现原理与编程方法,帮助读者理解从电容检测到单片机固件落地的完整链路。文档围绕 STC 系列单片机的 8 位 ADC 采样方案展开,讲解金属片与手指构成感应电容、充放电电压随触摸动作由约 2.7V 降至 2.3V 的判别依据,并给出 ADC 与串口联调的参数调试思路、寄存器配置宏定义及 C 源程序改编要点,同时提示电磁干扰与元件参数离散性对稳定性的影响。压缩包共 1 个 docx 文件,约 344KB,篇幅精炼,适合作为硬件方案选型与代码调试时的随身参考。目前已有 2155 人学习,可作为入门电容触摸按键设计的一份轻量实践样本。

1. 从一块 5 毫米玻璃后面抠出一个按键:这套方案到底要解决什么

家电面板上一排看不出缝隙的触摸键,多数时候并不是屏幕,而是玻璃背面压着一小片金属,靠手指靠近时那一点点电容变化去驱动一颗几块钱的单片机。这套基于单片机的电容感应式触摸按键原理与程序,要解决的就是在既没有专用触摸芯片、也拿不到原厂配件的前提下,用一颗带 8 位 ADC 的 STC 单片机把玻璃面板触摸按键重新做出来:硬件只有两只二极管、两只电阻、一只充放电电容加一片 Φ12mm 金属片,软件靠 PWM 驱动充放电、ADC 读回电压、串口打出原始数据来标定阈值。它适合电子类专业拿它做课设毕设的学生,适合想给小家电换面板、修按键的维修人员和 DIY 玩家,也适合需要在玻璃、亚克力面板上做无开孔按键的产品工程师。整套东西的成本压得很低,难点不在电路,而在“怎么把 400mV 的电压差稳定地判成一个按键动作”。

2. 需求与选型:专用触摸芯片、STC 单片机自写、STM32 三条路的取舍

2.1 玻璃面板按键的真实工况:手指、水汽、油污和电磁干扰一起上

先把使用场景说清楚,选型才有依据。玻璃面板式家电的按键,工作环境跟实验室面包板完全不是一回事:面板厚度常见在 3~6mm,触摸区上方可能有一层油污或水膜,机器内部紧挨着继电器、变压器、加热盘或者电机,电源是廉价的阻容降压或非隔离方案,地线本身就是脏的。在这种环境下,按键要满足的指标其实是四条:一是能隔着 5mm 玻璃可靠识别手指,误触发率要低到用户感知不到;二是不受面板上水滴、油渍的干扰,湿手操作不能乱跳;三是长寿命,没有机械触点磨损,这本来就是电容式的卖点;四是可维修,坏了之后能用通用元件替换,而不是整块板子报废。

第四条往往被忽略,但它恰恰是专用触摸芯片方案最难受的地方:这类芯片键位数固定、封装固定、寄存器手册不公开或者半公开,一旦停产或者买不到同型号,业余条件下基本没法替换,只能整板换。我在给小家电改面板时就吃过这个亏,一块四键板子上的触摸芯片烧了,原型号买不到,最后只能把整块板连同走线一起换掉。从这个角度说,“用单片机自己实现”不只是省钱,更是把可维修性握在自己手里。

还有一条隐性指标:按键要和主控功能长在同一颗芯片上。电磁炉、电茶壶这类产品,本身就需要一颗单片机去控制加热、定时、显示,如果触摸检测也由它兼任,就省掉了一颗芯片、一组电源去耦和一片布板面积。这是单片机方案在系统层面最大的优势,也是很多方案最后选择自己写触摸的原因。

2.2 三条实现路线:专用触摸 IC、STC 单片机自写、STM32 带触摸通道

把常见做法摊开对比,取舍就很清楚了。专用触摸芯片方案,键位数可选,接上电极和几个外围元件就能用,开发周期短,但它把算法封在黑匣子里,灵敏度、响应时间、抗干扰参数只能靠厂家给的几个配置脚来定,出问题无从下手;STC 单片机自写方案,用片内 ADC 加外围的二极管电阻电容,把充放电过程和判决逻辑全部写在代码里,参数可以一处处改,成本最低,缺点是原理要自己吃透、标定要自己做;带触摸感应通道的 STM32 系列属于第三条路,片内集成了电荷转移式的触摸检测单元,用官方的触摸库能直接拿到通道计数值,抗干扰和自校准做得比手搭电路完整,代价是芯片价格、开发环境和学习曲线都高一截。

对比项专用触摸芯片STC 单片机 + 外围 RC带触摸通道的 STM32
物料成本中最低,二极管电阻电容各一两个高
键位数灵活性受芯片型号限制换 ADC 通道即可扩展受触摸通道数限制
算法可见性黑匣子,只能调配置脚全部在源码里,逐行可改官方库,可调参数较多
抗干扰手段依赖芯片内部靠布板、屏蔽、软件滤波内置滤波与驱动屏蔽
维修替换依赖原型号通用元件,随处可得依赖同系列芯片
适合谁量产、开发周期紧课设毕设、维修、小批量中高端产品、有开发资源

我的建议很直接:交课设毕设、做小批量、修机器,选 STC 这条路,因为它把原理完整地暴露在你面前,答辩时每一行代码你都能解释清楚为什么这么写;如果项目本身对触摸通道数、防水和自校准有硬要求,比如面板要过泼水测试,那就往带触摸通道的 STM32 上靠,用官方库省下来的时间比省下来的那几块钱值钱。

2.3 关键器件与结构参数:560K 电阻、C0、两只二极管和 Φ12mm 金属片

这套电路的元件极少,但每一个参数都直接决定灵敏度,不能随手抓一个焊上去。下表是我整理的关键项,其中电阻值要特别注意:原始图纸上标过 560Ω,这是个笔误,实际必须是 560KΩ 量级。

元件/结构取值作用参数选错的后果
R1、R2560KΩ 量级与 C0 组成充放电时间常数,决定稳态电压用 560Ω 时 C0 在半周期内就充满,ADC 读到接近电源轨,2.7V 稳态点不存在
C0数百 pF 到 1nF 量级充放电电容,感应电容与它并联太小则电压抖,太大则触摸引起的电压变化被稀释
D1、D2小信号开关二极管分别为充电、放电提供单向通路反向漏电大时稳态电压漂移,夜晚温度变化就误触发
金属片Φ12mm感应电极面积小则感应电容小,5mm 玻璃后面信号不足
弹簧压紧金属片保证电极与玻璃贴合,同时引出导线压力不均或接触不良,会出现“按重点才有反应”
玻璃5mm介质层越厚感应电容越小,超过 6mm 后 8 位 ADC 的余量就很勉强

提示:这一节里的电阻值、电容值、玻璃厚度都是这套具体实现的取值,换成别的面板厚度时,R1、R2 和 C0 要重新配,配置思路在 3.4 节里说。

还有一个容易被忽视的结构细节:金属片必须靠弹簧压紧在玻璃下表面,中间不能有气泡或厚胶层。空气和胶的介电常数差别很大,一旦贴合不良,同样的手指压力在不同位置会给出完全不同的 ADC 值,标定出来的阈值就只对某一块板子有效,换一块装配就废。

3. 感应原理拆解:电荷泵式 RC 充放电如何把触摸变成 400mV

3.1 感应电容怎么来的:金属片、玻璃与手指构成的那只小电容

把结构抽象一下:玻璃下表面贴着 Φ12mm 金属片,上表面是要用手指按的触摸区,中间 5mm 玻璃就是介质。金属片是一极,手指是另一极,玻璃是介质,这就是一只容量极小的平板电容,容量跟金属片面积成正比、跟玻璃厚度成反比。没有手指时,对面是空气,介电常数低,这只电容只有几个 pF;手指按上去以后,人体皮肤带电荷参与进来,等效极板面积变大、介质等效介电常数变高,电容量明显上升。

关键在于这只感应电容并不是孤立的,它通过金属片和引线并在充放电电容 C0 两端。也就是说,手指按下去,等效于给 C0 并联了一只额外的小电容;手指抬起,这只电容又消失。整套检测的本质,就是把“并联上去的那一点点电容”翻译成“ADC 端能读出来的一点点电压变化”。这也解释了为什么布板和走线那么要命:引线本身对地就有寄生电容,它和感应电容一起并联在 C0 上,寄生电容越大,手指那点变化占的比例就越小,灵敏度就越差。后面讲屏蔽和避坑时,这条是最常被踩的。

3.2 PWM_IN 的两个半周期:D1 充、D2 放的电荷泵回路

电路由两只二极管 D1、D2,两只电阻 R1、R2 和一只充放电电容 C0 组成,PWM_IN 是单片机输出的方波驱动脚,ADC0 是采样脚。工作过程分两个半周期:

在高电平半周期,电源经 R2、D1 给 C0 充电,D1 导通,充电电流走 R2;在低电平半周期,PWM_IN 被拉到地,C0 上的电荷经 R1、D2 对地放电,D2 导通,放电电流走 R1。两只二极管的方向决定了充电和放电走的是不同的电阻支路,于是 C0 上最终会稳定在一个由两路时间常数共同决定的电压上——充进去的电荷和放出来的电荷达到平衡,电压就不再变化。

这个结构的巧妙之处在于,它是用一个数字引脚“泵”出一个模拟工作点,而不是靠分压电阻直接给一个固定电压。工作在泵状态下的节点,对感应电容的变化非常敏感:手指按上去,等效并联电容变大,在同等的充放电条件下,C0 两端的电压会被拉低。这就是“电容变化 → 电压变化”的转换环节,也是整套方案里唯一真正属于模拟设计的部分。

3.3 从 2.7V 掉到 2.3V:8 位 ADC 的判别余量怎么算

实测数据是这套方案最硬的依据:没有触摸动作时,充放电稳定后 ADC0 端读到约 2.7V;手指按下时,电压下降到约 2.3V。这个 400mV 的差值,对 8 位 ADC 意味着什么,得算一下。

AD 参考电压取芯片电源 5V,8 位转换器把 0~5V 分成 256 份,每份约 19.5mV,也就是常说的分辨率 20mV。2.7V 对应的转换结果约为 138,2.3V 对应约 118,两者相差 20 个码值。20 个码值的余量是什么概念:只要电源纹波、采样噪声和温度漂移造成的波动控制在 ±5 个码值以内,判决阈值放在 128 附近就有足够的安全边距。

粗略估算稳态电压的落点也能印证测量结果。忽略二极管正向压降,两路充放电在占空比 50% 时达到平衡,稳态电压近似为 VCC × R1/(R1+R2)。要让 5V 电源下稳定在 2.7V,需要 R1 约为 R2 的 1.17 倍。如果真按图纸上的 560Ω 去焊,RC 时间常数只有微秒级,而 PWM 半周期往往是几十微秒,C0 每个半周期都会被充满或放光,ADC 读到的就是接近电源轨或者接近地的电压,2.7V 这个工作点根本不存在,整个方案也就失效了。这处笔误当年误导过不少人,属于典型的“图纸上一字之差,板子上全盘皆输”。

3.4 为什么稳态电压与 RC 时间常数、PWM 频率绑在一起

有人会问,既然稳态电压由 R1、R2 的比例决定,那是不是随便给个 PWM 频率都行?不是。充放电要“跟得上”PWM 的节奏,才能在每个半周期内把电压推到平衡点附近,同时又不能太快,快到把感应电容的影响也一起冲掉。

时间常数 τ = R×C0,其中 R 取 R1 或 R2。经验做法是让半周期比 τ 大若干倍,保证每次都能充放到位,通常 PWM 频率落在数 kHz 到数十 kHz 这个区间里调。频率太高,C0 来不及充放,电压摆幅变小,触摸带来的差值也跟着变小;频率太低,采样周期被拉长,按键响应变迟钝,还容易把工频干扰直接引进来。

调整顺序我一般是这样的:先按 560KΩ 和 1nF 量级搭起来,用示波器看 ADC0 端的波形是不是一个平稳的直流加小纹波;再用串口把 ADC 值打出来,看无触摸时的码值是不是落在 130~145 之间;如果偏高,说明充电支路电阻偏小或者占空比偏大,把 R1、R2 的比例调一调;如果码值抖得厉害,先降 PWM 频率试试,再考虑加软件滤波。整套标定都围绕“让无触摸码值和触摸码值之间的 20 个码值不被噪声吃掉”这一件事。

4. 程序实现:STC12C4052AD 的 ADC 采样、串口标定与按键判决

4.1 寄存器定义与 ADC 初始化:八位转换的最小可用代码

这套程序基于 STC12C4052AD 的片内 8 位 ADC 编写,是根据厂商官网演示程序改编的。要注意头文件的问题:如果所使用的 STC12C2052AD.H 里缺少 ADC 相关的位定义,编译会直接报错,需要手工补上。下面这段是整理后的最小可用版本。

/* STC12C4052AD 片内 8 位 ADC 采样 + 串口输出,用于触摸按键标定 */ #include <STC12C2052AD.H> #include <intrins.h> #define uint unsigned int #define uchar unsigned char /* 头文件缺少以下定义时要手工补齐,否则编译报错 */ #define ADC_POWER 0x80 /* ADC 模块电源控制位 */ #define ADC_SPEEDLL 0x00 /* 每次转换 1080 个时钟周期,最稳最慢 */ #define ADC_SPEEDL 0x20 /* 每次转换 810 个时钟周期 */ #define ADC_SPEEDH 0x40 /* 每次转换 540 个时钟周期 */ #define ADC_SPEEDHH 0x60 /* 每次转换 270 个时钟周期,抗干扰最差 */ #define ADC_FLAG 0x10 /* 转换完成标志 */ #define ADC_START 0x08 /* 启动转换控制位 */ #define ADC_CHS1 0x02 /* 通道选择位 1 */ #define ADC_CHS0 0x01 /* 通道选择位 0 */ void Delay(uint x) /* 粗延时,供 ADC 上电稳定和串口节拍使用 */ { uint y; while (x--) { y = 5000; while (y--); } } void InitADC(void) { ADC_DATA = 0; /* 数据寄存器清零 */ ADC_CONTR = ADC_POWER | ADC_SPEEDLL; /* 开 ADC 电源,选最慢档 */ Delay(2); /* 等内部模拟电路稳定 */ } uint GetADCResult(uchar ch) { ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START; _nop_(); _nop_(); _nop_(); _nop_(); /* 启动后必要的等待 */ while (!(ADC_CONTR & ADC_FLAG)); /* 查询转换完成标志 */ ADC_CONTR &= ~ADC_FLAG; /* 清标志 */ return ADC_DATA; /* 返回 8 位结果,0~255 */ }

这段代码有三个地方值得说明。一是转换速度选的是ADC_SPEEDLL即 1080 个时钟周期一档,转换时间最长但结果最稳,触摸检测每秒只需要几十次采样,速度完全够用,没必要为了快牺牲稳定性。二是ADC_CONTR每次转换前都要重写一遍,把电源位、速度位、通道号和启动位一起写进去,这是这颗芯片的用法,不能只写启动位。三是启动之后那几个_nop_()和随后的标志轮询,前者是给内部采样保持留建立时间,后者是代替中断方式,简单但会占住 CPU——在单任务的按键检测里这不算问题,如果还要同时跑显示和加热控制,就要改成定时器里触发、标志位查询的写法。

4.2 串口为什么不能省:把 ADC 数据实时打出来

经常有人问:拿数字万用表量一下 ADC 端口在有手指和没手指时的电压,换算成十六进制写进程序不就行了,何必再搭串口?这个想法我在早期也动过,实践下来至少有两个地方行不通。

第一,万用表读数和片内 ADC 的转换结果对不上。万用表的 ADC 性能远好于单片机片内这颗 8 位转换器,同一个模拟量,两边读出来的数会有系统性偏差,用它去反推阈值,等于拿高精度仪器的读数去校 low 成本的传感器,误差全落在判决门限上。

第二,也是最关键的:感应按键不是静态测量。按键周围的电磁场扰动、板子布局、元件参数的离散性、手指按的位置和面积,都会让采样值实时波动。编程只能用“即时采样值”去做判决,万用表测出的那个数只能当作中心值参考,不能当作阈值直接写死。串口调试的意义就在于,你能看到一串连续的、带波动的数字,从中判断噪声幅度有多大、余量够不够,而万用表只会给你一个骗人的稳定值。

下面这段是配套的串口初始化和输出函数,晶振 12MHz 下按 2400 波特率配置,定时器 1 工作在 8 位自动重装方式。

void InitUart(void) { SCON = 0x50; /* 串口方式 1,允许接收 */ TMOD = 0x20; /* 定时器 1 方式 2,8 位自动重装 */ TH1 = 0xf3; /* 12MHz 晶振下对应 2400 波特率 */ TR1 = 1; /* 启动定时器 1 */ } void SendData(uint dat) { SBUF = dat; /* 写发送缓冲,触发发送 */ while (!TI); /* 等发送完成 */ TI = 0; /* 清发送标志 */ } void ShowResult(uchar ch) /* 连续打印指定通道的转换结果 */ { SendData(ch); /* 先发通道号,便于多通道区分 */ Delay(50); SendData(GetADCResult(ch)); /* 再发转换结果 */ Delay(50); } void main(void) { P1M0 = 0x03; /* P1.0/P1.1 设为高阻输入,作 ADC0/ADC1 使用 */ P1M1 = 0x00; InitADC(); InitUart(); while (1) { ShowResult(0); /* 只观察通道 0 的原始码值 */ } }

主函数里那两行端口模式配置不能漏。这颗芯片的 P1 口复位后不是高阻态,直接当模拟输入用会把采样值拉偏,必须把对应位配成高阻输入,ADC 才能正确读到外部电压。串口这边,2400 波特率在 12MHz 晶振下是这套定时器配置能稳定跑的低速档,调试用途足够,如果要更快就得换晶振或者改重装值重新算。实际调试时把这段烧进去,打开串口助手,看到的应该是一串在 138 附近小幅跳动的数字,手指按上去整体下跳到 118 附近,松手再回来——这个现象成立,硬件部分就算是通了。

4.3 从采样值到按键动作:基线跟踪、迟滞和去抖

拿到原始码值只是第一步,把它变成一个干净的按键动作,还得加三层软件处理。第一层是基线跟踪:环境温湿度和电源会有慢漂移,如果阈值写死,机器用一晚上可能就偏了,所以要在没有按键的时候缓慢更新基线值。第二层是迟滞:判决门限不能只有一个点,按下用一个低门限、松开用一个高门限,否则电压在门限附近抖动时会连续产生多次动作。第三层是去抖:连续若干次采样都同向,才认可状态改变。

/* 基线跟踪 + 迟滞 + 去抖,建议放在 10ms 定时中断或主循环节拍里执行 */ #define TOUCH_TH 128 /* 判决中心:无触摸约 138,触摸约 118 */ #define HYST 6 /* 迟滞带宽,上下各 6 个码值 */ #define DEBOUNCE 3 /* 连续 3 次同向才认可状态变化 */ #define BASE_SHIFT 4 /* 基线跟踪系数,1/16 的缓慢跟随 */ static uchar base = 138; /* 基线初值,取实测无触摸码值 */ static uchar cnt = 0; /* 去抖计数 */ static uchar pressed = 0; /* 当前按键状态 */ void TouchScan(void) { uchar raw = (uchar)GetADCResult(0); uchar th = base - (138 - TOUCH_TH); /* 阈值跟随基线整体平移 */ if (!pressed) { /* 未按下:码值明显低于阈值下限才算按下 */ if (raw < th - HYST) { if (++cnt >= DEBOUNCE) { pressed = 1; cnt = 0; } } else { cnt = 0; } /* 只在未按下时更新基线,避免按下期间把基线拉低 */ base = base - (base >> BASE_SHIFT) + (raw >> BASE_SHIFT); } else { /* 已按下:码值回升超过阈值上限才算松开 */ if (raw > th + HYST) { if (++cnt >= DEBOUNCE) { pressed = 0; cnt = 0; } } else { cnt = 0; } } }

这段逻辑里有几个参数是可以按现场情况调的。TOUCH_TH取的是无触摸码值和触摸码值的中点,本例中 138 和 118 的中点约 128,落在余量正中,两边各留 10 个码值。HYST取 6 是在 20 个码值总余量里划出的迟滞带,太小抗不住噪声,太大会吃掉灵敏度,5mm 玻璃下我一般取 5~8。DEBOUNCE取 3,配合 10ms 的扫描节拍,等于 30ms 确认时间,手指按下到响应基本无感,又能滤掉继电器吸合瞬间的干扰脉冲。BASE_SHIFT决定基线跟随速度,1/16 意味着大约 16 次扫描(160ms)才跟上一次环境变化,慢到不会被手指动作带偏,快到能跟上温漂。

还有一处细节值得强调:基线只在未按下状态更新,这一条如果写错,就会出现“按住不放,基线慢慢被拉到手指电平,然后按键自己松开”的经典 bug,排查起来很费时间。

4.4 参数标定与现场调整:改哪几个数、按什么顺序改

标定有一套固定顺序,不要跳步。第一步,硬件确认:串口打出的无触摸码值应该在 130~145 之间,波动幅度不超过 ±3;超出这个范围先改 R1、R2 比例或 PWM 频率,别急着动软件。第二步,量余量:按下手指,看码值下降多少,本例是 20 个码值左右,如果只降到 128 附近(差值不到 10),说明感应电容太小或者玻璃太厚,先考虑加大金属片面积或者减薄面板,软件上再怎么调都是徒劳。第三步,定阈值:取无触摸码值和触摸码值的中点,迟滞带取总余量的四分之一左右。第四步,压噪声:把家电里最容易干扰的负载(加热盘、继电器、电机)打开,观察码值波动,如果波动超过迟滞带的一半,就得回头做硬件屏蔽,软件滤波只能救一时。

现场调整时我会留两个口子:一个是把TOUCH_TH、HYST、DEBOUNCE单独放在文件头部,方便改;另一个是保留一个串口输出通道,量产前把每块板子的无触摸码值和触摸码值各打一遍,记录离散性。同一批板子如果码值差异超过 10,问题多半出在装配(弹簧压力、金属片贴合)而不是元件,这时候改软件是治标。

5. 避坑与排查:玻璃面板触摸按键最容易翻车的五处

5.1 时灵时不灵、要按很重才有反应:灵敏度和贴合问题

现象:手指轻放没反应,用力压下去才动作;换个位置按又正常了。

原因:九成是感应电容不足。要么金属片与玻璃之间没有贴紧,中间夹了空气或者厚胶;要么弹簧压力不够,金属片翘起一角;要么玻璃厚度超过设计值,比如换了更厚的面板。感应电容小了,手指带来的电压变化就从 400mV 缩到 100mV 以下,8 位 ADC 那点余量被噪声一吃就没了。

解决:先用手按压金属片对应位置再测码值,如果压紧后差值明显变大,问题就在装配,重新压紧或换弹力更足的弹簧;如果压紧也没改善,就加大金属片面积(Φ12mm 可以往 Φ15mm 走)或者减薄面板;软件上可以把转换速度档从ADC_SPEEDLL保持不变、把 PWM 频率降一档再试,让充放电更充分。

5.2 上电乱跳、开加热就误触发:电源与布线的干扰

现象:机器一上电按键就自己触发;或者加热盘、继电器一动作,按键就乱跳。

原因:这类产品的电源往往很简单,地线噪声大;PWM_IN 的方波和 ADC 采样线如果并排走得很长,驱动信号会直接串到采样线上;另外感应电极的引线如果太长又没屏蔽,它本身就是一根天线,把开关电源的干扰全收进来。

解决:三条一起做。一是采样线尽量短、远离加热和继电器走线,必要时用地线包围;二是软件上做多次采样取中值,或者干脆丢弃与上一次差异过大的异常值;三是如果用的是带驱动屏蔽功能的方案(比如某些带触摸通道的芯片可以在屏蔽线上输出与按键脚同相的驱动信号),把屏蔽线接上,让电极与屏蔽之间的寄生电容不再参与充放电,灵敏度能明显回升。这一条在 STM8S 那类方案里是官方推荐做法,思路可以借鉴到任何方案上。

5.3 按住不放结果自己松开:基线跟踪写错了

现象:手指一直按着,几十秒后按键状态自动变回松开,然后又开始反复触发。

原因:基线更新没有做“仅未按下时更新”的限制,或者更新速度过快。按住期间码值一直在触摸电平,基线被慢慢拉下去,等基线追上触摸电平,判决条件就不成立了。

解决:基线更新一定要和按键状态绑定,只在未按下时执行;跟随系数不要太大,1/16 到 1/32 之间比较稳妥;另外加一条保护,如果连续多次采样发现码值长时间处于触摸电平,就冻结基线不再更新。

5.4 标定用的是万用表读数:阈值写死后的连锁反应

现象:程序在实验室好用,装到整机上就不行;或者同一份固件,这台机器灵敏、那台机器迟钝。

原因:阈值是拿万用表量出来换算的固定值,没有考虑片内 ADC 的偏差、元件离散性和装配差异。

解决:回到串口标定这条路,把每台机器的无触摸码值和触摸码值实打实地打出来,阈值取中点,必要时做一次简单的单点校准——上电时若无触摸,采样若干次取平均作为基线初值,而不是用写死的 138。这一步多花十分钟,能省掉后面几天的返工。

5.5 多键互相干扰:通道切换后没等稳定就读数

现象:只有一个键按下,旁边那个键也跟着动作;或者按键顺序不同,触发结果不同。

原因:多通道轮询时,切换 ADC 通道后内部采样保持电路需要建立时间,紧接着就读数会读到上一个通道的残留;另外电极之间的边缘电场也会互相耦合。

解决:切换通道后加几个空操作或者短延时再启动转换;电极之间留出足够间距,中间用地线隔开;软件上做互斥判断,同一时刻只认可信号最强的那一个通道。

6. 验收与答辩:用五组数据证明这套按键在 5mm 玻璃后面站得住

答辩和验收最怕的场面是:你说“能用了”,评委问“怎么证明”,然后现场按了两下,恰好没触发。触摸按键这种东西,靠手感演示是最不可靠的,得拿数据说话。我的做法是提前把下面这张表填满,每一项都有对应的测试方法和判据,讲的时候一条条过,比嘴上说十遍“很灵敏”管用。

验收项测试方法合格判据
静态码值串口连续打印 100 次无触摸采样均值落在 130~145,波动不超过 ±3
触摸差值手指按住,打印 100 次采样与静态均值相差不少于 15 个码值
响应与去抖快速点按 20 次,记录触发次数20 次全部识别,无误触发、无漏触发
抗干扰开启加热盘或继电器,重复静态测试码值波动不超过迟滞带的一半
长时间稳定性连续通电 2 小时,每 10 分钟记录一次基线基线漂移不超过 5 个码值,无自发触发

这五项里,最容易被忽略也最能体现功底的是最后一项。很多方案在台上演示两分钟完美,装到机器里跑一晚上就出问题,原因就是基线漂移没有量化过。我一般在验收前会跑一次两小时的老化,把基线值画成一条曲线,漂移平缓、没有跳变,心里才算有底。

答辩时还有两个技巧。一是把“为什么不用专用触摸芯片”这个问题提前准备好,答案不是省钱,而是可维修性和算法可控性,可以顺带把 2.2 节那张对比表的口径讲一遍。二是主动交代那处 560Ω 应为 560KΩ 的笔误,并解释为什么 560Ω 会让稳态工作点消失——一个能指出图纸问题并说清原因的候选人,比一个只会照抄的候选人可信得多。

我自己的教训是在早期一次课程设计答辩上吃过亏:当时只演示了按键能亮灯,评委问“玻璃厚一点还行不行”,我答不上来,因为从来没量过余量。从那以后我每次做触摸类的东西,都强制走一遍“静态码值—触摸差值—干扰下波动—长时间基线”这套数据流程,哪怕只是个小作业,先有数再谈功能。希望这套流程帮到你,把手里的那块玻璃面板调得又稳又服帖。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进