去年帮朋友拆了一个智能插座,板子上主控芯片没丝印,8个引脚,周围全是电阻电容,没有专门的传感器芯片。我一开始以为是用分立元件搭的信号调理电路,后来查资料才知道,那是一颗集成了多个模拟前端通道的微控制器,裸片价折算下来不到两块钱人民币。
这类芯片在国内有一个很直白的名字:传感MCU。而国外一篇产品介绍里用了一句话形容它——“Microcontroller Family Provides 25 Sensing Functions for 25 Cents”,翻译过来就是:一个微控制器系列提供25种传感功能,成本只要25美分。这句话看起来很营销,但干过嵌入式硬件的人都能读出背后的分量。一颗单片机,能测温度、测电压、测电阻、测电容、测频率,还能当触摸按键用,整套信号链路的成本被压到极致,这件事在过去需要一颗MCU加一颗专用传感器芯片加外围运放才能做到。
这篇文章我就围绕这类低成本传感微控制器展开,讲清楚它到底是怎么做到“25种传感功能”的,为什么能卖这么便宜,以及在实际项目中应该怎么选型、怎么用、怎么校准。如果你正在做智能家居传感器、电池供电的检测设备、低成本消费电子方案,这篇文章应该能帮你省下不少选型和调试的时间。
1. 一颗单片机是怎么把“测”这件事包圆的
拿到这种芯片的第一反应,是它的引脚特别少,封装特别小,但数据手册里外设列表却长得吓人。我仔细看了一圈才明白,这类芯片的核心竞争力不在CPU,而在前半部分那一堆模拟电路。
1.1 从“拆了个玩具”说起:传感器方案的成本构成
先算一笔账。一个普通的NTC测温方案,如果用分立方案来做,大概是这样一个清单:
- 一颗NTC热敏电阻,几分钱
- 一颗固定电阻做分压,几厘钱
- 一颗8位单片机负责采样和上报,几毛钱
- 如果单片机内置ADC精度不够,还要加一颗外部ADC,几块钱
- 如果没有内置运算放大器,信号太弱还得加运放,这又是几毛到几块钱
加在一起,物料成本轻松突破三块五块。而传感MCU的思路完全不一样:它把运放、ADC、电压基准、比较器、恒流源、充电泵这些东西全部做到单片机内部,外部只需要按不同的目标物理量,把对应的传感元件换一换就行。要测温度就接NTC,要测湿度就接湿敏电阻,要测光照就接光敏电阻,片内的信号链路基本不用改。
这种方案的省钱逻辑非常直白:芯片厂家把模拟外设集成进来,一颗芯片吃下原来好几颗芯片的活儿,整机物料成本自然就下来了。而且因为外围电路元件数量少,PCB面积也小了,贴片成本也低了,生产测试的项目也少了。
我实际拆过几款十九块九包邮的智能产品,里面基本都是这个路子。你以为厂家是为了给你省钱,其实人家是把成本抠到极致之后,还能保证功能不砍。
1.2 一颗模拟前端吃掉所有信号调理
理解这类芯片,一个词就够了:模拟前端(AFE,Analog Front End)。它就是把传感器输出的微弱信号,经过放大、滤波、参考电压比较、模数转换,变成CPU能读的数字量。
你可以把这个过程想象成“把不同方言翻译成同一门普通话”。不管传感器输出的是电阻变化、电压变化还是电容变化,模拟前端都会把它翻译成ADC能采的电压信号,最终变成寄存器的数值。CPU端不需要关心外面接的到底是什么,只要根据采集到的数值,套用对应的换算公式就行。
不同厂家的传感MCU,模拟前端的设计大同小异,但一般包括这几样东西:
- 可编程增益放大器(PGA),用来放大微弱信号
- 高精度ADC,常见的是16位到24位
- 内部电压基准,用来给ADC提供参考电压
- 恒流源,用来给NTC、电阻式传感器提供激励
- 输入多路选择器(MUX),用来切换不同测量通道
- 比较器,用来做快速阈值判断
这些东西在普通单片机里属于“可选外设”,在传感MCU里则是“标配”。这也是它命名自带“sensing”的原因。
1.3 什么时候应该选这种芯片
不是我夸它好,这种芯片也有明显的边界。搞清楚它适合什么场景,才能用对地方。
适合的场景有几个共同点:
- 成本敏感,整机BOM是硬指标
- 测量对象是常见的物理量:温度、湿度、电压、电流、电容触摸、压力(通过应变片)、磁场(通过霍尔器件)
- 精度要求不算极端,比如测温做到±0.5℃到±1℃就可以
- 产品体积小,引脚少,最好一颗单芯片搞定所有事
不适合的场景也很明确。如果你要做的是高精度工业仪表,需要24位ADC配合外部精密基准,需要多通道同步采样,那还是老老实实选择专门的ADC芯片加MCU。内部集成的东西,受限于硅片面积和成本,性能天花板摆在那里。另外,如果你需要跑复杂的算法,比如语音识别、图像处理,这也不是传感MCU的强项,它的CPU核心通常是8位或者低端ARM Cortex-M0,算力有限。
选型这事,核心还是“够用就好”。我这个项目里只需要测两路温度和一路电池电压,用传感MCU一颗搞定,成本三块以内;如果上MCU加外部ADC的方案,成本直接翻到八块以上,还多出一堆调试工作。
2. “25种传感功能”是怎么算出来的
我第一次看到“25 sensing functions”的时候,第一反应是“营销噱头”。但翻完数据手册之后,我承认它确实有道理,关键看你能不能理解它的分类逻辑。
2.1 先搞懂信号链:不同传感器如何统一到ADC
要理解25种功能,先理解一件事:传感器的输出本质上只有几大类——电阻变化、电容变化、电压变化、频率变化、通断状态。
举个例子,NTC热敏电阻的阻值会随温度变化,这算电阻类;光敏电阻也是电阻类;湿敏电阻也是电阻类。而霍尔传感器输出的是电压;热电偶输出的也是电压;光电三极管在光照下输出电流,电流经过采样电阻后变成电压。热释电传感器输出的是微弱的电压脉冲;电容式触摸传感器变化的是电极之间的电容。
所以,不管外部接的传感器长什么样,到最后都落在“电学量”这个维度上。传感MCU只要把这几类电学量测准了,就能通过更换外部传感元件来覆盖很多种物理量。
这就是25种功能的底层逻辑:不是一颗芯片内置了25种传感器,而是一颗芯片通过一种统一的信号链,配合25种外部电路接法,可以测量25种物理量。
2.2 常见的传感功能分类
以我手上这颗8位内核的传感MCU为例,它的传感功能大致可以分这几类:
- 电压类:芯片供电电压检测、外部直流电压、电池电压、差分电压(比如电流采样电阻两端)
- 温度类:内部PN结温度(芯片自己测自己)、外部NTC测温、PTC测温
- 电阻类:接地电阻、分压电阻、光敏电阻(光照强度)、干簧管导通电阻
- 电容类:触摸按键、液位检测(通过水作为介质改变电容)、湿度传感器(湿敏电容)
- 频率类:外部脉冲计数、PWM占空比测量、霍尔转速传感器、光电编码器
- 数字状态类:按键检测、限位开关、门磁信号、红外遮挡检测
- 电流类:经过采样电阻的负载电流、恒流源激励下流过传感器的电流
每一类下来,两三个功能一凑,25个名额就很轻松了。实际上很多芯片数据手册里列出来的功能比25还多,只是宣传的时候取了一个好记的数字。
我把常见的25种功能整理成了一张表,方便你对照理解。
| 编号 | 测量对象 | 外部传感元件 | 信号链原理 | 典型应用 |
|---|---|---|---|---|
| 1 | 芯片温度 | 内置PN结 | 内部二极管压降测温 | 过温保护、芯片自检 |
| 2 | 环境温度 | NTC热敏电阻 | 恒流源激励+ADC采集 | 温度计、温控器 |
| 3 | 环境温度 | PTC热敏电阻 | 分压电路+ADC采集 | 电机保护、过热检测 |
| 4 | 温度变化率 | 快速响应的NTC | 连续采样差分处理 | 火灾预警、温差检测 |
| 5 | 电池电压 | 无(直接测量) | 分压电阻+ADC采集 | 电量提示、低压报警 |
| 6 | 外部直流电压 | 无(直接测量) | 分压电阻+ADC采集 | 电压表、电源监测 |
| 7 | 电流 | 采样电阻 | 差分输入+PGA放大 | 电流检测、功率统计 |
| 8 | 光照强度 | 光敏电阻 | 分压电路+ADC采集 | 光控灯、屏幕亮度调节 |
| 9 | 光照强度 | 光电二极管 | 光电流转电压+PGA放大 | 照度计、环境光感知 |
| 10 | 湿度 | 湿敏电阻 | 阻值变化+ADC采集 | 温湿度计、仓库监测 |
| 11 | 湿度 | 湿敏电容 | 电容变化+频率测量 | 土壤湿度、工业湿度 |
| 12 | 触摸按键 | 铜箔/PAD | 电容充放电时间测量 | 触控开关、触摸面板 |
| 13 | 液位 | 金属电极 | 电容变化检测 | 水箱液位、漏水检测 |
| 14 | 接近感应 | 电极板 | 电容变化检测 | 人体感应、非接触开关 |
| 15 | 压力 | 压阻式应变片 | 差分电压+PGA放大 | 电子秤、压力计 |
| 16 | 磁场 | 霍尔传感器 | 电压输出+ADC采集 | 转速检测、门磁开关 |
| 17 | 距离 | 红外对管 | 光电流变化+ADC采集 | 接近检测、避障 |
| 18 | 转速 | 光电编码器 | 脉冲计数 | 电机测速、风扇转速 |
| 19 | 占空比 | 外部PWM信号 | 输入捕获测量 | 遥控信号解码、电机控制 |
| 20 | 频率 | 外部方波 | 脉冲计数/捕获 | 频率计、流量计 |
| 21 | 按键状态 | 机械按键 | 高低电平检测 | 按钮输入、矩阵键盘 |
| 22 | 限位状态 | 微动开关 | 高低电平检测 | 行程开关、门锁检测 |
| 23 | 导通状态 | 干簧管 | 电阻通断检测 | 门窗磁报警、液位开关 |
| 24 | 气体浓度 | 半导体气敏传感器 | 阻值变化+ADC采集 | 燃气报警、空气质量 |
| 25 | 振动/倾斜 | 振动开关、倾斜开关 | 通断状态检测 | 防盗报警、姿态检测 |
这张表你可以拿来做选型参考。实际应用时,你的产品需要哪几种功能,就在这些功能里挑,然后写对应的驱动和算法。
2.3 每种“功能”其实是一套“接法”
这里要特别提醒一点:数据手册里的“传感功能”不是说芯片内部有25个不同的传感器,而是说它提供了25种“测量方案”。方案的含义是:内部那个可配置的模拟前端,加上外部某一种特定的接法,就能测一种物理量。
我自己第一次用的时候就被这个绕进去了。我想“这芯片支持电容触摸,那我接个NTC上去,是不是也能测温度?”答案是当然能,但你需要把模拟前端配置成电阻测量模式,而不是电容模式。同一个物理引脚,可以通过不同的内部配置,实现不同的测量功能。
这种灵活性是好事,但也有代价。代价就是,外设寄存器特别多,初始化代码比普通单片机复杂不少。用寄存器配置模拟前端的时候,需要仔细阅读数据手册中的“测量模式配置”章节,搞清楚每一个位的含义。
3. 实操:用这颗MCU做一个两路测温加电压监测节点
光说不练假把式。我下面用一个具体的项目例子,把这颗传感MCU的完整开发流程走一遍。项目需求很简单:做一个两路温度采集、一路电池电压监测的低功耗节点,数据通过串口发出去,成本控制在五块钱以内。
3.1 硬件连接和引脚分配
这个项目的硬件连接非常简洁:
- P1.0口接NTC分压电路,作为温度通道1
- P1.1口接另一个NTC分压电路,作为温度通道2
- P1.2口接电池电压分压电阻,作为电压通道
- UART把数据发出去
用到的NTC是10kΩ B值3950的常用型号,分压电阻也是10kΩ。这里有个设计细节要注意:NTC接在高端还是低端,会影响ADC读数的方向和线性度。我习惯把NTC放在高端,固定电阻放在低端,因为常见MCU的ADC只能采正电压,NTC在低端时,温度越高阻值越低,ADC读数越低,容易在高温区出现信号太小的问题;NTC在高端时,ADC读数是“1-分压比例”,低温区分辨率更好。这个项目的测温范围是0到100度,我选择了固定电阻在上、NTC在下,因为低温端NTC阻值大,分压比变化更明显。
电池电压那路,我选择两个电阻分压,把最高4.2V的锂电池电压分到1.4V以内,保证ADC不会过压。这两个分压电阻的阻值都选了100kΩ级别,目的是减小对电池的静态损耗。不过这里要记住一个坑:分压电阻太大,源阻抗就大,ADC采样的时候如果采样时间不够,误差会很大。后面我会专门讲。
3.2 从裸机代码开始:ADC初始化与采集
这颗MCU的ADC配置流程,大致分这样几步:
- 配置ADC的输入通道,选中需要测量的引脚
- 配置PGA增益,根据信号幅度选合适档位
- 配置采样时间和分辨率
- 选择参考电压源(内部基准或电源电压)
- 触发一次转换,读取结果
下面是一段简化的C代码,展示了配置和读取一个通道的过程:
// ADC初始化,测量NTC通道1 void adc_init_ntc1(void) { // 1. 设置P1.0为模拟输入 P1M1 |= 0x01; P1M2 &= ~0x01; // 2. 选择ADC通道0,对应P1.0 ADC_CONTR = 0x80; // ADC_POWER ON ADC_CONTR &= 0xF0; ADC_CONTR |= 0x00; // CHS = 000, 选择通道0 // 3. PGA增益设置为1倍 PGA_CONTR &= ~0x03; PGA_CONTR |= 0x00; // 4. 选择内部基准电压作为参考 ADC_CONTR |= 0x20; // REFS = 1 // 5. 设置采样时间为最长档,保证源阻抗适配 ADC_CONTR &= ~0x0C; ADC_CONTR |= 0x0C; // SAMP_TIME = 11 } // 读取一次ADC值,返回12位结果 unsigned int adc_read(void) { unsigned int result; // 启动转换 ADC_CONTR |= 0x40; // ADC_START = 1 // 等待转换完成(实际项目中建议加超时保护) while(!(ADC_CONTR & 0x20)); // 读取高8位和低4位 result = ADC_RES << 4; result |= ADC_RESL & 0x0F; // 清标志 ADC_CONTR &= ~0x20; return result; }里边的寄存器名字,不同厂商会不一样,但是逻辑是通用的。重点要领会的是那个“采样时间设到最长”的细节。前边提过分压电阻用了100kΩ级别,这个源阻抗配合ADC内部的采样电容,需要足够的充电时间才能让电压稳定。我发现这个问题是在调试时看ADC值在上下几十个数之间乱跳,后来把采样时间调长之后,数据立刻稳定下来。
3.3 把ADC值换算成温度和电压
读到了ADC值,下一步是把它换算成物理量。这一步最关键,也最容易出错。
电压换算比较简单:12位ADC,参考电压Vref,ADC读数N,那么电压值就是:
V = N × Vref / 4096
温度换算需要先算出NTC的当前阻值。假设固定电阻R是10kΩ,NTC在高端、固定电阻在低端,那么NTC两端的电压是供电电压减去固定电阻上的压降。如果用ADC值来表示,NTC当前阻值的计算公式是:
Rntc = (4096 - N) × R / N
拿到Rntc之后,再用Steinhart-Hart方程换算温度。工程上常用简化的B值公式:
T = 1 / (1/T0 + ln(Rntc/R0) / B) - 273.15
其中T0是25℃时的开尔文温度,R0是25℃时的阻值10kΩ,B是3950。
我建议直接写成查表加线性插值的方式。因为B值公式在宽温范围内有几百毫度的偏差,而查表法只要表够密,精度可以做得更高。我在交付项目时一般用B值公式做粗算,然后用两点校准来修正偏差,这样既能保证代码量小,又能保证精度到±0.5℃以内。
3.4 标定与校准:没有专业仪器也能做两点校准
说到校准,这是传感类项目里最容易被忽视、但影响最大的一步。低成本MCU的内部基准电压不准,误差可能有正负百分之几,直接套公式会导致温度读数系统性偏差。解决办法是给每个产品做校准。
我的做法是,在量产测试阶段,用恒温槽或者干井炉提供两个标准温度点(比如0℃和50℃),让设备分别上报ADC读数,然后把这两个点对应的校准系数写到芯片的OTP或者Flash里:
// 两点校准的计算结果 // 校准点1: 0℃时 ADC读数 = 2910 // 校准点2: 50℃时 ADC读数 = 1348 // 对应温度差: 50℃ // 所以每个ADC码对应的温度变化量 = (50 - 0) / (2910 - 1348) ≈ 0.032℃/码 int adc_to_temperature(unsigned int adc_value) { int temperature; temperature = (int)(((int)adc_value - ADC_AT_0C) * TEMP_PER_ADC_CODE); return temperature; }如果设备没有恒温槽,也可以用一个更取巧的办法:拿一个已经校准过的温度计作为参考,把探头和NTC绑在一起,先在室温下读一组数据,再把手握住传感器模拟体温,读第二组数据。这样两个点就能把增益误差和偏移误差同时校正掉。虽然精度不如恒温槽,但对大多数消费类产品来说,已经够用了。
4. 踩坑实录:低成本传感方案的四个经典问题
最后这部分,我把这几年用低成本传感MCU踩过的坑集中写一下。这些坑很多是数据手册上不会明说的,只有实打实调过板子的人才会遇到。
4.1 ADC数值乱跳,先查电源还是先查代码?
有一个项目,我设计的电路用一颗纽扣电池供电,采集电压的时候ADC读数一直跳,幅度大概正负50个数。我当时第一反应是代码有问题,反复检查了采样时间、滤波算法,折腾了两天才发现,问题出在纽扣电池本身——电池内阻大,ADC采样瞬间抽取的电流会拉低供电电压,导致参考电压跟着抖动。
解决方法是把采样做成两步:第一次采样可以丢弃,因为采样电容充电瞬间会对电源造成冲击;第二次、第三次采样再做平均。或者更彻底一点,给ADC加一个专门的滤波电容,形成低阻抗的供电节点。
这里有个经验法则:遇到ADC值乱跳,先查电源纹波和电源动态响应,再查代码。大多数ADC异常,根源都在供电上。
4.2 内部基准电压的温漂怎么补偿
低价MCU的内部基准电压,温漂系数通常在几十到上百ppm/℃。什么意思?温度变化10度,基准可能偏了0.1%。对于12位ADC来说,这已经能造成好几个码的误差了。
如果你做的产品要在户外或者高温环境下用,这个误差是逃不掉的。我推荐两个办法:
- 办法一:在固件里做温度补偿。利用芯片内置的PN结测温功能,先读出芯片温度,再根据芯片出厂时标记的基准温漂曲线去修正结果。
- 办法二:外部加一颗低温漂的基准电压源。这会让BOM成本增加几毛钱,但是精度提升非常明显。
大多数消费类产品,我建议选办法一。反正这颗芯片本身就能测内部温度,不用白不用。
4.3 采样时间不能拍脑袋决定
前边我提到采样时间要够长,但也不能一概而论。采样时间太长,测量速度就慢,如果产品需要快速响应,就会拖后腿。
正确的做法是根据外部源阻抗来计算。传感器信号源的等效阻抗越高,采样电容充电到目标电压需要的时间就越长。简单估算可以按这个公式来:
采样时间 ≈ 9 × 源阻抗 × 采样电容
比如内部采样电容是20pF,外部源阻抗是100kΩ,那么需要的时间大约就是9 × 100000 × 20e-12 = 18微秒。如果ADC模块允许配置采样时间,要留足裕量。
但源阻抗也不是越低越好。源阻抗太低意味着外部电阻分压的电流大,功耗高。我在做电池供电产品时,经常纠结这个矛盾。最后一般取一个折中:把源阻抗控制在10kΩ到100kΩ之间,采样时间则按最长档来配置。
4.4 常见问题速查表
我把调试过程中经常遇到的现象和排查方向整理成一个速查表,方便你遇到问题时快速定位。
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| ADC读数乱跳 | 供电电压不稳、参考源抖动 | 示波器观察VDD/参考引脚波形 | 加大滤波电容,分离数字和模拟供电 |
| 温度读数整体偏高或偏低 | 分压电阻精度低、基准不准 | 万用表实测分压点和基准电压 | 更换0.1%电阻,做两点校准 |
| 温度读数非线性偏差大 | NTC B值公式近似误差 | 对比标准温度计多点测试 | 改用查表和插值,或官方校准表 |
| 电池电压测不准 | 分压电阻阻值漂移或过时 | 标注实测值,对比万用表 | 选用温漂稳定的电阻,做软件偏置校准 |
| 低功耗模式下电流偏大 | 分压电阻一直耗电 | 万用表串入电池实测 | 用MOS管或MCU GPIO控制分压电路供电 |
| 触摸按键误触发 | 电源噪声、布线不合理 | 观察CMOD/CREF波形 | 按要求铺地,按键感应盘周围不要走高频线 |
| 温度响应慢 | NTC热容大 | 对比不同封装传感器 | 换0603封装,或传感器远离大热容结构 |
| 数据上报出现奇偶校验错误 | 地线噪声、波特率偏差 | 示波器观察UART波形 | 加粗地线,或者更换晶振 |
这个表格里的每一个问题,我都实际遇到过。特别是“分压电阻一直耗电”那个问题,第一次做电池供电产品的时候完全没有概念,直到实测发现休眠电流比标称值大了几十倍才恍然大悟。
再补充一个跟电源分压有关的技巧:测量电池电压的分压电阻,如果能用一个GPIO来控制上端供电,在低功耗模式下彻底断开分压支路,休眠电流能省下一大截。代价是多占用一个IO口,但很多资源不紧张的产品都愿意这么干。
我的一个个人经验收尾
说了这么多,我想最后分享一个关于选型心态的体会。传感MCU这类芯片,看起来功能很多、价格很便宜,但实际用起来不比通用MCU省心。原因在于,通用MCU的模拟部分简单,给用户的操作空间小,反而是下限高;而传感MCU把很多模拟控制权交给你,上限高,但下限也低,配置不好时测出来的数据会让你怀疑人生。
我第一次用这颗芯片的时候,光是模拟前端的PGA和采样时间两个寄存器,就调试了整整一个晚上。后来想通了,它本质上是一个“可编程的模拟仪器”,不只是“一个带ADC的单片机”。从这个角度去理解,再去翻数据手册,思路就顺了。
最后再提一个小技巧:这种低成本传感MCU在出厂时,内部往往有一批校准好的参考值,存在OTP区里。量产之前,记得先把各个通道的零点和满量程读数读一遍,标在产品出厂文件里。这对后面产线调试和售后问题分析会有很大帮助。你会发现,哪怕是一颗卖几毛钱的芯片,只要把校准流程做扎实,测出的数据比那些“跑分很高”的方案还要靠谱。