☰
STM32F0与PJ85718DM单总线实现本地远程温度采集
2026/10/22 12:11:08 网站建设 项目流程

干嵌入式开发这么多年,温度测量这种活计,看着简单,做起来全是细节。尤其是暖通空调这种场景,控制器往往装在电气盒里,传感器却可能在风道、盘管或者室外机组上,距离从几十厘米到几十米不等,旁边还蹲着变频器、压缩机和风机这类干扰源。这段时间我搭了一套温控监测电路,主控用了一颗 STM32F042C6,温度传感器用的 PJ85718DM,一根单总线同时接本地和远程两个传感器,实现了本地温度和远程温度的同时采集。项目做下来踩了不少坑,今天把这些经验整理出来,给打算做类似方案的伙计们一个参考。

1. 项目拆解:嵌入式与 HVAC 场景下的温度监测需求

1.1 本地温度和远程温度到底指什么

先说清楚一个容易含糊的点:标题里的“本地温度”和“远程温度”,在暖通空调里可不是随便叫叫的。很多温控器出厂时只有一个传感器,装在机器内部,测的是机箱内空气温度,这就是最常见的“本地温度”。但真正的现场需求往往不止一个点:回风口温度、出风口温度、盘管表面温度、室外环境温度,这些测量点离控制器有远有近,传感器放在设备深处或者风道里,就是“远程温度”。

我这套方案里,本地传感器直接焊接在主控板上,紧挨着 MCU,用于监测控制盒内温度和作为系统自身状态参考;远程传感器通过接线端子引出,放到实际需要控温的位置,比如空调风道或者换热器附近。两个传感器型号一致,都是 PJ85718DM,走的同一条单总线,但用不同的 ROM 地址区分。这里的“本地”和“远程”是物理位置上的区分,不是电气定义上的区分,固件层面必须靠传感器唯一编码来识别,这一点后面会详细说。

为什么本地温度也值得单独测?很多人觉得机箱内温度不重要,其实不然。控制器电路板本身会发热,电源模块、驱动管、MCU 都是热源。如果本地温度过高,说明散热风道堵了或者环境温度超标,这本身就是一条重要告警。我在样机上把本地传感器放在 MCU 旁边,实测板温比环境温度高 3 到 5℃,这个数据后来被用来做温度补偿,对整机寿命判断很有用。

1.2 为什么放弃模拟传感器而选数字单总线

早期很多暖通控制器用 NTC 热敏电阻,因为便宜。但模拟方案在“本地 + 远程”这种场景下非常难受:每路传感器都要占用一个 ADC 引脚,还要配分压电阻、滤波电容,生产时还得逐路做校准。最重要的是,远程传感器一旦拉出两三米线,线阻、接插件接触电阻、现场干扰都会直接影响采样电压,温度值飘来飘去,最后做出来的产品良品率很难看。

PJ85718DM 这类数字单总线传感器就完全不同。它内部自带 ADC 和校准,输出直接就是数字温度,主控不用关心模拟电压换算,线路上传的是数字脉冲,抗干扰能力比模拟信号强很多。它的协议是单总线,一根数据线就能挂多个传感器,每个传感器有 64 位唯一 ROM 编码,天然支持多点采集。对于本地一个、远程一个,甚至未来要扩展成八个、十个测温点,硬件上都不需要再增加引脚。

I2C 传感器我也考虑过。I2C 在板内通信很好用,但两条线加上电源和地,远程线缆至少要四根;而且 I2C 对总线电容和线长敏感,超过一米就容易出现时序问题。单总线只有一根数据线,加上电源和地总共三根线,线长长一点影响也小,非常适合从控制器引出到风道、盘管这种物理距离较远的场景。虽然单总线速度很慢,但温度本身是缓变信号,一秒更新一次绰绰有余,慢速换抗干扰能力,完全值当。

2. 器件选型:STM32F042C6 与 PJ85718DM 的组合逻辑

2.1 STM32F042C6 有哪些点正好踩中需求

STM32F042C6 是 ST 的 Cortex-M0 内核 MCU,主频最高 48MHz,Flash 32KB,SRAM 6KB,封装是 LQFP48,工作温度范围 -40℃ 到 85℃。这颗芯片在暖通控制场景里非常合适:主频不高但足够跑温度采集、通信和控制算法;Flash 不大但放一套单总线驱动、温度处理、Modbus/CAN 协议栈绰绰有余;M0 内核功耗低,整机温升小,这对摸机箱温度监控反而有利。

