STM32学习记录:DS18B20温度传感器实验(HAL库)
- 实验摘要
-
- DS18B20简述
- STMCubeMX引脚配置
-
- 芯片选型
- 引脚和时钟配置
- 生成ARM-MDK工程
- 编写DS18B20驱动文件
-
- 新建工程项目组
- 编写DS18B20.c
-
- 写时序
- 读时序
- 读取温度
- 编写DS18B20.h
- 主程序实现功能
- 重定向printf函数
- 包含头文件路径
- 编译项目并下载到硬件中
- 连接硬件线路
- 检验结果
- 总结
实验摘要
本文主要关于如何用STM32系列单片机驱动DS18B20温度传感器实现温度的串口打印显示,本实验中STM32基于HAL库开发。本文全程记录实验过程,手把手教大家基于STM32的DS18B20温度采集实验。
DS18B20简述
首先,我们拿到DS18B20之后进行观察。
该器件只有3个引脚,分别为电源端VCC,地GND和数据线DQ。只有一条数据线,说明该器件是单总线器件。单总线器件好处是只占用一个单片机的一个I/O口。
DS18B20通信协议通过查阅DS18B20中文资料获得,该部分将在驱动文件编写部分详细讲解。
STMCubeMX引脚配置
本文使用STMCubeMX软件进行引脚和时钟的配置
芯片选型
本文选择STM32L431RC系列,根据自己的芯片选择。
引脚和时钟配置
引脚主要配置外部时钟输入输出口,串口通信USART1用于打印温度数据,传感器数据DQ接口(此处使用PA5)。
将HCLK配置为80MHz。
工程管理,设置项目名称和保存路径,选择MDK-ARM V5。
Code Generator中建议勾选Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral,为每个外设生成独立的.c文件。
生成ARM-MDK工程
点击GENERATE CODE生成ARM-MDK工程。
编写DS18B20驱动文件
新建工程项目组
单击红圈出现
这里可以自行添加文件管理项目结构,清晰明了。这里我们可以在Group
新建一个文件夹Hardware
用于存放DS18B20的驱动文件。(DS18B20.C和DS18B20.h)
接着在文件夹Hardware
中添加DS18B20.C和DS18B20.h
编写DS18B20.c
DS18B20中文资料
链接: https://pan.baidu.com/s/1k060r4s_5XI1R9r00jDP2g 提取码: nmr4 .
首先写一个粗略的微秒延时函数,用于单线协议中的延时。
void delay_us(uint32_t time)
{
time *= 10;
while(time)
time--;
}
主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。若无低电平出现一直都是高电平说明总线上无器件应答。
做为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。
我们需要配置引脚为输入或输出模式,需要两个函数。
发送复位信号和检测存在脉冲两个函数。
引脚输入输出配置函数参考gpio.c
中的void MX_GPIO_Init(void)
函数编写。
void DS18B20_IO_IN(void){
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_5;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void DS18B20_IO_OUT(void){
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_5;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void DS18B20_Rst(void){
DS18B20_IO_OUT();//引脚输出模式
//拉低总线并延时750us
DS18B20_DQ_OUT_LOW;
delay_us(750);
//释放总线为高电平并延时等待15~60us
DS18B20_DQ_OUT_HIGH;
delay_us(15);
}
uint8_t DS18B20_Check(void){
//定义一个脉冲持续时间
uint8_t retry = 0;
//引脚设为输入模式
DS18B20_IO_IN();
while(DS18B20_DQ_IN && retry < 200){
retry++;
delay_us(1);
}
if(retry >= 200)
return 1;
else
retry = 0;
//判断DS18B20是否释放总线
while(!DS18B20_DQ_IN && retry < 240){
retry++;
delay_us(1);
}
if(retry >= 240)
return 2;
return 0;
}
写时序
写周期最少为60微秒,最长不超过120微秒。写周期一开始做为主机先把总线拉低1微秒表示写周期开始。随后若主机想写0,则继续拉低电平最少60微秒直至写周期结束,然后释放总线为高电平。若主机想写1,在一开始拉低总线电平1微秒后就释放总线为高电平,一直到写周期结束。而做为从机的DS18B20则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。
void DS18B20_Write_Byte(uint8_t data){
uint8_t j;
uint8_t databit;
DS18B20_IO_OUT();
for(j=1;j<=8;j++){
databit=data&0x01;//取数据最低位
data=data>>1; //右移一位
if(databit){ //当前位写1
DS18B20_DQ_OUT_LOW;
delay_us(2);
DS18B20_DQ_OUT_HIGH;
delay_us(60);
}else{ //当前位写0
DS18B20_DQ_OUT_LOW;
delay_us(60);
DS18B20_DQ_OUT_HIGH;
delay_us(2);
}
}
}
读时序
uint8_t DS18B20_Read_Bit(void){
uint8_t data;
DS18B20_IO_OUT();
DS18B20_DQ_OUT_LOW;
delay_us(2);
DS18B20_DQ_OUT_HIGH;
DS18B20_IO_IN();
delay_us(12);
if(DS18B20_DQ_IN)
data = 1;
else
data = 0;
delay_us(50);
return data;
}
uint8_t DS18B20_Read_Byte(void){
uint8_t i,j,data;
data = 0;
for(i=1;i<=8;i++){
j = DS18B20_Read_Bit();
data = (j<<7)|(data>>1);
}
return data;
}
读取温度
基本时序操作已经完成,再根据资料中的ROM命令编写DS18B20的启动函数。由于我们只使用一个DS18B20,所以可以直接跳过ROM。
DS18B20的ROM指令集
存储器指令
用到的指令
指令名称 | 指令代码 |
---|---|
跳过ROM | 0xCC |
温度变换 | 0x44 |
读暂存器 | 0xBE |
void DS18B20_Start(void){
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);//跳过ROM
DS18B20_Write_Byte(0x44);//温度变换命令
}
uint8_t DS18B20_Init(void){
//引脚初始化
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_5;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
DS18B20_Rst();
return DS18B20_Check();
}
short DS18B20_Get_Temperature(uint8_t a){
uint8_t temp;
uint8_t TL,TH;
short temperature;
DS18B20_Start();
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);//跳过ROM
DS18B20_Write_Byte(0xbe);//读暂存器
TL = DS18B20_Read_Byte();//低八位
TH = DS18B20_Read_Byte();//高八位
//判断温度值是否为负数
if(TH>0x70){
TH = ~TH;
TL = ~TL;
temp = 0;
}else
temp = 1;
temperature = TH;
temperature <<= 8;
temperature += TL;
temperature = (float)temperature*0.625;
if(temperature)
return temperature;
else
return -temperature;
}
在DS18B20.c开头包含头文件#include "DS18B20.h"
#include "DS18B20.h"
编写DS18B20.h
#include "stm32l4xx_hal.h"
#include "main.h"
#define DS18B20_DQ_OUT_HIGH HAL_GPIO_WritePin(DQ_GPIO_Port, DQ_Pin, GPIO_PIN_SET)
#define DS18B20_DQ_OUT_LOW HAL_GPIO_WritePin(DQ_GPIO_Port, DQ_Pin, GPIO_PIN_RESET)
#define DS18B20_DQ_IN HAL_GPIO_ReadPin(DQ_GPIO_Port, DQ_Pin)
头文件中要包含hal库头文件#include "stm32l4xx_hal.h"
和#include "main.h"
定义三个引脚操作函数。
主程序实现功能
用户包含
#include "DS18B20.h"
函数声明
uint8_t DS18B20_Init(void);
short DS18B20_Get_Temperature(void);
float temperature;
while(DS18B20_Init()){
printf("DS18B20 checked failed!!!\r\n");
HAL_Delay(500);
}
printf("DS18B20 checked success!!!\r\n");
temperature = DS18B20_Get_Temperature();
if(temperature < 0)
printf("temperature = -%.2f degree\r\n",temperature/10);
else
printf("temperature = %.2f degree\r\n",temperature/10);
HAL_Delay(200);}
重定向printf函数
在usart.c中添加printf重定向函数,该函数在不同信号芯片可能有不同。
#if 1
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
while((USART1->ISR & 0x40) == 0);
USART1->TDR = (uint8_t) ch;
return ch;
}
#endif
包含头文件路径
单击魔法棒图标
选择C/C++,在include path中添加文件路径。
…>>New(Insert)>>
选择DS18B20.c和DS18B20.h的路径。
编译项目并下载到硬件中
连接硬件线路
三条线路,连接之后DS18B20模块电源指示灯亮起。
检验结果
烧录程序,并打开串口助手,这里推荐win10应用市场的串口调试助手,可以免费下载。
我们看到温度数据可以被读取出来,可以用手捂一下传感器看温度是否有变化。实验完成!
总结
该实验完成了对DS18B20温度传感器的使用,主要重点是对单总线器件通信时序的学习,掌握了单总线器件时序的原理可以帮助我们使用其他的器件。