1. 为什么盯上这块板先把应用场景和选型逻辑说清楚先别急着看代码温度监测这活儿看似简单真正落到嵌入式设备和暖通空调系统里坑比想象中多。我最近做了一个小项目需求很明确既要监测设备主板附近的本地温度又要测量安装在几米甚至十几米外的风管、回风口的远程温度而且成本要压得足够低通讯要足够皮实。选芯片的时候我第一次看到PJ85718DM这颗料第一反应是这不就是常见的单总线数字温度传感器换了个丝印吗但仔细翻了手册之后发现事情没那么简单。它和主控之间只用一根数据线就能通信一条总线上可以挂多个传感器每个传感器有唯一的64位序列号主机可以精确寻址到每一个。这一点对于“本地远程多点测温”来说简直是量身定做的——不需要额外铺电源线、信号线、地线三根线到处跑一根双绞线串过去就完事了。主控这边选了STM32F042K6核心是Cortex-M0内核主频48MHzFlash 32KBRAM 6KB。你可能觉得性能很一般但做温度采集这种任务它绰绰有余。选它而不是更大容量的G0系列或F1系列理由很现实首先F042的性价比高做产品BOM核算有优势其次M0内核在极低主频下跑温度采集协议功耗表现比F1那种M3核心更友好最后这颗料引脚少、封装面积小适合放进HVAC控制器那种紧凑的PCB里。设备要采集的点位大概是这样的本地传感器放在主控板上测的是控制板自身的工作温度用来做降额保护和过热告警远程传感器放在空调箱的送风口、回风口、冷凝器盘管这些关键测点用来判断制冷制热效果、防结冰、辅助除霜逻辑。距离最近的大概0.5米最远的将近12米。这就引出了整个项目的核心矛盾一根线跑十几米信号还能不能可靠驱动代码怎么写才能在不同的线缆长度、不同的供电方式下稳定工作接下来我把整个设计和调试过程拆开讲。这套思路不仅适合HVAC你如果做储能电池包的电芯温度采集、冷库物联网终端、机房动环监控同样能用上。2. 硬件拓扑设计本地就近挂载远程长线传输细节都在布线里2.1 先画一下整体架构主控板放在控制器外壳里板上焊一个PJ85718DM这就是本地测点外部温度传感器通过一个两线制接插件引出线的另一端是防水封装的PJ85718DM探头这就是远程测点。主机的GPIO端口接单总线总线上挂两个传感器。这里有必要说一句单总线协议在设计上是支持多点挂载的理论上一条总线挂几十个器件也没问题但实际工程中要克制。挂得越多总线的寄生电容越大时序裕量越差。我这几个测点只有在空调箱的送风口和回风口才需要分开两个远程探头所以总线上最多就三颗器件一颗本地板载两颗远程探头。这个规模对时序来说毫无压力。2.2 供电方式的选择寄生供电与外部供电之争很多刚接触单总线传感器的人在供电上会迷路。这类传感器支持两种供电模式寄生供电只有两根线一根数据线一根地线传感器从数据线上偷电内部电容在总线上拉高电平时充电。这个模式好处是省一根线坏处是如果线太长、电容太大转换温度时的浪涌电流会把总线电压拉垮导致读数异常。外部供电三根线VDD、DQ、GND传感器转换温度时由外部电源直接供电总线只负责通信稳定得多。我这个项目里本地板载传感器用外部供电因为PCB上电源到处都是顺路引一个3.3V就行。远程探头我也选择了外部供电但注意我没让远程探头直接吃主控板上的3.3V而是用一对接线端子把VDD和GND也引出去了总共三根线。很多HVAC控制器为了省事远程探头只引两根线让传感器寄生供电。这种做法在5米内通常没事但在10米以上、线径又细的场景温度转换时容易出现偶发性的85℃误读或者CRC校验失败。要说明的是选外部供电并不代表三根线一定要走很粗的线。我用的是一般的屏蔽双绞线其中一组双绞线走DQ和GND另外单独一根线走VDD而且VDD在远程探头端又加了一个10μF的电解电容和一个100nF的瓷片电容用来在转换瞬间给传感器“撑腰”。这样试下来12米的线缆也能稳定运行。2.3 上拉电阻怎么选3.3V系统里别照抄4.7kΩ单总线是漏极开路结构主机和传感器通过拉低总线来发送信号不发送时靠上拉电阻把总线拉回高电平。官方推荐的上拉电阻典型值是4.7kΩ。但在实际项目中这个值要结合供电电压和线缆长度重新算。我的系统供电是3.3V主控GPIO也是3.3V电平。如果照抄5V系统里的4.7kΩ在3.3V下上拉电流只有0.7mA左右而这颗传感器在通信时需要约1.5mA的电流驱动总线电容和内部电路结果就是信号上升沿变得很缓时序余量不足单片机在高速读取时容易采到错误的电平。我实际试过几组电阻值用示波器看波形之后确认3.3V系统、10米左右线缆最佳的匹配是2.2kΩ上拉。如果线缆进一步延长到20米以上甚至可以用1kΩ。电阻值太小也不行会加大总线寄生电容的充放电损耗更重要的是当传感器拉低总线时上拉电阻越小灌入传感器的电流越大长期高温环境下可能会导致器件老化加速。这里还要提醒一下有些开发板上的上拉电阻是焊死的我一开始在某款现成的最小系统板上做实验板上默认就是4.7kΩ跟远程探头配合就有偶发失败。后面打样自己画板子才把上拉改成2.2kΩ。如果你是在现有板卡上调试不想动板子也可以把GPIO配置成开漏输出并内部使能上拉但内部上拉一般只有几十kΩ级别效果远不如外部电阻所以最好的方案还是在PCB设计阶段就把上拉电阻的选型定好。2.4 远程线的防护HVAC环境里别忘了TVS和滤波空调箱附近有压缩机、风机电机这些东西启停瞬间会产生很强的电磁干扰远程探头线缆相当于一根天线会把干扰信号带进控制板。有些项目在实验室里调试一切正常一到现场就频繁读到-55℃或者传感器搜索不到多半就是干扰问题。我对远程线的做法是接插件入口处在DQ线上串一个100Ω的电阻这个电阻要和上拉电阻的位置配合好——上拉在主机端串阻在传感器端同时DQ对地加一个TVS二极管选反向关断电压在5V附近的规格用来吸收静电和浪涌在PCB布局上远程端子、TVS、上拉电阻尽量靠近主控GPIO引脚避免“先长走线再防护”的低级错误。这三板斧下来现场干扰的影响基本可以忽略。3. 驱动协议拆解一次复位、一次ROM匹配、一次温度转换背后都在干什么3.1 单总线时序的几个关键窗口单总线协议的基本时序分三种复位脉冲、写时隙、读时隙。任何一个时序的宽度不在合法范围内通信就会断。我先把这几个关键窗口按PJ85718DM手册数值列出来后面写代码时再把这些数值揉进延时逻辑里。复位脉冲主机先将总线拉低至少480μs然后释放总线传感器在15~60μs之后拉低总线约60~240μs作为存在脉冲主机在发出复位脉冲之后需要在一个窗口内采样总线电平如果读到低电平说明有传感器在线。写时隙主机拉低总线开始一个时隙然后决定在时隙的前段释放还是继续拉低。如果主机想写0就把总线拉低整个时隙的大约60μs如果写1就只拉低约6μs然后释放靠上拉电阻把总线拉高。传感器在写时隙开始后15~60μs窗口内采样总线。注意写0时隙的持续时间必须在60~120μs之间写1时隙的释放后部分不能太短否则传感器可能无法识别。读时隙主机拉低总线至少1μs然后释放紧接着在15μs内采样总线电平。传感器如果发0会在主机释放总线后把总线拉低如果发1就保持高电平。所有读时隙必须在一个60μs左右的周期内完成而两次读时隙之间至少要间隔1μs的恢复时间。对于48MHz主频的STM32F042K6如果你用HAL库的延时函数来凑这些时序往往会因为函数调用开销导致时序偏差尤其是读时隙往往需要在采样前后框定精确的时间窗。我在实际代码里没有用HAL_Delay而是直接用SysTick或者简单的循环计数来做微秒级延时这一点在驱动效率上差别很大。3.2 从零写一套驱动初始化、ROM搜索与温度转换流程整个驱动流程可以拆成四步初始化总线、枚举总线上所有传感器序列号、对指定传感器发起温度转换、读取温度结果。前两步不是每次测温都要做尤其是枚举只有上电时做一次把序列号存起来之后直接通过ROM匹配命令来寻址目标传感器。初始化很简单GPIO配置成开漏输出拉低480μs释放然后等传感器回复存在脉冲。代码类似这样#define DQ_PIN_PORT GPIOA #define DQ_PIN GPIO_PIN_8 static uint8_t ow_reset(void) { uint8_t presence 1; GPIO_InitTypeDef gpio {0}; gpio.Mode GPIO_MODE_OUTPUT_OD; gpio.Pull GPIO_NOPULL; gpio.Speed GPIO_SPEED_FREQ_LOW; gpio.Pin DQ_PIN; HAL_GPIO_Init(DQ_PIN_PORT, gpio); HAL_GPIO_WritePin(DQ_PIN_PORT, DQ_PIN, GPIO_PIN_RESET); delay_us(500); HAL_GPIO_WritePin(DQ_PIN_PORT, DQ_PIN, GPIO_PIN_SET); delay_us(30); gpio.Mode GPIO_MODE_INPUT; gpio.Pull GPIO_PULLUP; HAL_GPIO_Init(DQ_PIN_PORT, gpio); delay_us(50); if (HAL_GPIO_ReadPin(DQ_PIN_PORT, DQ_PIN) GPIO_PIN_RESET) { presence 0; } delay_us(450); return presence; }注意GPIO先配置成开漏输出再切到输入模式。开漏模式下写入高电平相当于释放总线这是单总线操作的基本功。有些新手把GPIO配成推挽输出直接写1来释放总线这在总线上同时有多个开漏器件时会出问题——推挽高电平会拖着其他器件拉低的总线电位造成通信紊乱。ROM搜索本身有点绕它本质上是二叉树遍历主机依次读取每一位的两位码第一位表示传感器在该位上的值第二位表示相反值通过比对这两个电平可以判断当前节点是分支还是终点。对于只有两三个传感器的系统还有一个更粗暴但有效的办法直接用读取ROM命令0x33在有且仅有一个传感器时读取64位序列号。如果总线上挂了多颗则必须用搜索算法。我写的搜索函数每次可以返回一个序列号反复调用直到返回0表示全部枚举完成。温度读取这块我建议流程固定为先向目标发送ROM匹配命令0x55随后发送它的64位序列号再发送温度转换命令0x44等待转换完成至少750ms——PJ85718DM在12位分辨率下最大转换时间是750ms然后再发一次ROM匹配发读取暂存器命令0xBE连续读9个字节。第0、1字节是温度值第8字节是CRC校验。3.3 CRC校验不能省场景越恶劣越要较真刚才提到读回来9个字节最后一个是CRC。很多示例代码读温度时光顾着拼字节不看校验这在实验室环境也许能跑一整天不出错到了现场就是灾难。单总线的CRC算法是多项式x^8x^5x^41也就是0x8C初始种子是0。我实测下来远程线缆在受到干扰时出现的错误形态有两种一种是读回来的数据直接是0xFF或0x00一眼就能看出来有问题另一种比较坑温度值看起来完全合理比如从23.5℃变成了27.3℃但CRC校验是错的这种情况如果没有校验逻辑系统就会把假温度当成真温度用轻则控制逻辑误判重则可能触发不该有的告警。我在驱动里每次读完暂存器都会跑一遍CRC计算如果失败就重新发送读取命令重试连续重试3次都失败就丢弃这次数据标记该通道为故障。在长时间运行测试中12米线上CRC失败的偶发率大概在千分之一量级重试基本都能成功。如果你发现重试也救不回来那基本不是时序问题而是要检查硬件了比如上拉电阻、线缆屏蔽层接地这类。4. 软件架构怎么搭把温度采集做成一个可靠的状态机4.1 用状态机管理测温流程不要把延时函数糊在main里如果你之前是从某个示例代码复制粘贴开始做的可能会习惯这么写main循环里先发转换命令延时750ms然后读温度。这个写法在单测点场景没毛病但在多传感器、多测温周期还要兼顾HVAC控制逻辑的产品里基本没法用。原因很简单750ms的阻塞延时意味着整个控制主循环被卡死按键扫描、通讯轮询全部停摆这在一个实时控制设备里是不可接受的。我的做法是把测温流程拆成一个状态机放在10ms周期的主循环里调度。状态定义如下空闲什么都不做等待下一次测温周期到来启动转换对指定传感器发送温度转换命令等待转换记录启动时间不断查询是否已到750ms到点后跳到读取状态读取暂存器发送读取命令并接收9个字节每个状态只做自己该做的事一旦遇到耗时操作比如发送复位脉冲的500μs延时就用阻塞方式原地等待因为500μs对于10ms的调度周期来说不算什么。真正需要跨周期等待的是750ms转换时间用时间戳判断不阻塞。主机始终只和当前选中的传感器通信。先用ROM匹配命令锁定目标之后再发转换命令或读取命令。这样多个传感器轮询时不会乱套。4.2 测温周期与滤波策略HVAC控制不能直接拿原始值用测温周期我设的是1秒。空调系统的热惯性很大1秒采一次完全够用温度控制环路用的是每5秒的均值每秒的瞬时值只用于故障诊断和界面显示。软件滤波我采用了两个手段配合一是滑动平均取最近5次有效读数的平均数二是变化率限幅如果新读数跟上一次有效值的差超过3℃——远程探头安装在风管里正常工况下1秒内的温度变化不可能这么大——就认为是一次干扰丢弃该数据连续丢弃5次则把实际温度强制更新为新值防止在真实温度突变时滤波过于迟钝。这里有一个容易踩的坑滑动平均窗口里的历史值如果包含了非法数据会拖慢真实变化的响应速度。所以我只在全部数据都通过CRC校验和范围检查之后才入窗。范围检查很简单传感器本身只支持-55℃到125℃如果读出来是-55℃大概率不是真实温度而是传感器供电丢失或者总线时序完全错乱。我设置的有效范围是-40℃到80℃超出即判无效。4.3 多传感器管理序列号映射与故障标志位两个传感器用数组管理每个节点结构体里保存64位序列号、当前温度值、滤波值、最后一次成功通信时间戳、连续故障次数。上电时先尝试枚举如果总线上只有两颗传感器而实际枚举出来也是两颗就把它们按序列号分别映射到本地和远程两个逻辑测点。比较麻烦一个场景是产品量产时序列号各不相同不能通过固件硬编码。我的做法是在出厂校准环节把枚举出来的两颗序列号按顺序写入Flash实际使用时如果枚举结果顺序变化就通过一个简单的排序序列号小的当本地测点大的当远程测点。这个映射规则有点无厘头但对于固定两颗传感器的产品是稳定可靠的不会因为上电时序不同导致本地和远程数据互换。故障处理上连续读取失败超过10次就把该测点标记为故障温度显示为“--”控制逻辑切到保守模式如果是冷凝器盘管温度传感器故障就不再启动制冷防止盘管结冰如果是送风温度故障风机仍然运行但停止调节阀门保持在上一次安全开度。这样即使传感器彻底挂了设备也不会出安全事故。5. 实测过程中的几个经典翻车现场5.1 翻车一第一版PCB温度读回来全是85℃这个问题我在网上看到很多人遇到过也花了不少时间排查。85℃这个值很特殊它其实是传感器上电后的默认温度寄存器的复位值。如果主机读到的温度一直是85℃说明传感器根本没有成功执行温度转换命令寄存器只停留在复位状态。换了个传感器还是85℃基本就排除了传感器本身的故障。最后定位到根因我在发送温度转换命令之后切换GPIO模式的时候把关断输出配错了导致总线在传感器转换期间没有被可靠上拉传感器压根没收到有效的转换指令。解决方法是把总线释放的操作统一封装成一个函数确保GPIO永远是开漏输出高电平而不是在输入模式间来回切换——开漏输出高电平和输入模式虽然电气效果一样但在模式切换的瞬间可能产生毛刺直接把命令时序破坏掉。5.2 翻车二远程探头低温读数在0℃附近频繁跳动当时的现象是温度在0~5℃区间来回跳而且只有距离最远的那颗探头这样。我用示波器抓DQ线上的波形发现远端传感器发出的读时隙信号上升沿非常缓在主机采样时电平还处于0.8V左右的模糊区读到的比特位不稳定。这个问题的根源是线缆分布电容太大。双绞线每米大约有50pF电容12米就是600pF再加上传感器的输入电容总线总电容接近800pF。上拉电阻2.2kΩ给800pF充电的时间常数是1.76μs在标准读时隙的采样窗口内电压刚好爬升到阈值附近非常危险。我把上拉电阻从2.2kΩ降到1kΩ实测波形上升沿改善明显再没出现跳动。注意此时上拉电流会接近3.3mA传感器拉低总线时的灌电流也增大了发热会略有增加但仍在器件允许范围内。如果线缆更长比如超过20米我建议直接把传感器换成电流源方式驱动总线或者改走RS485组网别硬撑着单总线长距离传输。5.3 翻车三示波器探头一接上去就好一拿下来就坏这个现象特别迷惑但它真的发生在调试过程中。问题的本质是示波器探头本身有大约10MΩ的输入阻抗和十几pF的电容探头接上去相当于给总线增加了一个很小的负载但同时它改变了地回路——确切地说把设备地和示波器的地连在了一起无意中给远程线缆的屏蔽层提供了更好的接地路径。去掉探头后屏蔽层悬空干扰信号重新进来故障复现。所以最终解决方案不是依赖示波器而是给远程线的屏蔽层单独做接地处理屏蔽层在控制器端接地传感器端悬空避免形成地环路。现场设备的地线质量很重要HVAC这类设备经常被安装在没有独立地线的环境里屏蔽层接了大地干扰问题才彻底解决。6. 低功耗与量产细节从能跑到能卖之间还差几步6.1 在电池供电设备里压低功耗如果你的场景是电池供电的冷柜温度记录仪那功耗控制就要更激进。STM32F042K6支持多种低功耗模式在两次测温之间完全可以从Stop模式唤醒。我的做法是把传感器和主控的单总线GPIO都配置成外部中断模式传感器没有通信时不活动主控睡在Stop模式下用RTC定时器每10秒唤醒一次整个过程耗时不到30ms剩余99.7%时间都在睡觉。这10秒一次的测温周期下实测平均功耗能压到几十微安级别对于一节18650电池来说理论续航可以到一年以上。但要注意传感器本身在等待期间会有一点静态功耗如果整机要求极低功耗还可以用一颗MOS管控制传感器的VDD只有测温时才通电这样等于把传感器的静态功耗也掐掉了。代价是每次测温前要给传感器留出至少100ms上电稳定时间否则第一读永远是失败的。6.2 量产测试与校准每颗传感器的误差不要轻信规格书这类单总线传感器的精度一般在±0.5℃范围内但这是在理想条件下的数值。实际上传感器封装内部的引脚焊接应力、PCB走线的热传导、探头外壳的导热介质都会引入额外误差。我见过一块板子上两颗传感器测同一个点读数相差1.2℃的情况。所以在产品出厂前我建议做一次单测点校准在一个恒温槽里以0℃和50℃两个标准温度点做校准把每颗传感器的偏差存进Flash在实际显示温度时做线性纠偏。校准的线性纠偏也就是做一个两点拟合求出偏移量和增益系数。量产后发现绝大多数器件的增益偏差很小问题都在偏移上所以大多数厂家只做零点校准就够了。具体的实现逻辑是typedef struct { int16_t offset; // ADC/计数偏移量单位0.1℃ int16_t gain; // 增益修正系数默认1000表示1.000 } temp_cal_t;如果25℃时读书偏高0.4℃offset存-4单位0.1℃即可。如果50℃时偏高0.2℃25℃时偏高0.4℃那么gain可以调整成1002左右用一个简单的直线方程去修正全量程。这个校准动作对于工业级设备来说很重要因为HVAC系统里温度测点的偏差会直接影响压缩机启停判断偏差大要么导致频繁启停浪费电要么导致房间温度永远达不到设定值。7. 最后再分享一点现场经验调试这类单总线多点测温系统我最大的体会是硬件上的问题往往伪装成软件问题而软件上的问题又常常通过硬件现象暴露出来。比如读温度偶发失败你可能会拼命调延时参数、改滤波逻辑但实际上就是某个GPIO在模式切换时产生了微秒级毛刺反过来你以为上拉电阻换个阻值就能搞定结果发现是远程线的屏蔽层没有接地。所以排查问题的时候示波器要跟代码一起看时序波形和寄存器数据要互相对照。如果你现在要做的项目和我类似我先给你的建议是只要传感器总线上挂超过两颗或者线缆长度超过5米就果断用外部供电别省那一根线上拉电阻按线缆长度实测调整不要拘泥于规格书上的典型值驱动代码里CRC校验是底线绝不能省。这套方案做冷库、做机房、做风管测温都适用把时序和硬件搞扎实了剩下的事情就只是换壳子。
阅读完成 · 觉得有帮助?