RC充放电检测法:从原理到实战
各位同学,今天我们来聊聊触摸检测里最经典、也最基础的方法——RC充放电检测法。说实话,这个方法我用了快十年了,从最早的电阻触摸屏到现在的电容式触摸按键,它始终是嵌入式工程师的必修课。
为什么这么说?因为它的原理简单,实现成本低,而且抗干扰能力还不错。我当年做第一个触摸项目时,就是用几个电阻电容加一个IO口搞定的。嗯,咱们一步步来看。
RC电路原理:电容充放电的本质
先说说RC电路。说白了,就是一个电阻和一个电容串联在一起。当给这个电路通电时,电容会慢慢充电;断电时,电容会慢慢放电。这个「慢慢」有多慢?取决于RC时间常数τ。
公式很简单:τ = R × C
τ的单位是秒。比如10kΩ电阻配100nF电容,τ = 10k × 100n = 1ms。这意味着电容电压充到63.2%需要1ms,充到95%需要3τ,也就是3ms。
我习惯用一个经验值:充到电源电压的63.2%需要1τ,充到90%需要2.3τ,充到99%需要4.6τ。这些数字你记在心里,调试时很有用。
关键点:电容值变化时,充放电时间会跟着变。触摸传感器就是利用这个原理——手指靠近会改变电容值,从而改变充放电时间。
充放电时间测量:怎么测才准?
测量充放电时间,常用的方法有两种:一种是测充电时间,一种是测放电时间。我个人更推荐测放电时间,为什么?因为放电时电容初始电压是确定的,测量误差小。
具体怎么做?看这个流程:
- 先把IO口设为输出,拉高电平,给电容充电到VCC
- 然后把IO口设为输入(高阻态),同时启动定时器
- 电容通过外部电阻放电,电压慢慢下降
- 当电压降到某个阈值(比如0.7V或1.5V)时,IO口检测到低电平,停止定时器
- 读定时器值,这就是放电时间
我在项目中遇到过一个问题:IO口的输入阈值电压不是固定的。不同芯片、不同温度下,阈值可能从0.7V漂到1.2V。这会导致测量结果不稳定。后来我改用比较器或者ADC来检测阈值,效果就好多了。
小技巧:如果芯片有施密特触发输入,尽量用它。施密特触发有滞回特性,能有效抑制噪声引起的误触发。
阈值比较法实现:代码怎么写?
阈值比较法的核心思想是:设定一个基准时间T0(没有触摸时的放电时间),然后实时测量放电时间T。如果T比T0大很多,说明有触摸。
为什么T会变大?因为手指靠近时,电容值增加了,放电变慢了。你想想看,电容从10pF变成12pF,放电时间就多了20%。这个变化足够我们检测到。
下面是一个典型的实现代码,我用的是STM32的HAL库:
// 初始化
#define THRESHOLD_TOUCH 50 // 触摸阈值,单位:定时器计数
#define THRESHOLD_RELEASE 30 // 释放阈值,带滞回
uint16_t base_time = 0; // 基准时间
uint16_t measure_time = 0; // 实测时间
// 测量一次放电时间
uint16_t measure_discharge_time(void) {
uint16_t count = 0;
// 1. 充电:IO口输出高
GPIO_SetPin(GPIO_PIN, GPIO_MODE_OUTPUT_PP);
GPIO_WritePin(GPIO_PIN, GPIO_PIN_SET);
delay_us(10); // 确保充满
// 2. 开始放电:IO口设为输入,同时启动定时器
GPIO_SetPin(GPIO_PIN, GPIO_MODE_INPUT);
TIM_Cmd(TIM2, ENABLE);
// 3. 等待电压降到阈值以下
while(GPIO_ReadPin(GPIO_PIN) == GPIO_PIN_SET) {
count++;
if(count > 10000) break; // 超时保护
}
// 4. 停止定时器,返回计数值
TIM_Cmd(TIM2, DISABLE);
return TIM_GetCounter(TIM2);
}
// 触摸检测主循环
void touch_scan(void) {
measure_time = measure_discharge_time();
if(measure_time > (base_time + THRESHOLD_TOUCH)) {
// 检测到触摸
touch_flag = 1;
} else if(measure_time < (base_time + THRESHOLD_RELEASE)) {
// 触摸释放
touch_flag = 0;
}
}
注意看,我用了两个阈值:THRESHOLD_TOUCH和THRESHOLD_RELEASE。这就是滞回比较,防止在临界点来回跳变。我曾经吃过这个亏——不加滞回,手指轻轻一碰,输出信号就在0和1之间疯狂抖动。
避坑指南:我曾经在量产时发现,同一批板子,有的灵敏度高,有的灵敏度低。查了半天,发现是PCB走线寄生电容不一致导致的。解决办法是:每块板子出厂前做一次自动校准,把base_time重新测一遍。
RC充放电检测法的知识体系
下面这张图是我画的,把整个方法的逻辑串起来了。你可以看到,从物理原理到软件实现,每一步都有对应的处理手段。
实际项目中的参数选择
参数怎么选?我直接给个参考表,这是我做项目时常用的组合:
| 应用场景 | 电阻R | 电容C | 理论τ | 测量分辨率 |
|---|---|---|---|---|
| 触摸按键(小面积) | 10kΩ | 10pF(含寄生) | 0.1μs | 高(需高速定时器) |
| 触摸按键(大面积) | 100kΩ | 50pF(含寄生) | 5μs | 中 |
| 接近感应 | 1MΩ | 100pF(含寄生) | 100μs | 低(但检测距离远) |
| 水位检测 | 470kΩ | 200pF(含寄生) | 94μs | 中(需防电解) |
注意,这里的电容C包含了PCB走线的寄生电容。我习惯在设计时预留一个调试焊盘,方便用示波器实测波形。嗯,说到示波器,调试时一定要看波形——充电曲线是不是平滑的?放电有没有毛刺?这些一眼就能看出来。
经验之谈:如果测量结果跳动很大,先别急着改算法。用示波器看看电源纹波,很多时候是电源噪声耦合到触摸通道上了。加个100nF去耦电容,问题就解决了。
总结一下
RC充放电检测法,说白了就是利用电容充放电的时间变化来感知触摸。它的优点是简单、成本低、不需要专用芯片。缺点是受寄生电容和温度影响较大,需要做校准和补偿。
我个人建议,初学者先用这个方法入门,把原理吃透。等你真正理解了电容检测的本质,再去学更高级的电荷转移法、互电容检测法,会事半功倍。
好了,这一节的内容就到这里。记住:理论要懂,但动手更重要。拿块开发板,焊几个电阻电容,写几行代码,你才能真正掌握它。