外设方面,这颗 MCU 不但有 USART、SPI、I2C 和 12 位 ADC,还有 CAN 控制器和 USB 设备控制器。暖通空调里很多风机盘管、冷热源机组之间的通信用的就是 CAN 或者 Modbus。我最后选了 CAN 作为对外上报温度数据的通道,因为 CAN 总线在工业现场的抗干扰能力和多节点组网能力都更好,STM32F042C6 直接带 CAN 控制器,只需要外接一个 CAN 收发器就行。

这颗 MCU 还有一个容易被忽略的优势:它的 GPIO 大多可以容忍任意配置成开漏模式,这对单总线操作非常关键。单总线要求主机引脚既能拉低总线,又能释放总线让外部上拉电阻把电平拉高,开漏输出正好就是干这个的。很多老款 8 位机虽然也能做,但引脚模式切换麻烦,或者内部上拉电阻太小影响时序,STM32F0 系列用起来顺手得多。

2.2 PJ85718DM 的角色与实测表现

PJ85718DM 是一颗单总线数字温度传感器,指令集和时序与常见的 DS18B20 兼容,这也是我敢直接拿过来用的原因。它有三个引脚:VCC、GND 和 DQ,供电范围比较宽,标称工作范围和精度覆盖了暖通空调常用区间,在风道、盘管这种温度场景里完全是杀鸡用牛刀。

需要说明的是,这颗传感器出厂时内部已经有校准数据,接上就能用,不需要每个传感器单独做温度校准,这是数字传感器最大的省心之处。你只需要按单总线协议发起温度转换,等一段时间,再把暂存器里的原始值读出来乘以分辨率系数,就能得到温度值。我在样机上实测,本地传感器和远程传感器在恒温环境下读数差距在 0.2℃ 以内,对于 HVAC 控制来说已经完全够用。

这颗传感器的功耗不高,正常温度转换时电流在毫安级,待机时几乎不耗电。我的系统里用了低功耗设计,多数时间让 MCU 进入 STOP 模式,只有定时唤醒做温度采集和上报,整体平均功耗控制得很好。如果你对功耗更敏感,还可以在转换完成前让 MCU 睡一觉,等时间到再醒。

2.3 选型时容易忽略的几个坑

第一个坑是上拉电平。PJ85718DM 虽然可以用 3V 到 5.5V 供电,但 STM32F042C6 的 GPIO 不等于 5V 容忍,你在 5V 系统下用上拉到 5V 的单总线,MCU 引脚很可能会被反向电流搞坏。我们的板子统一用 3.3V 供电,单总线上拉电阻也接到 3.3V,这样 MCU 和传感器都在同一电压域,最稳妥。如果你想用 5V 传感器,中间必须加电平转换,不要把 5V 直接怼到 MCU 引脚上。

第二个坑是 PA11 和 PA12 的复用冲突。STM32F042C6 的 CAN 控制器引脚是 PA11 和 PA12,但 USB 控制器也用这两个引脚,两者不能同时使用。我在规划引脚时一开始想“反正 CAN 和 USB 都有外设,全都配上”,后来仔细看数据手册才发现冲突,只能二选一。最后选了 CAN 作为上行通信口,USB 就没法用了。设计定点前一定要把外设引脚冲突排查一遍,别等画完板再改。

第三个坑是 Flash 和 RAM 浪费。我曾经在一个类似项目里用了带完整实时操作系统的方案,结果为了跑系统把 RAM 吃掉了大半,温度采集这种任务用裸机轮询或者简单调度就足够了,STM32F042C6 的 6KB RAM 根本不用省着用。过于复杂的软件架构在这个项目里只会增加调试成本。

3. 硬件设计:把本地和远程传感器接在同一根总线上

3.1 引脚规划与最小系统

我用的引脚分配是这样安排的:单总线数据引脚用 PB5,配置为开漏输出,外部接上拉电阻到 3.3V;调试串口用 USART2 的 PA2 和 PA3;对外通信选择 CAN 用 PA11 和 PA12,外接一个 CAN 收发器;如果需要 Modbus,还可以用 USART1 的 PA9 和 PA10。SWD 调试口在 PA13 和 PA14,这两个引脚不要挪作他用,除非你想把调试工具点废。

