STM32玩转物联网11-DS18B20实验
在嵌入式开发中,温度测量是一个常见的应用场景,而DS18B20作为一种单总线数字温度传感器,以其高精度、低功耗、易操作等特点,成为了许多开发者的首选。本节课,我们将带领大家掌握如何使用STM32来驱动DS18B20,实现温度的精确测量。DS18B20是一种单总线数字温度传感器,它能够直接输出数字信号,避免了传统模拟温度传感器需要模数转换的复杂过程。它的主要特点如下:(1)单总线接口仅需一个GPIO
前言
在嵌入式开发中,温度测量是一个常见的应用场景,而DS18B20作为一种单总线数字温度传感器,以其高精度、低功耗、易操作等特点,成为了许多开发者的首选。本节课,我们将带领大家掌握如何使用STM32来驱动DS18B20,实现温度的精确测量。
一、准备
1.DS18B20简介
DS18B20是一种单总线数字温度传感器,它能够直接输出数字信号,避免了传统模拟温度传感器需要模数转换的复杂过程。它的主要特点如下:
(1)单总线接口
仅需一个GPIO引脚即可实现通信,大大简化了硬件连接。
(2)高精度
测量精度可达±0.5℃,温度范围为-55℃至+125℃。
(3)低功耗
在测量时仅消耗微弱电流,非常适合电池供电的便携式设备。
(4)多设备连接
单总线上可以挂接多个DS18B20,通过ROM码区分每个设备。
2.DS18B20控制方法
2.1 原理图
原理图如下图所示,注意,DQ引脚需要上拉4.7K电阻,以确保信号的稳定传输。
2.2 硬件连接
硬件连接示意图如下所示:
2.3 总线协议
(1)初始化时序
- 复位脉冲
主机拉低总线至少480us,然后释放总线。 - 存在脉冲
DS18B20在检测到总线的上升沿后,等待15-60us,然后发出一个低电平持续60-240us的存在脉冲。
(2)写 ‘1’ 时序
- 主机拉低数据线15us后迅速拉高,DS18B20在15-60us的窗口内采样数据。

(3)写 ‘0’ 时序
- 主机拉低数据线至少60us。

