一、DS18B20 简介
DS18B20 是由 Dallas Semiconductor 公司生产的单总线数字温度传感器。它具有以下特点:
- 单总线接口:仅需一个引脚即可与微控制器进行通信,减少了硬件连接的复杂度。
- 数字输出:直接输出数字温度值,无需额外的模数转换电路。
- 精度高:可编程分辨率为 9 - 12 位,对应的温度精度分别为 0.5°C、0.25°C、0.125°C 和 0.0625°C。
- 宽温度范围:测量范围为 -55°C 到 +125°C。
二、硬件连接
在使用 STM32F407 与 DS18B20 进行连接时,需要将 DS18B20 的数据线(DQ)连接到 STM32F407 的一个 GPIO 引脚。同时,DS18B20 的电源引脚(VDD)接 3.3V 或 5V,接地引脚(GND)接地。为了保证通信的稳定性,通常需要在 DQ 引脚上拉一个 4.7KΩ 的电阻到电源。
三、驱动代码实现
1. 初始化 GPIO 引脚
首先,需要初始化与 DS18B20 连接的 GPIO 引脚。以下是使用 STM32Cube HAL 库进行初始化的代码:
#include "stm32f4xx_hal.h"
#define DS18B20_PORT GPIOA
#define DS18B20_PIN GPIO_PIN_0
void DS18B20_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = DS18B20_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
}
2. 单总线复位脉冲
DS18B20 的通信需要先发送一个复位脉冲,以检测设备是否存在。以下是复位脉冲的代码实现:
uint8_t DS18B20_Reset(void) {
uint8_t presence;
// 拉低总线480 - 960us
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
HAL_Delay(1);
// 释放总线,等待15 - 60us
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
HAL_Delay(1);
// 读取DS18B20的存在脉冲
presence = HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN);
HAL_Delay(4);
return presence;
}
3. 写一位数据
向 DS18B20 写入一位数据的代码如下:
void DS18B20_WriteBit(uint8_t bit) {
if (bit) {
// 写1
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
__asm("nop");
__asm("nop");
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
HAL_Delay(1);
} else {
// 写0
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
HAL_Delay(1);
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
__asm("nop");
__asm("nop");
}
}
4. 读一位数据
从 DS18B20 读取一位数据的代码如下:
uint8_t DS18B20_ReadBit(void) {
uint8_t bit;
// 拉低总线1 - 15us
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
__asm("nop");
__asm("nop");
// 释放总线,等待1 - 15us后读取数据
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
__asm("nop");
__asm("nop");
bit = HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN);
HAL_Delay(1);
return bit;
}
5. 写一个字节数据
向 DS18B20 写入一个字节数据的代码如下:
void DS18B20_WriteByte(uint8_t byte) {
uint8_t i;
for (i = 0; i < 8; i++) {
DS18B20_WriteBit(byte & 0x01);
byte >>= 1;
}
}
6. 读一个字节数据
从 DS18B20 读取一个字节数据的代码如下:
uint8_t DS18B20_ReadByte(void) {
uint8_t i, byte = 0;
for (i = 0; i < 8; i++) {
byte >>= 1;
if (DS18B20_ReadBit()) {
byte |= 0x80;
}
}
return byte;
}
7. 启动温度转换
启动 DS18B20 进行温度转换的代码如下:
void DS18B20_StartConversion(void) {
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM操作
DS18B20_WriteByte(0x44); // 启动温度转换
}
8. 读取温度值
读取 DS18B20 的温度值的代码如下:
float DS18B20_ReadTemperature(void) {
uint8_t temp_l, temp_h;
int16_t temp;
float temperature;
DS18B20_StartConversion();
HAL_Delay(750); // 等待转换完成
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM操作
DS18B20_WriteByte(0xBE); // 读取温度寄存器
temp_l = DS18B20_ReadByte();
temp_h = DS18B20_ReadByte();
temp = (temp_h << 8) | temp_l;
temperature = (float)temp / 16.0;
return temperature;
}
四、测试代码
以下是一个简单的测试代码,用于在主函数中调用 DS18B20 驱动函数并打印温度值:
#include "stm32f4xx_hal.h"
#include <stdio.h>
#define DS18B20_PORT GPIOA
#define DS18B20_PIN GPIO_PIN_0
// 前面定义的驱动函数
int main(void) {
HAL_Init();
DS18B20_GPIO_Init();
while (1) {
float temperature = DS18B20_ReadTemperature();
printf("Temperature: %.2f °C\n", temperature);
HAL_Delay(1000);
}
}
五、代码解释
- GPIO 初始化:将与 DS18B20 连接的 GPIO 引脚初始化为开漏输出模式,以适应单总线通信的要求。
- 复位脉冲:通过拉低总线一段时间,然后释放总线,等待 DS18B20 返回存在脉冲,以检测设备是否正常工作。
- 读写位和字节:通过控制总线的高低电平,实现向 DS18B20 写入一位或一个字节的数据,以及从 DS18B20 读取一位或一个字节的数据。
- 启动温度转换:发送特定的命令字节,启动 DS18B20 进行温度转换。
- 读取温度值:在温度转换完成后,读取温度寄存器的值,并将其转换为实际的温度值。
六、注意事项
- 延时时间:DS18B20 的通信协议对延时时间要求较高,需要确保延时时间的准确性。在上述代码中,使用了
HAL_Delay()
函数进行延时,实际应用中可以根据需要进行调整。 - 上拉电阻:为了保证通信的稳定性,需要在 DQ 引脚上拉一个 4.7KΩ 的电阻到电源。
- 温度转换时间:DS18B20 的温度转换时间与分辨率有关,最高分辨率(12 位)下的转换时间为 750ms。在读取温度值之前,需要等待转换完成。
七、总结
通过以上代码,你可以实现基于 STM32F407 HAL 库的 DS18B20 驱动。该驱动代码可以方便地集成到你的项目中,用于实时监测环境温度。在实际应用中,你可以根据需要对代码进行优化和扩展,例如添加错误处理、多设备支持等功能。
希望以上内容对你有所帮助。如果你在使用过程中遇到任何问题,可以随时进行提问。