STM32驱动DS18B20
时间: 2025-07-09 19:47:09 浏览: 7
### STM32 使用 HAL 库驱动 DS18B20 温度传感器
#### 一、硬件连接
DS18B20 是一种基于 One-Wire 协议的数字温度传感器,其数据线可以与 STM32 的任意 GPIO 引脚相连。为了简化设计并提高通信稳定性,通常会在 DS18B20 数据线上接入一个上拉电阻(推荐阻值为 4.7kΩ)。在某些开发板中,可以选择 PB9 或其他引脚作为 DS18B20 的数据引脚[^2]。
#### 二、软件实现
以下是使用 STM32 HAL 库通过 One-Wire 协议读取 DS18B20 温度数据的主要步骤:
1. **初始化 GPIO 和 TIM 定时器**
- 配置用于 DS18B20 数据传输的 GPIO 引脚。
- 初始化定时器以提供精确的微秒级延时功能。
```c
// GPIO 初始化
void DS18B20_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE(); // 启用 GPIOB 时钟
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉输入
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
// 微秒级延时函数
void DelayUs(uint16_t us) {
__HAL_TIM_SET_COUNTER(&TIM_Handle, 0); // 设置计数器初始值为 0
__HAL_TIM_ENABLE(&TIM_Handle); // 开启定时器
while (__HAL_TIM_GET_COUNTER(&TIM_Handle) < us); // 检查当前计数值是否达到目标值
__HAL_TIM_DISABLE(&TIM_Handler); // 关闭定时器
}
```
2. **One-Wire 总线操作**
实现 One-Wire 协议的核心在于发送复位脉冲以及检测从设备的存在信号。以下是一个简单的 One-Wire 复位和存在检测函数:
```c
#define ONE_WIRE_PORT GPIOB
#define ONE_WIRE_PIN GPIO_PIN_9
// 发送复位脉冲并等待响应
uint8_t DS18B20_Reset(void) {
uint8_t presence = 0;
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_RESET); // 下拉总线
DelayUs(480); // 延迟至少 480us
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_SET); // 释放总线
DelayUs(70); // 等待主机释放总线后的延迟时间
if (!HAL_GPIO_ReadPin(ONE_WIRE_PORT, ONE_WIRE_PIN)) // 如果有设备应答,则返回低电平
presence = 1;
DelayUs(410); // 等待剩余的时间完成一次完整的复位周期
return presence;
}
// 写入单个字节到 DS18B20
void DS18B20_WriteByte(uint8_t data) {
for (int i = 0; i < 8; i++) {
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_RESET); // 下拉总线
DelayUs(2);
if ((data << i) & 0x80)
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_SET); // 写高电平时序
else
DelayUs(60); // 写低电平时序
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_SET); // 释放总线
DelayUs(10);
}
}
// 从 DS18B20 读取单个字节
uint8_t DS18B20_ReadByte(void) {
uint8_t byte_data = 0;
for (int i = 0; i < 8; i++) {
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_RESET); // 下拉总线
DelayUs(2);
HAL_GPIO_WritePin(ONE_WIRE_PORT, ONE_WIRE_PIN, GPIO_PIN_SET); // 释放总线
DelayUs(10);
if (HAL_GPIO_ReadPin(ONE_WIRE_PORT, ONE_WIRE_PIN))
byte_data |= (1 << i); // 将接收到的数据拼接到字节变量中
DelayUs(60);
}
return byte_data;
}
```
3. **启动转换并获取温度**
调用上述函数来执行 DS18B20 的温度测量过程,并最终解析得到实际温度值。
```c
float DS18B20_GetTemperature(void) {
float temperature = 0.0f;
int16_t raw_temp = 0;
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过 ROM 地址匹配命令
DS18B20_WriteByte(0x44); // 启动温度转换命令
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过 ROM 地址匹配命令
DS18B20_WriteByte(0xBE); // 读取寄存器命令
raw_temp = DS18B20_ReadByte(); // 获取最低有效字节
raw_temp |= DS18B20_ReadByte() << 8; // 获取最高有效字节
if (raw_temp & 0x8000) // 判断是否为负数
raw_temp = -(~raw_temp + 1);
temperature = (float)(raw_temp >> 4); // 取整部分
temperature += (float)((raw_temp & 0xF) * 0.0625); // 加上小数部分
return temperature;
}
```
---
###
阅读全文
相关推荐


















