1. 1-Wire总线技术概述
1-Wire总线是Dallas Semiconductor(现为Maxim Integrated子公司)开发的一种单线通信协议,以其极简的硬件设计和低成本特性在嵌入式系统领域独树一帜。这项技术的核心创新在于仅用单根数据线(加上地线)就能实现双向通信和设备供电,彻底颠覆了传统总线需要多根信号线的设计理念。
提示:1-Wire总线在实际应用中通常需要连接一个4.7kΩ的上拉电阻,这是保证信号完整性的关键元件。
1.1 技术特点与优势
1-Wire总线最显著的特点是它的"三合一"能力:
- 单线通信:所有数据传输通过一根双向开漏信号线完成
- 寄生供电:多数1-Wire器件可以从数据线"窃取"电源(典型工作电压2.8V-5.25V)
- 设备级联:支持在单总线上挂接多个设备(理论最多100个)
这种设计带来的直接优势包括:
- 布线成本降低70%以上(相比I2C/SPI)
- 安装维护简单,适合长距离部署(最远可达300米)
- 每个设备内置全球唯一64位ROM ID(含8位家族码+48位序列号+8位CRC)
- 工作温度范围宽(-40°C到+85°C工业级)
1.2 典型应用场景
根据我在工业自动化项目中的实践经验,1-Wire技术特别适合以下场景:
- 分布式传感器网络:温度传感器DS18B20组成的多点监测系统
- 资产追踪与管理:iButton(纽扣式封装)用于设备标识
- 安防系统:基于DS1990A的电子钥匙门禁
- 工业控制:DS2408提供的远程数字I/O扩展
- 数据记录:DS2431 EEPROM用于设备参数存储
在2018年参与的一个农业物联网项目中,我们使用1-Wire总线连接了32个DS18B20温度传感器,分布在200米长的温室大棚中。相比传统方案,布线成本节省了约85%,且系统稳定运行至今。
2. 硬件实现细节
2.1 电气特性与拓扑结构
1-Wire总线采用主从式架构,所有通信由主机发起。其电气特性有几点关键参数:
| 参数 | 典型值 | 说明 |
|---|---|---|
| 工作电压 | 2.8-5.25V | 寄生供电时需≥3V |
| 通信速率 | 15.3kbps | 标准模式 |
| 驱动方式 | 开漏输出 | 需外接上拉电阻 |
| 总线电容 | ≤800pF | 影响最大传输距离 |
| 静态电流 | 1μA | 休眠状态功耗 |
拓扑结构方面,常见的有三种配置方式:
- 线性拓扑:最简单直接的串联方式
- 星型拓扑:通过DS2409耦合器实现分支
- 混合拓扑:结合前两种方式的优点
2.2 关键电路设计
在实际项目中,可靠的1-Wire电路设计需要注意以下几个要点:
上拉电阻计算:
Rp(max) = (Vdd - Vil)/(Iol + ∑Ili)其中:
- Vdd:电源电压
- Vil:输入低电平阈值(通常0.8V)
- Iol:主机驱动电流
- Ili:各从机输入漏电流
ESD保护: 建议在总线入口处添加DS9503等专用保护器件,特别是在工业环境中。我们曾在一个工厂项目中因忽略ESD保护导致30%的设备在一年内失效。
长线驱动: 当传输距离超过30米时,应考虑:
- 使用CAT5e等双绞线
- 降低上拉电阻值(可至1.5kΩ)
- 增加线路驱动器(如DS2480B)
2.3 硬件接口方案
根据不同的主控资源,1-Wire接口有四种典型实现方式:
2.3.1 GPIO直接驱动
最简单的实现,仅需一个GPIO引脚:
// 硬件连接示例 // MCU_GPIO ---[4.7kΩ]---+--- 1-Wire总线 // | // Vdd(3.3V/5V)这种方式的优点是成本最低,但对时序要求严格。在STM32上的实现要点:
- 配置引脚为开漏输出模式
- 精确控制μs级延时
- 操作期间关闭中断
2.3.2 定时器+PWM驱动
利用定时器输出比较功能生成精确波形,适合资源丰富的MCU:
// STM32 HAL示例 TIM_OC_InitTypeDef sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_TOGGLE; sConfigOC.Pulse = 100; // 100us脉冲 HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);2.3.3 UART转1-Wire
巧妙利用UART的BREAK信号实现复位脉冲:
// 配置UART发送0xF0(11110000)产生特定波形 HAL_UART_Transmit(&huart1, (uint8_t*)"\xF0", 1, HAL_MAX_DELAY);2.3.4 专用接口芯片
DS2482等专用转换芯片提供标准I2C到1-Wire的转换,大大简化设计:
- 内置电平转换
- 自动时序控制
- 错误检测功能
3. 协议深度解析
3.1 通信时序详解
1-Wire协议的核心在于精确控制三个基本时序:
复位脉冲(≥480μs低电平)
- 主机拉低总线480μs以上
- 释放总线后,从机应在15-60μs内回送存在脉冲
- 存在脉冲持续时间60-240μs
写时隙
- 写"1":拉低1-15μs后释放
- 写"0":拉低60-120μs后释放
- 两种时隙后都需要至少1μs的恢复时间
读时隙
- 主机拉低总线1-15μs
- 释放后必须在15μs内采样总线状态
- 从机保持"0"的时间窗口为15-60μs
注意:所有时序测量都以下降沿为基准点,上升时间tr对系统稳定性影响很大。
3.2 命令集架构
1-Wire协议采用分层命令结构:
ROM命令层(8位)
| 命令 | 代码 | 功能 |
|---|---|---|
| Read ROM | 0x33 | 读取单个设备ROM ID |
| Match ROM | 0x55 | 指定设备地址进行通信 |
| Skip ROM | 0xCC | 广播所有设备 |
| Search ROM | 0xF0 | 枚举总线设备 |
| Alarm Search | 0xEC | 搜索报警设备 |
功能命令层(设备相关)
以DS18B20温度传感器为例:
0x44 // 开始温度转换 0xBE // 读取暂存器 0x4E // 写入暂存器3.3 设备枚举算法
Search ROM算法是1-Wire最精妙的部分,其核心是二进制搜索树遍历:
- 主机发送Search ROM命令(0xF0)
- 对ROM ID的每一位: a. 主机发起两个读时隙 b. 从机返回该位的值和补码 c. 主机根据响应决定搜索方向
- 记录分歧点(last_discrepancy)
- 重复直到所有设备被发现
实际实现时需要处理多种边界情况,以下是经过验证的枚举代码框架:
uint8_t ROM_NO[8]; int LastDiscrepancy = 0; int LastFamilyDiscrepancy = 0; int LastDeviceFlag = 0; int OWSearch() { int id_bit_number = 1; int last_zero = 0; int rom_byte_number = 0; uint8_t id_bit, cmp_id_bit; if (!LastDeviceFlag) { // 初始化搜索 if (OWReset()) return 0; OWWriteByte(0xF0); // Search ROM命令 do { id_bit = OWReadBit(); cmp_id_bit = OWReadBit(); if (id_bit && cmp_id_bit) break; // 无设备响应 if (id_bit != cmp_id_bit) { search_direction = id_bit; // 所有设备该位相同 } else { // 处理分歧位 if (id_bit_number < LastDiscrepancy) { search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); } else { search_direction = (id_bit_number == LastDiscrepancy); } if (!search_direction) last_zero = id_bit_number; } // 设置搜索方向 if (search_direction) ROM_NO[rom_byte_number] |= rom_byte_mask; else ROM_NO[rom_byte_number] &= ~rom_byte_mask; OWWriteBit(search_direction); id_bit_number++; rom_byte_mask <<= 1; if (!rom_byte_mask) { rom_byte_number++; rom_byte_mask = 1; } } while(rom_byte_number < 8); if (!(id_bit_number < 65)) { LastDiscrepancy = last_zero; if (LastDiscrepancy <= 0) LastDeviceFlag = 1; return 1; // 搜索成功 } } return 0; // 搜索完成 }4. 软件实现要点
4.1 底层驱动开发
基于GPIO的实现需要特别注意时序精度。以下是经过优化的STM32 HAL实现:
#define OW_PIN GPIO_PIN_0 #define OW_PORT GPIOA uint8_t OWReset(void) { uint8_t presence = 0; // 配置为开漏输出 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = OW_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(OW_PORT, &GPIO_InitStruct); // 拉低480μs HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_RESET); delay_us(480); // 释放总线,切换为输入 HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_SET); GPIO_InitStruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(OW_PORT, &GPIO_InitStruct); // 等待存在脉冲 delay_us(70); if (!HAL_GPIO_ReadPin(OW_PORT, OW_PIN)) { presence = 1; } // 等待时隙结束 delay_us(410); return presence; } void OWWriteBit(uint8_t bit) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = OW_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; HAL_GPIO_Init(OW_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_RESET); if (bit) { delay_us(6); // 写"1"时隙 HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_SET); delay_us(64); } else { delay_us(60); // 写"0"时隙 HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_SET); delay_us(10); } } uint8_t OWReadBit(void) { uint8_t bit = 0; GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = OW_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; HAL_GPIO_Init(OW_PORT, &GPIO_InitStruct); // 启动读时隙 HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_RESET); delay_us(6); HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_SET); // 切换为输入 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(OW_PORT, &GPIO_InitStruct); // 在15μs时采样 delay_us(9); bit = HAL_GPIO_ReadPin(OW_PORT, OW_PIN); // 等待时隙结束 delay_us(55); return bit; }4.2 CRC校验实现
1-Wire使用两种CRC:
- 8位CRC(x⁸ + x⁵ + x⁴ + 1):用于ROM ID校验
- 16位CRC(x¹⁶ + x¹⁵ + x² + 1):用于数据块校验
以下是经过优化的查表法实现:
// 8位CRC预计算表 static const uint8_t dscrc_table[] = { 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, // ... 完整表共256个元素 }; uint8_t OWCRC8(uint8_t *addr, uint8_t len) { uint8_t crc = 0; while (len--) { crc = dscrc_table[crc ^ *addr++]; } return crc; } // 16位CRC计算 uint16_t OWCRC16(uint8_t *data, uint16_t length) { uint16_t crc = 0; while (length--) { crc ^= *data++; for (uint8_t i = 0; i < 8; i++) { if (crc & 0x0001) crc = (crc >> 1) ^ 0xA001; else crc >>= 1; } } return crc; }4.3 典型设备驱动
以DS18B20温度传感器为例,完整驱动应包括:
- 初始化序列
void DS18B20_Init(void) { OWReset(); OWWriteByte(0xCC); // Skip ROM OWWriteByte(0x4E); // Write Scratchpad OWWriteByte(0x7F); // TH寄存器 OWWriteByte(0x00); // TL寄存器 OWWriteByte(0x7F); // 配置寄存器(12位分辨率) }- 启动温度转换
void DS18B20_StartConv(void) { OWReset(); OWWriteByte(0xCC); // Skip ROM OWWriteByte(0x44); // Convert T命令 // 寄生供电时需要强上拉 HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_SET); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = OW_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出提供强上拉 HAL_GPIO_Init(OW_PORT, &GPIO_InitStruct); delay_ms(750); // 等待12位转换完成 }- 读取温度值
float DS18B20_ReadTemp(void) { uint8_t temp[9]; OWReset(); OWWriteByte(0xCC); // Skip ROM OWWriteByte(0xBE); // Read Scratchpad for (uint8_t i = 0; i < 9; i++) { temp[i] = OWReadByte(); } if (OWCRC8(temp, 8) != temp[8]) { return NAN; // CRC校验失败 } int16_t raw = (temp[1] << 8) | temp[0]; return (float)raw / 16.0f; // 转换为摄氏度 }5. 实战经验与故障排查
5.1 常见问题及解决方案
根据多年项目经验,整理出1-Wire系统典型故障及对策:
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 检测不到设备 | 上拉电阻过大 | 减小Rp至1.5kΩ或增加强上拉 |
| 通信不稳定 | 总线电容过大 | 缩短线长或使用低电容电缆 |
| CRC校验失败 | 时序不精确 | 校准延时,确保满足15μs采样窗口 |
| 多设备冲突 | ROM搜索算法错误 | 检查last_discrepancy处理逻辑 |
| 寄生供电异常 | 电流不足 | 添加局部储能电容(100nF/设备) |
5.2 性能优化技巧
批量读取优化: 对于多传感器系统,先广播启动所有转换,再逐个读取,可节省75%时间。
动态调整分辨率: 根据应用需求灵活设置DS18B20分辨率(9-12位),平衡精度与速度。
中断处理策略: 在关键时序段禁用中断,但总禁用时间不超过100μs以免影响系统实时性。
电缆选择建议:
- 短距离(<10m):普通双绞线
- 中距离(<100m):CAT5e网络线
- 长距离(>100m):屏蔽双绞线+线路驱动器
5.3 可靠性设计要点
总线监控: 添加DS2406等监控设备,实时检测总线状态。
故障隔离: 使用DS2409分支器实现故障区段隔离。
电源冗余: 关键设备提供双供电(寄生+独立电源)。
抗干扰措施:
- 总线走线避开强电线路
- 添加磁珠滤波
- 采用屏蔽线接地
在2020年一个海上石油平台监测系统中,我们通过以下设计实现了99.99%的通信可靠性:
- 所有1-Wire节点采用铠装屏蔽电缆
- 每50米添加一个DS2409作为中继
- 关键传感器采用独立供电模式
- 实施每日CRC自检和月度全系统ROM扫描
6. 高级应用与扩展
6.1 网络化部署方案
对于大规模部署,可采用分层架构:
[中央服务器] | [区域网关]---[1-Wire网桥]---[终端设备] | | [SQL数据库] [本地缓存]关键技术点:
- 使用DS2480B实现RS-232到1-Wire转换
- 区域网关采用树莓派等Linux设备
- 数据同步采用MQTT协议
6.2 安全增强设计
加密认证: 使用DS2465协处理器实现SHA-256加密
防篡改机制:
- 采用DS28E15实现数字签名
- 关键参数写入一次可编程存储器
安全审计: 记录所有设备访问日志,定期校验ROM ID
6.3 混合总线集成
将1-Wire与其他总线技术融合:
[Modbus RTU] | [PLC]---[协议转换器]---[1-Wire]---[传感器网络] | [Ethernet/IP]实现要点:
- 使用DS2480B+STM32构建协议转换器
- 设计统一寻址方案(1-Wire ROM ID映射到Modbus寄存器)
- 开发跨平台驱动库
在智能建筑项目中,这种混合架构成功整合了:
- 200+ DS18B20温度传感器
- 50+ DS2413数字I/O模块
- 30+ DS28E15安全认证节点 通过单一BACnet接口对外提供所有数据。