功能引脚配置说明
单总线 DQPB5开漏输出,外部 4.7kΩ 上拉到 3.3V
调试串口PA2(TX) / PA3(RX)USART2,9600 或 115200
CAN 通信PA11(RX) / PA12(TX)外接收发器和终端电阻
Modbus 可选PA9(TX) / PA10(RX)USART1,可复用
SWD 调试PA13 / PA14不用于其他功能

最小系统其实很简单:STM32F042C6 需要一组 3.3V 电源和若干个 100nF 去耦电容,电源入口放一个 10μF 电解电容或者钽电容。虽然这颗 MCU 内部有 RC 振荡器,但暖通现场有温度漂移和干扰,我建议外接一个 8MHz 晶振,让系统时钟更稳。复位引脚接一个 10kΩ 上拉电阻和 100nF 电容,这是 ST 官方推荐的典型复位电路。

上电时 MCU 默认从 Flash 启动,不需要额外配置启动引脚。LQFP48 封装焊盘间距不算密,手工贴片难度不大,样品阶段用热风枪也能焊上,但如果量产建议直接交给贴片厂。板上预留一个 3 引脚插针给本地传感器,再预留一个端子给远程传感器,两个传感器并联到同一条数据线上。

3.2 上拉电阻与远程电缆的关键设计

单总线最基本的要求是数据线上必须有一个上拉电阻。我本地传感器在板内走线很短,远程传感器线缆最长到三米,整体总线电容并不夸张,所以首选阻值是 4.7kΩ。如果现场线长超过五米,建议把上拉电阻降到 2.2kΩ,让上升沿更陡,否则总线电容一大,信号半天抬不到高电平,时序就容易出问题。

远程传感器的线缆建议用三芯屏蔽线:一芯给 VCC,一芯给 GND,一芯走 DQ 信号,屏蔽层在控制器侧单端接地。千万不要两端都接地,否则地电位差会形成地环路电流,反而把干扰引进来。我踩过一次跟变频器共用电源地线的情况,远程读数从 25℃ 跳到了 40℃,后来把传感器供电单独用一路低噪声电源,读数才稳定下来。

连接器位置要加 ESD 保护。远程线缆是从设备外面引进来的,很容易感应静电或者被雷击浪涌打到,我习惯在连接器旁边放一只双向 TVS 二极管,钳位到 3.3V 电源轨,或者用低电容的 TVS 并联在 DQ 线对地上。这样做的好处是总线被瞬态高压打的时候,MCU 引脚不会先烧掉,损失最多是一颗几毛钱的二极管。

3.3 本地和远程传感器的安装工艺

本地传感器虽然叫“本地”,但也不是随便找个地方焊上就行。我把本地传感器放在 MCU 对角的位置,远离功率 MOSFET 和电感,这些器件工作时会产生高频开关噪声,离太近会让传感器供电质量变差,影响转换稳定性。传感器引脚旁边放一个 100nF 去耦电容,效果立竿见影。

远程传感器如果是放到风道里,最好买带金属护套或者环氧封装的探头,原厂裸传感器直接接线在现场是不可靠的,冷凝水、灰尘、腐蚀性气体会让传感器在几个月内失效。探头安装时尽量让感温头对着气流方向,不要贴死金属风道壁,否则测的是管壁温度而不是气体温度。还有一点,传感器接头不要放在风道积水区,现场难配平又容易结露短路。

两个传感器连接到同一条总线上之后,软件上要不要区分谁是谁?这是我一开始没想清楚的地方。你可以用硬件的办法:本地传感器固定焊在板内,远程传感器从端子接入,上电时总线连接关系固定有序;也可以让软件在第一次启动时扫描所有 ROM 地址,然后根据预设规则绑定。我最后采用了“先扫描、后绑定”的方式,把本地传感器的 ROM 地址和远程传感器的 ROM 地址分别存在配置区里,更换传感器时重新执行一次绑定流程,这样灵活性最高。

4. 固件实现:从底层时序到应用层温度值

4.1 初始化单总线引脚