(4)读 时序
- 读触发信号
主机拉低数据线小于15us,然后释放总线。 - 数据采样
主机在释放总线后15us开始采样数据。
二、实例
1. 建立工程
将上节《OLED显示实验》代码复制并修改名字为:10.OLED,打开Project.ioc文件,配置PB4输出。
生成代码后,通过Keil打开工程,在Application/User/Driver处右击选择Add New Item…,添加C文件,名称命名为drv_ds18b20。
同样方法创建drv_ds18b20.h文件, 上图第2步选择Header File(.h)文件即可,drv_ds18b20.h内容如下:
#ifndef __DRV_DS18B20_H__
#define __DRV_DS18B20_H__
#include "main.h"
////IO操作函数
#define DS18B20_DQ_OUT PBout(4) //数据端口 PB4
#define DS18B20_DQ_IN PBin(4) //数据端口 PB4
uint8_t DS18B20_Init(void); //初始化DS18B20
float DS18B20_Get_Temp(void); //获取温度
void DS18B20_Start(void); //开始温度转换
void DS18B20_Write_Byte(uint8_t dat);//写入一个字节
uint8_t DS18B20_Read_Byte(void); //读出一个字节
uint8_t DS18B20_Read_Bit(void); //读出一个位
uint8_t DS18B20_Check(void); //检测是否存在DS18B20
void DS18B20_Rst(void); //复位DS18B20
#endif
drv_ds18b20.c内容如下:
/****************************************Copyright (c)****************************************************
**
** File name: drv_ds18b20.c
** Created by: XiaoYe
** Created date: 2025-06-01
** Version: v1.0
** Descriptions: The original
** Link address: https://gitee.com/iot_camp/kits_inn_iot
**
*********************************************************************************************************/
#include "drv_ds18b20.h"
#include "gpio.h"
/**
* @brief 设置PB4方向输入:
* @param 输入参数: 无
* @return 返 回 值: 无
*/
void DS18B20_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 串口外设功能GPIO配置 */
GPIO_InitStruct.Pin = DS18B20_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}
/**
* @brief 设置PB4方向输出:
* @param 输入参数: 无
* @return 返 回 值: 无
*/
void DS18B20_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 串口外设功能GPIO配置 */
GPIO_InitStruct.Pin = DS18B20_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}
/**
* @brief 复位DS18B20
* @param 输入参数: 无
* @return 返 回 值: 无
*/
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //SET PA0 OUTPUT
DS18B20_DQ_OUT = 0; //拉低DQ
delay_us(750); //拉低750us
DS18B20_DQ_OUT = 1; //DQ=1
delay_us(15); //15US
}
/**
* @brief 等待DS18B20的回应
* @param 输入参数: 无
* @return 返 回 值: 1:未检测到DS18B20的存在, 0:存在
*/
uint8_t DS18B20_Check(void)
{
uint8_t retry=0;
DS18B20_IO_IN();//SET PA0 INPUT
while (DS18B20_DQ_IN&&retry<200)
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)return 1;
return 0;
}
/**
* @brief 从DS18B20读取一个位
* @param 输入参数: 无
* @return 返 回 值: 1/0
*/
uint8_t DS18B20_Read_Bit(void) // read one bit
{
uint8_t data;
DS18B20_IO_OUT();//SET PA0 OUTPUT
DS18B20_DQ_OUT = 0;
delay_us(2);
DS18B20_DQ_OUT = 1;
DS18B20_IO_IN();//SET PA0 INPUT
delay_us(12);
if(DS18B20_DQ_IN)
data=1;
else
data=0;
delay_us(50);
return data;
}
/**
* @brief 从DS18B20读取一个字节
* @param 输入参数: 无
* @return 返 回 值: 读到的数据
*/
uint8_t DS18B20_Read_Byte(void) // read one byte
{
uint8_t i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
/**
* @brief 写一个字节到DS18B20
* @param 输入参数: dat:要写入的字节
* @return 返 回 值: 无
*/
void DS18B20_Write_Byte(uint8_t dat)
{
uint8_t j;
uint8_t testb;
DS18B20_IO_OUT();//SET PA0 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DS18B20_DQ_OUT = 0;// Write 1
delay_us(2);
DS18B20_DQ_OUT = 1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT = 0;// Write 0
delay_us(60);
DS18B20_DQ_OUT = 1;
delay_us(2);
}
}
}
/**
* @brief 开始温度转换
* @param 输入参数: 无
* @return 返 回 值: 无
*/
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
/**
* @brief 初始化DS18B20的IO口 DQ 同时检测DS的存在
* @param 输入参数: 无
* @return 返 回 值: 1:不存在, 0:存在
*/
uint8_t DS18B20_Init(void)
{
DS18B20_Rst();
return DS18B20_Check();
}
/**
* @brief 从ds18b20得到温度值
* @param 输入参数: 无
* @return 返 回 值: 温度值 (-550~1250)
*/
float DS18B20_Get_Temp(void)
{
uint8_t temp;
uint8_t TL,TH;
short tem;
float temperature;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// Read Scratchpad
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}else temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得低八位
temperature=(float)tem*0.625/10;//转换
if(temp)
return temperature; //返回温度值
else
return -temperature;
}
main函数内容如下, 修改OLED显示内容,while(1)中定期调用DS18B20_Get_Temp()获取实时温度数据,并更新OLED显示。
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int ret = 0;
int cnt = 300;
float value_temp = 0;
char str_temp[16] = { 0x00 };
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_USART3_UART_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
printf("start application\r\n");
// 使能空闲中断
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart3, (uint8_t *)Uart_Frame_Record.Data_RX_BUF, RX_BUF_MAX_LEN); // 启动DMA接收
// 获取温度数据
value_temp = DS18B20_Get_Temp();
// 初始化 OLED
oled_init();
delay_ms(200);
oled_fill(0xFF);//全屏点亮
delay_ms(200);
oled_fill(0x00);//全屏灭
// 显示OLED屏幕信息
oled_show_string(24, 0, (unsigned char *)" System", 2);
oled_show_chinese(5, 4, 12);
oled_show_chinese(20, 4, 13);
#ifdef SUPPORT_ESP8266
// 连接路由器
ESP8266_STAInit();
delay_ms(1000);
if (wifi_connect_status != WIFI_GOT_IP)
{
while(ESP8266_STAConnect((char *)Wssid, (char *)Wpassword));
}
// 连接MQTT 服务器
printf("ready to connect to mqtt server\r\n");
mqtt_task_init();
mqtt_task_subcribe();
//mqtt_task_report();
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
#ifdef SUPPORT_ESP8266
mqtt_task_report();
HAL_Delay(60000);
#endif
value_temp = DS18B20_Get_Temp();
sprintf(str_temp, ": %.1f ", value_temp);
oled_show_string(40, 4, (unsigned char *)str_temp, 2);
HAL_Delay(1000);
}
return ret;
/* USER CODE END 3 */
}
2. 核心函数
drv_ds18b20.c中核心函数为float DS18B20_Get_Temp(void),每次读取数据都会先发送复位信号,注意命令含义,0xCC表示使用此命令同时寻址总线上的所有设备,而无需发送任何ROM代码信息,主设备可以通过发出Skip ROM命令和Convert T[0x44]命令,使总线上的所有DS18B20同时执行温度转换。
注意,只有当总线上只有一个从属设备时,Read Scratchpad[0xBE]命令才能跟随Skip ROM命令。在这种情况下,通过允许主设备从从设备读取而不发送设备的64位ROM代码,可以节省时间。如果存在多个从属设备,则Skip ROM命令和Read Scratchpad命令将导致总线上的数据冲突,因为多个设备将尝试同时传输数据。
float DS18B20_Get_Temp(void)
{
uint8_t temp;
uint8_t TL,TH;
short tem;
float temperature;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// Read Scratchpad
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}else temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得低八位
temperature=(float)tem*0.625/10;//转换
if(temp)
return temperature; //返回温度值
else
return -temperature;
}
3. 程序执行
本实验实现了上电初始化完成后,每隔1秒钟获取一次温度数据,并立刻显示在OLED上面。
三、小结
如您在使用过程中有任何问题,请加QQ群进一步交流。
QQ交流群:573122190 (备注:物联网项目交流)
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)