干这行时间久了,你会发现一个挺有意思的规律:很多看似复杂的控制系统,最后真正决定稳定性的往往是几个温度采集点。去年我做的一款机房空调控制器就卡在这个环节上——电控箱内部得测温,风道远端也得测温,两个点相距三四米,用的是NTC加运放的方案。结果温度一拉远,线缆压降、接头电阻全跑出来了,误差一度漂到两度多,调起来相当痛苦。后来整体换方案,主控选了STM32H743ZI,前端测温芯片换成了PJ85718DM,重新搭了一套本地加远程二极管测温的系统,才算把事情彻底解决。
这篇文章我把整个项目的关键细节整理一遍,包括为什么选PJ85718DM、怎么把本地温度和远端探头温度读准、远程数据怎么上传给上位机,以及我在现场踩过的几个坑。希望对正在做HVAC控制器或者嵌入式测温模块的朋友有点帮助。
1. 项目全貌:为什么要做本地加远程温度监测
1.1 HVAC和嵌入式场景对温度监测的要求
先聊聊项目背景。HVAC系统里的温度监测和普通消费电子产品不太一样,它有三个很典型的特点。
第一是点位分散。一台空调箱可能同时需要采集回风温度、送风温度、盘管进出水温度、电控箱内温度,这些探头分布在设备的不同方位,有的近在咫尺,有的隔了好几米甚至十几米。第二是精确度要求高。楼宇自控系统做能量调节和故障诊断时,温度偏差直接关系到风机变频、水阀开度的控制逻辑,误差太大整个系统都在瞎调。第三是可靠性要求苛刻。HVAC设备往往在楼顶、机房、设备层这些环境不太友好的地方运行,温度从零下到四五十摄氏度都很常见,传感器必须在这种条件下保持稳定。
嵌入式系统这边也是类似的路数。板卡内部功率器件越来越多,MOS管和驱动芯片发热量很大,必须实时掌握板内温度来防止过热;同时外壳上又得留一个温度接口去监测外部环境。以往大家都是拿NTC热敏电阻设计方案,便宜是便宜,但后端的信号调理电路、ADC采样、线性化校准一样都少不了。而且NTC是非线性的,温度越低电阻变化越陡,想要在全量程范围做到高精度,得做分段校准,工作量不小。
1.2 读懂“本地温度”和“远程温度”两层含义
这个项目的标题里反复提到“本地”和“远程”,我在这篇文章里会从两个层面来用它。
在芯片层面,PJ85718DM本身就是一个支持双通道测温的器件。它内部集成了一个温度传感单元,可以测量芯片自己所在位置的温度,这就是“本地温度”;同时它还提供独立的远端测温通道,通过外接一颗普通三极管去感知远处的温度,这就是“远程温度”。把三极管探头拉远以后,就可以同时看到板内和远端的实时温度。
在系统层面,STM32H743ZI读取到这两个温度之后,再通过RS485总线以Modbus RTU协议上报给上位监控平台,这台控制器本身也成了远程监控网络里的一个节点。整个过程可以概括为:本地采集加远程探头的“双点测温”,再加上远程通信上报的“双路传输”。
这两个层面贯穿整个项目的硬件设计和软件架构,下面我会分别展开。
1.3 测温方案选型对比:为什么放弃NTC
先列一个我在项目初期做过的对比表,这样大家能直观看到几个方案的差异。
| 方案指标 | 传统NTC+ADC | 模拟接口温度芯片 | 数字温度芯片(本项目) |
|---|---|---|---|
| 远端探头支持 | 需要额外调理电路 | 不支持或支持少 | 原生支持二极管探头 |
| 精度典型值 | 1%误差需校准 | 0.5°C左右 | 0.5°C以内 |
| 抗干扰能力 | 较弱,易受线缆影响 | 一般 | 较强,有滤波 |
| 软件复杂度 | 需要线性化 | 中等 | 寄存器直接读 |
| 供应链成本 | 低 | 中 | 中等偏高 |
NTC的问题我在开头已经提过,核心痛点其实是两个:一个是远距离传输误差,另一个是生产校准成本。NTC探头线和后端调理电路的匹配关系很难精确控制,生产线上的每台设备可能都得单独校准一遍,这在大批量制造中是个不小的负担。
PJ85718DM这类数字温度传感器不一样。它把测温模拟前端、ADC、数字滤波和接口逻辑集成在了一颗芯片里,硬件上只需要解决供电和I2C通信,软件上读取寄存器就能拿到温度值。配合STM32H743ZI这种带硬件I2C外设和浮点运算单元的高性能MCU,整个测温链路的开发工作量至少压缩了一半。
2. 核心器件解析:PJ85718DM 与 STM32H743ZI
2.1 PJ85718DM 的测温原理与内部结构
先说说PJ85718DM这颗芯片。它的核心是片上本地温度传感器加远程二极管测温引擎的组合。熟悉温度芯片的朋友看到这个架构应该很快能联想到类似器件的工作方式,但PJ85718DM在一些细节上做得比较均衡。
本地测温走的是标准带隙基准加Sigma-Delta ADC的路线。芯片内部有一个温敏PN结,它的正向压降跟温度呈近似线性关系,配合高精度ADC做模数转换,再把结果按芯片内部校正好的系数换算成温度值。PJ85718DM的本地测温范围标称是-40°C到+125°C,典型精度可以做到±0.5°C,这个精度等级用在HVAC控制逻辑上已经比较充裕了。
远程测温是这颗芯片最有意思的部分。它并不是直接测量电阻或者电压,而是利用三极管VBE电压的温度特性。简单解释就是:给外接三极管的发射结施加两个大小成比例的偏置电流,两次测得的VBE之差和绝对温度成正比。因为消掉了三极管饱和电流等工艺相关参数,只需要恒定的电流比例关系,所以测温结果一致性很高,基本不需要逐颗校准。
PJ85718DM的远程通道支持NPN和PNP两种接法,而且带串联电阻抵消功能。这个功能在探针拉线较长时非常实用——电缆本身的阻抗会引起测量偏置,芯片内部可以主动计算并补偿掉这部分影响。
2.2 STM32H743ZI 主控资源配置
STM32H743ZI是H7系列里一颗规格比较均衡的芯片。Cortex-M7内核跑到480MHz,自带2MB Flash和1MB RAM,做温度采集这种任务简直是绰绰有余。实际上这个项目里真正吃资源的是后续的通信协议栈和故障诊断逻辑,不是测温本身。
我选它的考量主要是这几个:
- 片上I2C资源充足。H743ZI有四个I2C外设,PJ85718DM独占一路,另外还有I2C去连EEPROM、扩展IO等,完全不会互相干扰。
- 带浮点单元。温度换算、滤波计算、Modbus CRC计算用浮点运算很方便,CPU负载也低。
- 串口资源丰富。它有多达8个UART,我可以用一个接调试口,一个接RS485收发器,一个接WiFi模块预留云端上传能力,互不占用。
- 可靠性接口。H7系列的时钟树和电源管理比老一代M4强不少,PLL配置灵活,配合外部晶振跑出精确的UART波特率更容易,Modbus通信的帧定时也更好控制。
2.3 这对组合为什么合适
经常有人问,测温用一颗8位单片机加一颗I2C温度传感器就够了,为什么要上H743这种大核?
这个疑问是合理的。如果项目仅仅是读两路温度然后本地显示,用低成本的MCU确实更合适。但实际项目往往会跟随业务发展持续扩展需求。比如后来客户要求加数据记录、Modbus TCP网关、历史趋势曲线、故障预测模型,这些都需要较多的存储和计算资源。如果一开始选了性能临界的老平台,后面加功能就得换主板重新做认证,成本反而更高。
PJ85718DM加STM32H743ZI这个组合的核心价值在于:测温前端由专用传感器芯片承担,保证精度和一致性;系统主控则负责数据融合、协议处理和通信协同。专业的事交给专业的器件,这是嵌入式系统设计里性价比最高的状态。
3. 硬件电路:从传感器探头到主控芯片的完整链路
3.1 I2C接口电路与上拉电阻选择
PJ85718DM和STM32H743ZI之间走的是标准I2C总线。硬件连接上需要关注几个点:
- SDA和SCL必须接上拉电阻到电源。I2C是开漏结构,没有上拉就没有高电平。
- 上拉电阻的阻值要看总线速率。项目里跑的是400kHz快速模式,我用的是4.7kΩ上拉到3.3V,实测波形上升沿时间在1us以内,完全满足规格要求。
- STM32H743ZI的I2C引脚要配置为开漏输出模式,不能配推挽,否则会产生总线冲突。
- 总线走线尽量短,PJ85718DM和主控的距离控制在5cm以内,避免寄生电容过大导致信号劣化。
PJ85718DM还有地址引脚A0和A1,支持通过硬件电平配置多颗器件挂在同一总线上。我项目里预留了两个地址位,理论上同一条I2C总线最多可以挂四颗。不过实际只用了两颗,后续扩展也有余地。
3.2 远程测温通路设计与布线要点
远程测温的物理通路是从PJ85718DM的D1、D2引脚接出去到远端探头。这里有一个设计重点:远端探头不是热敏电阻,而是三极管的发射结。我用的是SOT-23封装的NPN三极管,集电极和基极短接,只保留发射结作为温敏元件。这种接法的好处是温度特性一致性好,而且器件成本极低,比专门的温度探头便宜不少。
布线方面我有几个亲身实践的建议:
- 远程测温线路属于模拟敏感信号,一定要避开开关电源、继电器、变频器这些强干扰源。
- 如果走线超过30cm,建议D线采用双绞线,或者至少和地线一起走,减小共模干扰。
- 对于特别长的走线,PJ85718DM的串联电阻抵消功能能补偿掉一部分线阻带来的误差,具体补偿范围取决于芯片配置寄存器。我在项目中实测了2米和5米的线缆,补偿效果差异在小数点后一位,效果可以接受。
- 三极管探头不要靠近高热器件,尽量安装在风道中心或者被测物体的表面,固定时使用导热硅胶,保证热接触良好。
这里要特别提醒一点:远程二极管测温的原理是电流激励后测VBE,所以驱动线和测量线共用同一对线,线缆电阻如果太大,会直接影响VBE采样结果。PJ85718DM的串联电阻抵消机制可以解决一部分,但前提是线缆电阻不能超过芯片设计的最大范围。项目中最稳妥的做法还是把线控在合理长度以内。
3.3 电源网络与PCB布局实战经验
PJ85718DM的工作电压我选择用3.3V供电,和STM32H743ZI的IO电平保持一致,省去了电平转换电路。硬件设计时需要注意:
- 传感器供电要加一个100nF的靠近芯片引脚放置的去耦电容,有条件再加一个1uF的缓充电容,用于稳定远端测温时内部的电流脉冲。
- 布局时把PJ85718DM尽量靠近被测对象。如果测的是板内温度,芯片要贴在功率器件附近;如果测的是空气温度,芯片反而要远离热源,避免自身发热导致读数偏高。
- 主控板上的DCDC开关电源会产生较大的纹波,传感器部分的地要单独铺一小块,然后单点接入主板地,电源分配遵循星型结构。
这些看起来是很基础的EMC设计原则,但实际项目里很多温度采集不稳定都是电源和地没处理干净引起的。特别是远程测温,它的信号非常微弱,更容易受到干扰。
4. 软件驱动:把温度数据从寄存器里“取”出来
4.1 初始化I2C与PJ85718DM寄存器配置
先看STM32H743ZI这一端的初始化。我用的是HAL库,工程的时钟主频配到400MHz,I2C外设时钟挂载在APB1上。初始化代码如下:
/* I2C3 外设初始化 */ I2C_HandleTypeDef hi2c3; hi2c3.Instance = I2C3; hi2c3.Init.ClockSpeed = 400000; /* 400kHz fast mode */ hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_16_9; hi2c3.Init.OwnAddress1 = 0x00; hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c3);PJ85718DM在上电后需要花大约几十毫秒完成内部复位和自检。初始化流程里给一个足够长的延时,然后写配置寄存器。典型的配置项包括:
- 测温模式设置为连续转换模式;
- 转换分辨率设置到12位(对应0.0625°C的LSB);
- 使能远程测温通道;
- 设置报警阈值和极性。
配置寄存器的写操作示意如下:
uint8_t cfg[] = {0x00, 0x60, 0x10}; /* 第一个字节为寄存器地址,后续为配置数据 */ HAL_I2C_Master_Transmit(&hi2c3, (PJ85718DM_ADDR << 1), cfg, 3, 100);这里注意I2C通信地址要先左移一位,把7位器件地址转换成总线上的8位传输地址,这是新手经常忽略的地方。
4.2 读取本地温度与远程温度的数据解析
PJ85718DM的温度数据寄存器是16位的。读出顺序是先读高字节再读低字节,然后把两个字节拼成一个完整的ADC结果。
uint8_t buf[2]; int16_t raw; HAL_I2C_Master_Transmit(&hi2c3, (PJ85718DM_ADDR << 1), (uint8_t[]){0x01}, 1, 100); HAL_I2C_Master_Receive(&hi2c3, (PJ85718DM_ADDR << 1), buf, 2, 100); raw = (buf[0] << 8) | buf[1]; /* 符号处理:若高位为1,则为负温度 */ if (raw & 0x8000) { raw = -(~raw + 1); } float temp_local = raw * 0.0625f;12位温度数据左对齐存储在16位寄存器里,所以读取出来以后按照0.0625°C/LSB的系数换算即可。比方说raw等于0x0190时,温度就是400×0.0625=25°C。
远程温度的读取逻辑和本地温度大同小异,只是寄存器地址不同。需要注意的是,远程温度数据分辨率虽然是0.0625°C,但因为二极管探头的初始偏差比本地通道大一些,实际误差范围会比本地略大,这在器件手册里也有说明。
4.3 数据滤波与异常判断
直接从寄存器读到的温度值往往会有一些小幅波动,这主要来自环境噪声和ADC转换本身的量化噪声。我在项目中加了一级简单的软件滤波,用的是滑动平均和中值滤波结合的方式:
- 每100ms采集一次原始值,缓存最近5个点;
- 先取中间3个点做算术平均,避免偶发的尖峰毛刺对平滑结果产生过大影响;
- 最终结果再送进后续的闭环控制逻辑。
异常判断也不能省。HVAC现场偶尔会出现探头脱落或线路断开的故障,芯片内部逻辑会检测到远程通道的开路状态,并把温度寄存器设置成一个异常特征值。我在软件里做了对应处理:
if (raw == 0x7FFF || raw == 0x8000) { /* 远程探头异常,置故障标志 */ sensor_fault = 1; return; }这类判断逻辑平时用不上,但一旦现场出现故障,它能帮助维护人员迅速定位问题,避免系统拿着一个错误温度去控制风机和阀门。
4.4 报警阈值与中断逻辑
PJ85718DM还有一个很有用的功能:本地和远程通道都可以独立设置高低温报警阈值。当温度超过阈值时,ALERT引脚会被拉低,触发STM32H743ZI的外部中断。
这个功能相当于把温度检测的一部分工作卸载到传感器芯片上。MCU不需要一直轮询温度寄存器,只要在中断里读取标志位,知道是哪一路报警,然后做相应处理即可。这种设计在需要低功耗待机、或者CPU被其他任务占满时非常有用。
我在项目里是这样用的:把远程送风温度上限设为35°C,下限设为5°C;本地板温上限设为70°C。一旦触发报警,系统立刻调整风机转速并且在上位机显示告警。
5. 远程上报:让上位机看到实时温度
5.1 通信方案选型:Modbus RTU 与 RS485
数据采集到本地之后,最终要交给上位机。在HVAC行业里,Modbus RTU over RS485是事实上的标准协议,几乎所有楼宇自控系统都支持。选择这个方案有很实际的考虑:
- RS485是差分信号,抗干扰能力强,传输距离可以到几百米,非常适合设备间通信;
- Modbus协议结构简单,公开文档齐全,上位机组态软件基本都集成;
- 客户现有的PLC和网关设备都能直接对接,不需要额外开发私有协议。
STM32H743ZI的UART外设配一个RS485收发器芯片就可以了。硬件上更简单,现在很多收发器自带方向控制引脚,连DE和RE两个脚都可以合并成一个控制信号。
5.2 主从站程序框架与状态机
因为我做的是从站设备,程序逻辑相对简洁,用Modbus主站来读我的数据。每一帧请求收到以后,我需要做三件事:校验从站地址、校验CRC、解析功能码。
温度相关的数据我映射到了保持寄存器组里,地址安排如下:
| 寄存器地址 | 内容 | 数据类型 |
|---|---|---|
| 0x0000 | 本地温度(放大10倍) | 无符号整型 |
| 0x0001 | 远程温度(放大10倍) | 无符号整型 |
| 0x0002 | 设备状态标志位 | 位映射 |
| 0x0003 | 固件版本号 | 无符号整型 |
温度值放大10倍发送是为了兼容不支持浮点的上位机系统,27.3°C就发送273。这个做法在工业通信领域非常常见,既保留了小数点后一位精度,又避免了浮点字节序的兼容性问题。
帧接收用定时器加状态机的思路管理,接收完一帧数据后做校验,校验通过再组织响应帧。核心代码结构大致如下:
switch (rx_state) { case WAIT_ADDR: if (recv_byte == SLAVE_ADDR) rx_state = WAIT_FUNC; break; case WAIT_FUNC: func_code = recv_byte; rx_state = WAIT_DATA; break; /* ...后续状态处理 */ }Modbus RTU要求在3.5个字符时间内完成一帧数据的接收,超过这个时间就认为是下一帧数据的开始。我用STM32H743ZI的定时器输入捕获来做帧间隔测量,实测下来波特率9600和19200两种速率下帧边界识别都很准。
5.3 多节点组网与调试技巧
一台HVAC设备往往不止一个温度监控点,多台设备之间要组网。每台设备分配一个唯一的Modbus地址即可。PJ85718DM的A0和A1地址引脚可以区分四颗温度芯片,但我这里每台控制器只需要一颗PJ85718DM,所以从站地址直接用拨码开关设定,方便现场安装时灵活配置。
调试RS485通信时我推荐一个习惯:先用USB转485适配器接电脑,用串口调试助手直接发16进制帧数据,比用软件模拟快很多。排查不通的原因时,先检查收发器的方向控制引脚是否切换正确,再看TX/RX是否交叉,最后查波特率和校验位。这三个环节能排除九成以上的通信问题。
6. 实测数据与现场踩坑记录
6.1 实验室校准:恒温槽对比测试
软件流程跑通以后,我先把板卡送到实验室做对比测试。用恒温槽把环境温度控制在几个标准点,分别是0°C、15°C、25°C、50°C和70°C,然后用经过计量校准的铂电阻温度计做基准,读取PJ85718DM报告的本地温度值。
测试结果整理如下:
| 基准温度 | 本地温度读数 | 偏差 |
|---|---|---|
| 0.00°C | 0.19°C | +0.19°C |
| 15.00°C | 15.08°C | +0.08°C |
| 25.00°C | 25.04°C | +0.04°C |
| 50.00°C | 50.12°C | +0.12°C |
| 70.00°C | 70.21°C | +0.21°C |
这个数据在HVAC控制领域完全可以接受。全量程最大偏差0.21°C,系统性偏移也稳定,如果后续精度要求更高,完全可以在软件里做一个线性校正,把偏差进一步压缩。
远程通道的测试结果也差不多,偏差略高于本地,但还在规格范围内。
6.2 现场运行数据表现
现场安装后运行了两个星期,我来回看了后台记录的数据曲线。本地温度基本稳定在45°C上下,和电控箱内散热设计预期一致;远程送风温度随负载变化有波动,范围在18°C到23°C之间,响应速度也能跟上风机启停的变化。
对比之前的NTC方案,最明显的改善是稳定性。同样的安装位置,NTC方案夜间低温时段会出现周期性的一两度波动,分析半天没找到原因,怀疑是接线端子接触电阻随温度变化导致的。换成PJ85718DM加二极管探头后,这个现象直接消失了,温度曲线平滑了很多。
6.3 三个典型故障的排查全过程
项目过程中不是一帆风顺的,我遇到并解决了三个有代表性的问题,这里按时间顺序记录下来。
第一个问题是远程温度长时间卡在一个固定值不变。排查下来发现是探头三极管的引脚定义搞反了。我用的SOT-23封装,型号字面朝上时从左到右依次是基极、集电极、发射极,结果焊接时按普通三极管的习惯接法把集电极和基极接反了。检查电路图后修正处理,温度恢复正常。
第二个问题是RS485通信偶发性丢帧。逻辑上帧格式、CRC都对,但上位机就是间歇性收不到数据。后来用示波器抓波形,发现是收发器方向切换时间不够,响应帧发送完以后立刻把方向切回接收状态,最后一个字节因为驱动器还没完全释放而丢失。解决办法是在发完最后一个字节以后加一个几百微秒的等待延时,等总线释放干净再切方向。
第三个问题是PJ85718DM本地温度在半夜突然跳高。后来定位到是设备在凌晨主动启动电加热除湿功能,功率器件发热导致板温上升。这是正常的物理现象,不是故障。我在软件里针对这个场景做了一个时间窗口判断,把除湿时段的板温报警阈值放宽,避免误告警。
7. 常见问题速查表与工程师避坑清单
7.1 问题、原因与解决办法速查表
把我在开发和现场遇到的典型问题整理成一张表,方便大家遇到类似情况时快速定位。
| 故障现象 | 可能原因 | 解决办法 |
|---|---|---|
| I2C通信一直返回超时 | 上拉电阻缺失或过大 | 按总线速率选择4.7kΩ上拉 |
| 远程温度偏高几度 | 线缆电阻过大未做抵消 | 配置串联电阻抵消功能或缩短线缆 |
| 温度在某个值上下跳变 | 探头接触不良或引脚焊反 | 重新焊接探头,检查三极管极性 |
| 所有温度都是0x7FFF | 远程通道开路故障 | 检查探头线路是否断开 |
| 本地温度偏高 | 芯片靠近热源或自热 | 增加散热距离,调整布局 |
| RS485丢帧 | 方向控制切换太快 | 发送后增加释放延时 |
| MODBUS读不到数据 | 地址冲突或波特率不一致 | 检查从站地址和串口参数 |
7.2 一些额外的小建议
最后再分享几个这轮项目里积累的小经验。
关于PJ85718DM的配置,初始化代码里务必检查写操作后回读的配置值是否一致。I2C总线偶尔会有错位,如果配置字写错了,温度数据没准也能读出来,但工作模式不对会导致报警逻辑失效。加一个写后回读验证,成本极低,收益却很实在。
关于探头的连接方式,远程二极管测温使用的三极管一致性远比想象中重要。我对比过同一批和三批混用的料,批次一致的情况下无需单独校准,混料后误差能明显增加。量产时控制探头物料批次是个容易被忽视但非常关键的点。
关于H7系列的调度,如果主控上还有其他实时性要求很高的任务,比如PWM控制或高速通信,需要给I2C读取任务一个充足的优先级和合理的分时调度窗口。STM32H743ZI性能很强,但也不能掉以轻心,温度采集这个任务虽然简单,它却是一个持续数据来源,一旦调度卡顿,后续滤波和控制逻辑全部会出问题。
这个项目从原理图到量产经历了三轮改板,最终的方案其实并不花哨:一颗数字温度传感器做本地和远端探头采集,一颗高性能MCU做数据处理和通信上报,硬件上注意供电和布局,软件上做好滤波和故障检测,剩下的就是踏实解决问题。希望我踩过这些坑的记录,能帮你少走些弯路。