固件工程我用的是 STM32CubeMX 生成的基础框架,外设初始化代码自动生成,但在单总线引脚这里我做了一点自定义:把 PB5 配置成开漏输出,并且开启内部上拉。外部已经有了 4.7kΩ 上拉电阻的话,内部上拉可以不开,我开主要是为了在极端情况防总线悬浮,实际使用没什么坏处。

#define OW_PORT GPIOB #define OW_PIN GPIO_PIN_5 #define OW_SET() (OW_PORT->BSRR = OW_PIN) #define OW_CLR() (OW_PORT->BRR = OW_PIN) #define OW_READ() (HAL_GPIO_ReadPin(OW_PORT, OW_PIN) == GPIO_PIN_SET) void bsp_onewire_init(void) { __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitTypeDef gpio = {0}; gpio.Pin = OW_PIN; gpio.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出,释放时为高阻 gpio.Pull = GPIO_PULLUP; // 内部上拉,可开可关 gpio.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(OW_PORT, &gpio); }

注意这里的开漏模式是关键。如果配置成推挽输出,拉低之后想释放总线就必须切换成输入模式,频繁切换容易引入毛刺。开漏模式拉低就是输出低,置高就是释放总线,由外部上拉把电平拉高,这正是单总线主机最理想的工作方式。

微秒级延时我用的是 DWT。STM32F042C6 内置数据观察点单元,可以读取 CPU 周期计数器,精度比 SysTick 中断高得多,而且不占用中断资源。初始化时打开 DWT 计数,延时函数直接数周期:

