STM32基于HAL工程FREERTOS读取DS18B20数据+串口输出
STM32基于HAL工程FREERTOS读取DS18B20数据+串口输出
·
STM32基于HAL工程FREERTOS读取DS18B20数据+串口输出
- ✨申明:本文章仅发表在CSDN网站,任何其他网站,未注明来源,见此内容均为盗链和爬取,请多多尊重和支持原创!
- 🍁对于文中所提供的相关资源链接将作不定期更换。
🔰基于STM32CubeMX配置工程,当然不局限于STM32其他型号的芯片的使用,只要是stm32芯片都可以使用该源文件进行驱动,方便适配移植,减少不必要的重复开发工作。
- 🎯本工程经实物验证,程序没有问题。
- 🔖工程基于FREERTOS下,串口打印读取到数据,

🛠STM32F103基于STM32CubeMX配置工程
- 🔨配置FREERTOS时基。(OS的时基和 SysTick(滴答定时器) 分开)

- 🌿开启定时器1用于读取DS18B20数据时使用。

- 🌿配置DS18B20数据引脚

- 🌿使能一个串口,用于调试信息输出

- 🧲在中间件(Middleware)当中,选择OS系统

- 🌿根据实际运行情况适当调整堆栈空间。

📚工程源码
链接: https://pan.baidu.com/s/1hphH64UK_BsM9nSOL-0FJQ
提取码: wzb1
DS18B20传感器温度读取流程
DS18B20是单总线数字温度传感器,移植其驱动核心是实现单总线时序(复位、存在脉冲、写位、读位),再基于时序封装温度读取逻辑。以下以STM32为例(裸机,基于HAL库),讲解通用移植步骤和核心代码。
一、硬件准备与引脚配置
- 硬件连接:
- DS18B20的VDD接3.3V(或5V,注意电平匹配);
- GND接单片机GND;
- DQ(数据引脚)接单片机任意GPIO(如PA0),并串联4.7K上拉电阻到VDD。
- GPIO配置(STM32 HAL库):
- 模式:推挽输出 + 上拉输入(需动态切换输入/输出);
- 速度:低速即可。
二、核心:单总线时序实现(关键)
DS18B20的所有通信依赖严格的单总线时序,这是移植的核心,不同MCU(如STM32、51、GD32)仅GPIO操作不同,时序逻辑完全一致。
1. 引脚电平操作封装(适配不同MCU)
先封装GPIO的输入/输出切换、电平读写,方便移植到其他MCU时仅修改此处:
#include "stm32f1xx_hal.h"
// 定义DS18B20数据引脚(根据实际硬件修改)
#define DS18B20_DQ_PORT GPIOA
#define DS18B20_DQ_PIN GPIO_PIN_0
// 设置DQ为输出模式
static void DS18B20_Set_Output(void)
{
GPIO_InitTypeDef gpio_init_struct = {0};
gpio_init_struct.Pin = DS18B20_DQ_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
gpio_init_struct.Pull = GPIO_NOPULL;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DS18B20_DQ_PORT, &gpio_init_struct);
}
// 设置DQ为输入模式
static void DS18B20_Set_Input(void)
{
GPIO_InitTypeDef gpio_init_struct = {0};
gpio_init_struct.Pin = DS18B20_DQ_PIN;
gpio_init_struct.Mode = GPIO_MODE_INPUT; // 输入模式(上拉由硬件电阻保证)
gpio_init_struct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DS18B20_DQ_PORT, &gpio_init_struct);
}
// 写DQ引脚电平
static void DS18B20_Write_Level(uint8_t level)
{
if(level)
HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(DS18B20_DQ_PORT, DS18B20_DQ_PIN, GPIO_PIN_RESET);
}
// 读DQ引脚电平
static uint8_t DS18B20_Read_Level(void)
{
return HAL_GPIO_ReadPin(DS18B20_DQ_PORT, DS18B20_DQ_PIN);
}
// 微秒级延时(需根据MCU主频校准,STM32F1默认72MHz)
static void DS18B20_Delay_Us(uint16_t us)
{
uint32_t ticks = (HAL_RCC_GetHCLKFreq() / 1000000) * us;
ticks /= 8; // 简易延时,需实际校准
while(ticks--);
}
2. 单总线核心时序实现
(1)复位与检测脉冲
uint8_t DS18B20_Reset(void)
{
uint8_t retry = 0;
DS18B20_Set_Output(); // 输出模式
DS18B20_Write_Level(0); // 拉低总线至少480us
DS18B20_Delay_Us(500);
DS18B20_Write_Level(1); // 释放总线,等待15~60us
DS18B20_Set_Input(); // 切换为输入模式
DS18B20_Delay_Us(60);
// 检测DS18B20的存在脉冲(拉低总线60~240us)
while(DS18B20_Read_Level() && retry < 100)
{
retry++;
DS18B20_Delay_Us(1);
}
if(retry >= 100)
return 1; // 复位失败
else
retry = 0;
// 等待存在脉冲结束(总线恢复高电平)
while(!DS18B20_Read_Level() && retry < 200)
{
retry++;
DS18B20_Delay_Us(1);
}
DS18B20_Set_Output(); // 恢复输出模式
return 0; // 复位成功
}
(2)写位时序
void DS18B20_Write_Bit(uint8_t bit)
{
DS18B20_Set_Output();
DS18B20_Write_Level(0); // 拉低总线至少1us
DS18B20_Delay_Us(2);
// 写1:释放总线;写0:保持拉低
if(bit)
DS18B20_Write_Level(1);
else
DS18B20_Write_Level(0);
DS18B20_Delay_Us(60); // 保持时序至少60us
DS18B20_Write_Level(1); // 释放总线
DS18B20_Delay_Us(2);
}
(3)读位时序
uint8_t DS18B20_Read_Bit(void)
{
uint8_t bit = 0;
DS18B20_Set_Output();
DS18B20_Write_Level(0); // 拉低总线至少1us
DS18B20_Delay_Us(2);
DS18B20_Write_Level(1); // 释放总线
DS18B20_Set_Input(); // 切换输入模式
DS18B20_Delay_Us(10); // 等待数据稳定
// 读取总线电平(DS18B20在15us内输出数据)
if(DS18B20_Read_Level())
bit = 1;
else
bit = 0;
DS18B20_Delay_Us(50); // 等待时序结束
DS18B20_Set_Output(); // 恢复输出模式
return bit;
}
(4)写字节/读字节封装
// 写字节(低位先行)
void DS18B20_Write_Byte(uint8_t byte)
{
uint8_t i;
for(i=0; i<8; i++)
{
DS18B20_Write_Bit(byte & 0x01);
byte >>= 1;
}
}
// 读字节(低位先行)
uint8_t DS18B20_Read_Byte(void)
{
uint8_t i, byte = 0;
for(i=0; i<8; i++)
{
byte >>= 1;
if(DS18B20_Read_Bit())
byte |= 0x80;
}
return byte;
}
三、温度读取逻辑封装
DS18B20读取温度的流程:复位 → 发送跳过ROM指令(0xCC)→ 发送转换指令(0x44)→ 等待转换完成 → 复位 → 发送跳过ROM指令 → 发送读暂存器指令(0xBE)→ 读取2字节温度数据 → 转换为实际温度。
// 读取DS18B20温度(返回值:0成功,1失败;temp为温度指针,单位℃,保留1位小数)
uint8_t DS18B20_Read_Temperature(float *temp)
{
uint8_t temp_h, temp_l;
uint16_t temp_raw;
if(DS18B20_Reset() != 0) // 复位失败
return 1;
DS18B20_Write_Byte(0xCC); // 跳过ROM指令(单传感器时用)
DS18B20_Write_Byte(0x44); // 启动温度转换
DS18B20_Delay_Us(10); // 无需等待,可轮询或延时(转换需约750ms)
// 等待转换完成(简易方式:延时750ms,也可检测总线电平)
HAL_Delay(750);
if(DS18B20_Reset() != 0) // 再次复位
return 1;
DS18B20_Write_Byte(0xCC); // 跳过ROM指令
DS18B20_Write_Byte(0xBE); // 读暂存器指令
// 读取温度低字节、高字节(共16位)
temp_l = DS18B20_Read_Byte();
temp_h = DS18B20_Read_Byte();
// 组合原始温度值(DS18B20温度格式:高5位符号位,低11位数据位)
temp_raw = (temp_h << 8) | temp_l;
// 转换为实际温度(分辨率12位时,1LSB=0.0625℃)
if(temp_raw & 0x8000) // 负温度
{
temp_raw = ~temp_raw + 1; // 补码转原码
*temp = -((float)temp_raw * 0.0625);
}
else // 正温度
{
*temp = (float)temp_raw * 0.0625;
}
return 0;
}
四、移植适配要点(关键!)
- 延时校准:
DS18B20_Delay_Us是时序核心,不同MCU(如51、STM32H7、ESP32)的微秒延时实现不同,需用逻辑分析仪/示波器校准,确保:- 复位拉低≥480us;
- 写位拉低≥1us,总时序≥60us;
- 读位拉低≥1us,10us后读取数据。
- 多传感器适配:若总线上有多个DS18B20,需替换“跳过ROM指令(0xCC)”为“匹配ROM指令(0x55)+ 传感器64位ROM地址”。
- 电平匹配:若MCU是3.3V、DS18B20接5V,需加电平转换(如三极管、MOS管),避免GPIO过压。
- 初始化调用:在主函数中先初始化GPIO时钟,再调用
DS18B20_Reset()检测传感器。
五、测试代码(主函数示例)
int main(void)
{
float temp;
HAL_Init();
SystemClock_Config(); // 初始化系统时钟(STM32标准流程)
MX_GPIO_Init(); // 初始化GPIO(包含DS18B20引脚)
while(1)
{
if(DS18B20_Read_Temperature(&temp) == 0)
{
// 打印温度(如串口输出,示例:temp=25.5℃)
printf("Temperature: %.1f℃\r\n", temp);
}
else
{
printf("DS18B20 read failed!\r\n");
}
HAL_Delay(1000); // 1秒读取一次
}
}
更多推荐



所有评论(0)