STM32F103C8T6用HAL库搞定DS18B20温度读取,附完整代码和逻辑分析仪调试技巧
2026/5/30 23:48:41 网站建设 项目流程

STM32F103C8T6 HAL库驱动DS18B20实战:从时序调试到温度读取全解析

对于嵌入式开发者而言,单总线协议设备总是带着一丝神秘色彩——看似简单的单线通信,却隐藏着严格的时序要求。DS18B20作为经典的数字温度传感器,其单总线协议在STM32上的稳定实现往往成为初学者的"拦路虎"。本文将带您深入HAL库下的DS18B20驱动开发,重点解决那些教程中鲜少提及的时序调试痛点,通过逻辑分析仪直观测距,打造工业级稳定的温度采集方案。

1. 硬件准备与CubeMX工程配置

在开始编码之前,正确的硬件连接和基础工程配置是成功的第一步。STM32F103C8T6与DS18B20的典型连接方式看似简单,但细节决定成败:

  • 硬件连接方案
    • DS18B20的DQ引脚通过4.7kΩ上拉电阻连接至STM32任意GPIO(本文以PC13为例)
    • VDD接3.3V,GND共地
    • 注意:寄生供电模式下需确保电源电流足够,否则温度转换时可能出现复位

CubeMX关键配置(以STM32CubeIDE为例):

  1. 创建STM32F103C8T6工程
  2. 启用PC13引脚为GPIO_Output(初始配置,后续需动态切换)
  3. 配置系统时钟为72MHz(精确延时的基础)
  4. 生成工程时勾选"Generate peripheral initialization as a pair of .c/.h files"

提示:虽然CubeMX可以生成GPIO初始化代码,但DS18B20要求引脚在输入/输出模式间动态切换,因此我们需要手动重配置GPIO模式。

2. 单总线协议深度解析与HAL实现

单总线协议的精髓在于精确的时序控制。我们先解剖协议标准,再转化为HAL库实现。

2.1 初始化时序:设备检测的关键

DS18B20的初始化过程包含三个关键阶段:

阶段主机动作从机响应时间要求
复位脉冲拉低480-960μs典型值500μs
释放总线释放DQ线等待15-60μs后拉低上拉电阻作用
存在脉冲保持输入模式拉低60-240μs检测窗口60μs

对应的HAL实现代码:

void DS18B20_Reset(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 配置为推挽输出 GPIO_InitStruct.Pin = DS18B20_DQ_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStruct); // 复位脉冲 HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_RESET); delay_us(480); // 实测480-800μs均可 HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_SET); // 切换为输入模式检测应答 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStruct); delay_us(60); // 等待应答检测窗口 uint8_t presence = HAL_GPIO_ReadPin(DS18B20_DQ_PORT, DS18B20_DQ_PIN); delay_us(420); // 完成整个初始化周期 return presence; }

2.2 读写时序:位操作的精确控制

单总线协议的读写操作都以**时隙(time slot)**为单位,每个时隙处理1位数据。关键参数对比如下:

写时隙参数对比表

参数写'0'时隙写'1'时隙
主机拉低时间60-120μs1-15μs
采样窗口下降沿后15-60μs同左
恢复时间≥1μs≥1μs

读时隙参数对比表

操作时间要求
主机拉低时间≥1μs
释放到采样时间15μs内
整个时隙持续时间≥60μs

对应的位读写函数实现:

void DS18B20_WriteBit(uint8_t bit) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = DS18B20_DQ_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_RESET); delay_us(bit ? 5 : 60); // 写1保持5μs,写0保持60μs HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_SET); delay_us(bit ? 55 : 1); // 完成整个时隙周期 } uint8_t DS18B20_ReadBit(void) { uint8_t bit = 0; GPIO_InitTypeDef GPIO_InitStruct = {0}; // 主机拉低 GPIO_InitStruct.Pin = DS18B20_DQ_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_RESET); delay_us(2); // 远大于1μs最小值 // 释放总线并切换输入 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStruct); delay_us(12); // 释放后等待12μs采样 bit = HAL_GPIO_ReadPin(DS18B20_DQ_PORT, DS18B20_DQ_PIN); delay_us(50); // 完成整个读时隙 return bit; }

3. 逻辑分析仪调试实战技巧

当温度读取异常时,逻辑分析仪是定位问题的终极武器。以Saleae Logic为例,我们需要关注三个关键波形:

3.1 初始化序列诊断

正确的初始化波形应包含:

  1. 明显的480μs以上低电平复位脉冲
  2. 释放后上拉电阻导致的上升沿
  3. DS18B20的应答脉冲(60-240μs低电平)

常见问题及波形特征

  • 无应答脉冲

    • 可能原因:接线错误、上拉电阻过大、电源问题
    • 波形表现:释放总线后始终为高电平
  • 应答脉冲位置异常

    • 可能原因:延时精度不足
    • 波形表现:应答出现在释放总线60μs之后

3.2 读写时序测量技巧

在Saleae Logic中设置触发条件为下降沿,捕获单个读写时隙:

  1. 添加测量标尺,检查关键时间参数:

    • 写'0'时低电平持续时间是否在60-120μs
    • 读时隙中采样点是否在释放总线后15μs内
  2. 使用协议分析器:

    • 在Logic软件中安装"1-Wire"协议解码器
    • 设置正确的DQ引脚和采样率(建议≥4MHz)

典型调试案例波形对比

[主机拉低] |________| | | [理想写0] |←60μs→| |________| [实测有误] |←45μs→| // 不足60μs导致识别错误

3.3 温度转换全过程捕获

完整温度读取流程应包含:

  1. 初始化序列
  2. 发送跳过ROM命令(0xCC)
  3. 发送温度转换命令(0x44)
  4. 等待转换时间(典型750ms)
  5. 重新初始化
  6. 发送读取暂存器命令(0xBE)
  7. 读取两个字节温度数据

注意:在转换期间(步骤4)总线活动可能导致转换失败,建议此时将GPIO配置为输入模式减少干扰。

4. 工业级稳定驱动实现

结合调试经验,我们给出经过验证的完整驱动实现,包含以下增强特性:

  • 动态GPIO模式切换
  • 精确的us级延时
  • 错误重试机制
  • 负温度处理
  • CRC校验(可选)

核心温度读取函数

float DS18B20_GetTemp(void) { uint8_t tempL, tempH; int16_t temp; if(DS18B20_Reset()) return DEVICE_DISCONNECTED; DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0x44); // Convert T delay_ms(750); // 等待转换完成 if(DS18B20_Reset()) return DEVICE_DISCONNECTED; DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0xBE); // Read Scratchpad tempL = DS18B20_ReadByte(); tempH = DS18B20_ReadByte(); temp = (tempH << 8) | tempL; return temp * 0.0625f; // 12位精度,LSB=0.0625°C }

精确延时实现方案

void delay_us(uint32_t us) { uint32_t start = DWT->CYCCNT; uint32_t cycles = us * (SystemCoreClock / 1000000); while((DWT->CYCCNT - start) < cycles); } void delay_ms(uint32_t ms) { HAL_Delay(ms); // 直接使用HAL提供的ms级延时 }

注:使用DWT(Cycle Counter)前需先启用:

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

在项目实践中发现,当多个DS18B20挂载在同一总线上时,ROM匹配和CRC校验变得尤为重要。虽然单个传感器可以跳过这些步骤,但规范的实现应该包含完整的搜索算法和校验机制——这或许是您进阶路上的下一个挑战目标。

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

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

立即咨询