void bsp_timing_init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } void delay_us(uint32_t us) { uint32_t start = DWT->CYCCNT; uint32_t ticks = us * 48; // 48MHz while ((DWT->CYCCNT - start) < ticks); }

用 DWT 的好处是延时不会被中断打断,单总线这类对微秒级时序敏感的操作用其他延时方式经常越调越乱。如果有人在 RTOS 环境里用,记得先把 DWT 初始化放在启动早期,否则周期计数可能没起来。

4.2 单总线复位、读位、写位

单总线底层时序就三个动作:复位、写位、读位。先看复位,也就是主机把总线拉低至少 480μs,然后释放,传感器检测到这个下降沿后会回一个存在脉冲,主机在释放后 60μs 到 240μs 之间读取到低电平,说明总线上有传感器。

uint8_t ow_reset(void) { uint8_t presence; OW_CLR(); delay_us(500); OW_SET(); // 释放总线 delay_us(40); // 等传感器存在脉冲 presence = (OW_READ() == 0) ? 1 : 0; delay_us(400); return presence; }

如果 presence 是 1,说明传感器在线;如果是 0,总线上没有传感器或者传感器供电掉了。这个返回值很重要,应用层要用它来判断是否上报故障。

写位和读位的时序都在微秒级别。写“1”时主机拉低总线 6μs,然后释放,让上拉电阻把总线拉高;写“0”时主机拉低总线 60μs,再释放。读位时主机先拉低总线 2μs,释放后在 8μs 左右采样总线电平,传感器会在这个窗口内把数据放到总线上。我整理出下面的代码:

void ow_write_bit(uint8_t bit) { delay_us(2); if (bit) { OW_CLR(); delay_us(6); OW_SET(); delay_us(58); } else { OW_CLR(); delay_us(60); OW_SET(); delay_us(2); } } uint8_t ow_read_bit(void) { uint8_t bit; OW_CLR(); delay_us(2); OW_SET(); delay_us(8); bit = OW_READ() ? 1 : 0; delay_us(50); return bit; }

写入一个字节就是把上面函数按 LSB First 的顺序循环八次。读取一个字节同理。写整个 ROM 地址的时候,要记得低位在前,地址字节的顺序和传感器内部存储顺序一致,否则 Match ROM 永远对不上。

4.3 枚举设备并绑定本地/远程地址

单总线的独门技能就是多条总线只需要一根数据线,每个传感器出厂烧录一个 64 位 ROM 编码。上电后总线上的传感器数量可能是一个或者多个,甚至可能是零。这时固件要先做一次枚举,把所有在线传感器的 ROM 地址扫描出来。

枚举算法的标准做法是逐位搜索:先发送复位脉冲,再发送 0x33 搜索 ROM 命令,然后按位判断总线上的分叉情况。这个算法网上有现成实现,这里不展开全部代码,我只说思路:先读一位,再读一位的补码,如果两位都是 1,说明总线上没有设备;如果一位是 0 一位是 1,说明这一位的值是确定的;如果两位都是 0,说明存在分叉,需要自己决定走 0 分支还是 1 分支,并记录路径。

扫描完成之后,我把 ROM 地址列表打印到调试串口。实际项目里,本地传感器固定在板上,远程传感器接在端子上,上电扫描后总会有两个地址,我先把这两个地址保存成默认配置,然后在应用层定义两个常量:

#define LOCAL_TEMP_ADDR_0 0x28 #define LOCAL_TEMP_ADDR_1 0xA4 ... #define REMOTE_TEMP_ADDR_0 0x28 #define REMOTE_TEMP_ADDR_1 ...

你不一定非要在代码里写死地址,也可以放在 EEPROM 或者 Flash 配置区。我的习惯是固件里保留一个“自动绑定”模式:首次上电且配置区为空时,自动把扫描到的两个传感器按顺序绑定为本地和远程,并在日志里打印出哪个是本地、哪个是远程。开发阶段这么干很省事,等现场传感器更换时也不需要改程序,重新执行一次绑定就行。

4.4 启动温度转换并读取结果

单总线读温度分两步:先发转换命令,再读暂存器。转换命令 0x44 会让传感器内部开始一次 ADC 采样,12 位分辨率下最长要 750ms。我通常先用 Skip ROM 命令(0xCC)把所有传感器同时触发转换,这样多个传感器同时采样,时间上并行,等转换完成后再逐个读取。

uint8_t sensor_start_all(void) { if (!ow_reset()) return 0; ow_write_byte(0xCC); // Skip ROM ow_write_byte(0x44); // Start temperature conversion return 1; }

读取某个指定传感器的温度时,先用 Match ROM 命令(0x55)指定 ROM 地址,再发送 Read Scratchpad 命令(0xBE),然后连续读 9 个字节。暂存器前两个字节就是 16 位温度原始值,低字节在前。后面的字节包括上限、下限、配置和 CRC 校验值,CRC 用来检查这一帧数据是否被干扰损坏。

int16_t sensor_get_temp_raw(uint64_t rom) { uint8_t buf[9]; uint8_t i; if (!ow_reset()) return TEMP_ERROR; ow_write_byte(0x55); // Match ROM for (i = 0; i < 8; i++) { ow_write_byte((uint8_t)(rom >> (8 * i))); } ow_write_byte(0xBE); // Read Scratchpad for (i = 0; i < 9; i++) { buf[i] = ow_read_byte(); } if (crc8(buf, 8) != buf[8]) return TEMP_CRC_ERROR; return (int16_t)((buf[1] << 8) | buf[0]); }

CRC 校验不能省。现场传感器电缆长,总线容易受到干扰,读回来的暂存器数据可能中间有一位翻转了。如果不校验,温度可能从 25℃ 变成 60℃,这在暖通控制里是事故级别的误差。CRC8 的多项式是 0x8C,实现方式可以查表也可以按位算,我直接把按位版本贴出来:

uint8_t crc8(const uint8_t *data, uint8_t len) { uint8_t crc = 0; while (len--) { uint8_t inbyte = *data++; for (uint8_t i = 0; i < 8; i++) { uint8_t mix = (crc ^ inbyte) & 0x01; crc >>= 1; if (mix) crc ^= 0x8C; inbyte >>= 1; } } return crc; }

温度原始值换算很简单,12 位分辨率下每个 LSB 代表 0.0625℃。比如原始值 0x0191 换算下来是 25.00℃,0xFF6E 是 -9.125℃。公式就是temp = raw * 0.0625f。我建议应用层保留 float 或者用一个 int16_t 表示 0.01℃ 精度,避免浮点开销太大的话就用定点:temp_centi = raw * 6 / 100? 不对,raw * 100 / 16就能得到摄氏度百分度。实际上raw * 6.25,也就是raw * 25 / 4,用整数就能精确到 0.01℃。

4.5 把温度值送到通信接口

裸机采集到温度只是第一步,暖通系统里温度要参与控制或者上报给上位机。我这边用 CAN 把两个温度值周期发出去,每 500ms 发一帧。具体帧格式可以自己定义,也可以走行业协议。我为了调试方便,另外用调试串口打印一行日志:

[LOCAL] 25.4C [REMOTE] 22.8C

如果希望温度直接参与 PID,就在主循环里读一次local_temp和remote_temp,然后根据温差计算风阀或者水阀开度。这里有一个经验:不要在每次读取温度后都立刻执行控制输出,否则 0.5℃ 的量化抖动会让阀门来回抖,最好加上滞回或者滤波。我简单地把两次读数做了均值滤波,控制效果立刻稳定很多。

5. 现场问题与排查实录

5.1 从 85℃ 说起

做单总线温度采集的人多多少少都见过那个诡异的 85℃。我第一次上电时,代码先读了一遍温度,打印出来全是 85.0℃,当时还以为是传感器坏了。后来查资料才明白,很多这类传感器上电后内部暂存器默认值就是 +85℃,如果在温度转换还没完成时就去读暂存器,读到的就是这个默认值。

解决办法很简单:确保发了 0x44 转换命令后,等待时间超过转换时间,再读取结果。12 位分辨率下等 750ms 是安全的;如果你用 9 位分辨率,只需要 94ms 左右。如果不想傻等,可以周期查询:发转换命令后,每 50ms 读一次,直到暂存器第 7 字节的忙标志位清零。这样既能省时间又能避开默认值陷阱。

还有一种情况会让读数一直是 85℃:传感器处于错误状态,没有响应复位脉冲。此时ow_reset()返回 0,整个温度采集链路直接判错误值,不应该去读暂存器。如果固件忽略了复位结果直接发命令,总线静默时读到的往往是 0xFF,对应温度换算出来也是异常值。所以我建议在应用层加判断:ow_reset()失败直接走传感器掉线告警,不要进入后续读取流程。

5.2 远程读数跳变的那点事

远程传感器读数跳变是最让现场工程师头疼的。我有一次把远程传感器线缆沿着电源线布线,结果温度从 25℃ 到 45℃ 之间来回跳。后来检查发现线缆虽然是屏蔽线,但屏蔽层在现场设备侧也接了地,两端接地形成了地环路,变频器工作时地环路电流直接在屏蔽层上产生干扰电压,传感器供电都受影响。

处理方法是把传感器一侧的屏蔽层悬空,只在控制器侧接地,地环路立刻被切断。另外,如果现场设备本身的接地阻抗高,控制器和传感器之间的地电位差会直接加到信号地上,我不建议传感器远程端和控制器共用地线太长的话,尽量用差分或者隔离方案。距离三五米以内,三线制加单端屏蔽地通常够用。

总线上的干扰还可以通过并一个小电容解决。我在远程连接器的 DQ 线对地之间并了一个 1nF 的陶瓷电容,对高频噪声有抑制作用。但这颗电容不能太大,否则单总线读写时序的上升沿会被拉软,导致通信失败。如果你发现并了 10nF 后温度反而读不出来,那就是电容太大了,换回 1nF 或去掉。

5.3 长总线丢设备

总线长度超过十米时,传感器时有时无是常见现象。单总线协议本身支持几十米传输,但实际受上拉电阻、线缆电容、接线方式影响很大。我遇到的情况是:上拉电阻用 4.7kΩ,总线长度四五米没问题,延长到八九米时,远程传感器经常枚举不到,本地传感器倒是正常。

排查过程很简单:用示波器看 DQ 线上的上升沿,发现上升沿明显变缓,波形拉出一个长尾巴,到了读时序采样点电平还没到高电平阈值。解决方式是降低上拉电阻到 2.2kΩ,让上拉能力更强,上升沿变陡,问题解决。如果你用的是 5V 供电的单总线系统而 MCU 是 3.3V,还可以考虑用有两路电源的有源上拉方案,但对大多数项目,2.2kΩ 已经够用。

长线还会带来一个问题:传感器供电线上的压降。如果传感器远程端 VCC 线太细,十几米后电压可能掉到 3V 以下,传感器工作不稳定。现场布线建议 VCC 和 GND 用 0.5 平方毫米以上的线,DQ 信号线稍细一点没关系。如果可能,尽量用星型接线,不要手拉手串成一条长链,否则末端设备的信号质量会很差。

5.4 更换传感器后无法匹配

本地传感器和远程传感器都用自己的 ROM 地址绑定,如果现场坏了换一颗新的,固件里保存的旧地址就匹配不上了。我遇到过现场工程师把远程传感器换掉之后,设备一直报远程温度故障,查了半天才发现是地址没重新绑定。

解决方法是不要把 ROM 地址当作永久不变的参数,而是提供一个“重新识别”流程:长按按键或者通过通信接口发送一条命令,让设备重新扫一遍总线上的 ROM 列表,然后更新配置。在固件里我把这种逻辑设计成掉线自动重扫:如果远程传感器连续 5 次读取失败,自动进入枚举模式,如果总线上恰好只有一个地址发生变化,就用新地址替代旧地址。这样做虽然不能完全替代手动确认,但能省掉好多上门维护的功夫。

顺带说一句,传感器更换后也要检查安装位置和线缆,很多情况下不是传感器本身坏了,而是接线端子松动或者现场潮湿导致接触不良。检修时先量 DQ 信号线和地之间的电阻,正常应该能看到几兆欧以上的静态电阻,接上传感器后复位脉冲会在总线上有活动信号,用万用表也能粗略判断线路通断。

5.5 常见故障速查表

现象可能原因处理办法
读回 85℃转换未完成,读到默认值等待超过转换时间,或查询忙标志
读回异常大/负值CRC 校验失败加强屏蔽接地,过滤错误帧
找不到远程传感器上拉电阻偏大换 2.2kΩ,减小总线电容
远程温度跳变屏蔽层两端接地/靠近干扰源屏蔽层单端接地,TVS 保护
总线完全无应答传感器没供电或接线断检查 VCC/地线/端子氧化
更换传感器后找不到ROM 地址变化重新枚举绑定地址

这个表是我们项目内部排查手册的浓缩版,现场出了问题先对着表查大概率能找到方向。

6. 还可以继续扩展的方向

6.1 一根总线上挂更多传感器

单总线协议一个很自然的好处就是可以扩展多个传感器。现在我只接了两个,本地和远程各一个,但如果要测回风温度、送风温度、盘管温度、室外温度,只需要再往总线上并几颗传感器,靠 ROM 地址区分就行。实际的限制主要是传感器数量和转换时间,总线上所有传感器可以并行转换,然后再逐个读取,所以传感器数量增加基本不影响更新周期。

6.2 接入 Modbus 或 CAN 网关

现在的方案里 CAN 直发简单帧,但如果是楼宇自控系统,绝大多数上位机还是走 Modbus 协议。STM32F042C6 的 USART 资源够用,我其实在这个项目里预留了 Modbus 从站功能:把所有温度值映射成 Modbus 保持寄存器,通过 RS485 收发器接到上位机。Modbus 协议简单,但建议把超时和重试机制做好,否则现场一个从站异常会把整个总线拖住。

6.3 低功耗采集与轮询策略

前面提到过,单总线传感器转换时电流较大,转换完成后进入待机状态,此时几乎不耗电。如果做电池供电的设备,可以拉长采集周期,比如 10 秒唤醒一次,发转换命令后就进入 STOP 模式,等 100ms 左右再从 STOP 唤醒读结果。这样平均功耗可以压到很低。唯一要注意的是,单总线时序期间不能进 STOP,否则 GPIO 释放和采样会乱套,时序必须放在唤醒之后。

6.4 温度校准的小经验

数字传感器出厂校准过了,但现场安装位置仍然会带来系统误差。比如本地传感器紧挨着电源模块,温度比真实环境高几度;远程传感器靠着金属风道壁,温度又偏低。我在应用层给两个传感器各加了一个可配置偏移量,存储在 Flash 配置区,现场用标准温度计校准后写入。这个偏移量不用太复杂,0.1℃ 步进就够,关键是每台设备在校准时能独立修改,而不是在固件里写死。

最后再分享一个小技巧:批量生产的设备要想避免每台都校准的麻烦,最好在硬件设计时把本地传感器的位置固定下来,同时把远程传感器的探头形式标准化。这样就算传感器之间有几度差异,也能通过统一偏移量修正,不用一台台逐个调。这套单总线方案我后来在其他项目里又复用了几次,每次只要改一下引脚和配置,逻辑都不用动,省下的调试时间非常可观。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询