关于DS18B20和的基本信息在此就不详细介绍了。本文代码部分主要参考了两篇文章1 2 ,具体时序图及解说可阅读这篇博客,对DS18B20的时序等工作原理的理解也参考了另一份博客3和视频 4 ,最终,成功将基于常见STM32开发板的DS18B20程序移植到了BearPi-HM_Nano开发板中,接下来将介绍如何开发板连接DS18B20数字温度传感器测量温度。
本实验在Hi3861开发环境下编译运行,得到的温度精度为小数点后三位。
温度传感器与小熊派开发板连接如下:
DQ------GPIO7 VDD------v5.5 GND-------GND
将DS18B20的头文件和.c文件放到所需的工程中即可。
step1 、在程序头部引入DS18B20.h头文件,
step2、在主程序中调用初始化函数 DS18B20_Init()
step3、在需要读取温度的位置调用读取函数DS18B20_Read_Temperature(),用于获取当前温度currentTemp。
#include DS18B20.h //step1
#include (other xxx.h)
....
void task(void){
float currentTemp;
GpioInit();
DS18B20_Init(); //step2
while(1){
currentTemp=DS18B20_Read_Temperature(); //step3
printf("\nCurrentTemperature = %.3f",currentTemp);
}
}
在工程的BUILD.gn文件中,
step4、static_library(“修改一下这里,自定义”)
step5、sources = [… …]中增加DS18B20.c文件,
step6、并在include_dirs = [… …]中增加DS18B20.c和DS18B20.h文件中所需的头文件路径。
在顶层BUIL.gn中,
step7、lite_component(“app”) {
features = [增加你要编译的工程,对应step4中的名字] }
定义 GPIO7为DS18B20的信号引脚,再定一个全局变量DS18B20_DQ_IN存放从DS18B20中读取到的电平信号。
#define GPIO_DQ WIFI_IOT_IO_NAME_GPIO_7
WifiIotGpioValue DS18B20_DQ_IN = {0};
将与输入有关的两个功能打包成函数,以便后面使用。
/******************************************************
* 函数名 :DS18B20_IO_IN
* 功能 :设置端口为输入
* 输入 :无
* 输出 :无
*******************************************************/
void DS18B20_IO_IN(void){
//设置GPIO_DQ为输入模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_IN);
//配置为浮空输入
IoSetPull(GPIO_DQ,WIFI_IOT_IO_PULL_NONE);
}
/******************************************************
* 函数名 :GPIO_GetInputValue
* 功能 :获取GPIO输入状态
* 输入 :id, *val
* 输出 :0/1
*******************************************************/
uint8_t GPIO_GetInputValue(WifiIotIoName id,WifiIotGpioValue *val){
GpioGetInputVal(id,val);
return *val;
}
初始化DS18B20
/********************************************
* 函数名 :DS18B20_Init
* 功能 :初始化DS18B20
* 输入 :无
* 输出 :无
********************************************/
uint8_t DS18B20_Init(void){
//配置数据信号引脚GPIO_7(GPIO_DQ)
IoSetFunc(GPIO_DQ,WIFI_IOT_IO_FUNC_GPIO_7_GPIO);
//设置GPIO_DQ为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
//设置GPIO_DQ输出高电平
GpioSetOutputVal(GPIO_DQ,1);
//复位DS18B20
DS18B20_Res();
//等待DS18B20的回应
return DS18B20_Check();
}
/********************************************
* 函数名 :DS18B20_Res
* 功能 :复位DS18B20
* 输入 :无
* 输出 :无
********************************************/
void DS18B20_Res(void){
//设置GPIO_DQ为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
//拉低电平
GpioSetOutputVal(GPIO_DQ, 0);
//延时750us
usleep(750);
//拉高电平
GpioSetOutputVal(GPIO_DQ, 1);
//延时15us,为应答脉冲做准备
hi_udelay(15);
}
响应部分
/********************************************
* 函数名 :DS18B20_Check
* 功能 :将引脚设置为输入模式,等待DS18B20拉低电平的回应
* 判断引脚低电平时间是否大于60us,小于240us
* 返回应答结果
* 输入 :无
* 输出 :返回1 无响应 返回0 有响应
* ******************************************/
uint8_t DS18B20_Check(void){
uint8_t t=0;
//配置GPIO_3为输入模式
DS18B20_IO_IN();
//等待应答,引脚一直为高,未被设备主动拉低。提供200us的超时时间
while(GPIO_GetInputValue(GPIO_DQ,&DS18B20_DQ_IN) && t<200){
t++;
hi_udelay(1);
}
//若超时仍未响应,则返回1
if(t>=200){
printf("\nError: Waiting Response Overtime!Non-Respond!");
return 1;
}else{
t=0;
}
//引脚响应,则判断引脚低电平时间是否大于60us,小于240us
while((!GPIO_GetInputValue(GPIO_DQ,&DS18B20_DQ_IN)) && t<240){
t++;
hi_udelay(1);
}
//响应时间过长,应答失败
if(t>=240){
printf("\nError: Responsing Overtime! \n");
return 1;
}
printf("\nResponse is OK !(t = %d)",t);
return 0;
}
写数据
/********************************************
* 函数名 :DS18B20_Write_Byte
* 功能 :写一个字节到DS18B20
* 输入 :要写入的字节
* 输出 :无
* ******************************************/
void DS18B20_Write_Byte(uint8_t byte){
uint8_t i,test;
//设置GPIO_3为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
for(i=1;i<=8;i++){
test = byte & 0x01;
byte = byte >> 1;
if(test){ //写1
GpioSetOutputVal(GPIO_DQ, 0);
hi_udelay(2);
GpioSetOutputVal(GPIO_DQ, 1);
hi_udelay(60);
}else{ //写0
GpioSetOutputVal(GPIO_DQ, 0);
hi_udelay(60);
GpioSetOutputVal(GPIO_DQ, 1);
hi_udelay(2);
}
}
}
读数据
/********************************************
* 函数名 :DS18B20_Read_Byte
* 功能 :读取一个字节
* 输入 :无
* 输出 :1/0
* ******************************************/
uint8_t DS18B20_Read_Bit(void){
uint8_t t=0;
//设置GPIO_3为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
GpioSetOutputVal(GPIO_DQ, 0); //拉低
hi_udelay(2);
GpioSetOutputVal(GPIO_DQ, 1); //释放
//设置GPIO_3为输入模式
DS18B20_IO_IN();
hi_udelay(12);
//获取输入电平值
if(GPIO_GetInputValue(GPIO_DQ,&DS18B20_DQ_IN)){
hi_udelay(50);
return 1;}
else{
hi_udelay(50);
return 0;}
}
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);
hi_udelay(2);
}
return data;
}
/********************************************
* 函数名 :DS18B20_Read_Temperature
* 功能 :温度读取
* 输入 :无
* 输出 :温度
* ******************************************/
void DS18B20_Change_Temperature(void){
DS18B20_Res();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0x44);
}
float DS18B20_Read_Temperature(void){
uint8_t TL,TH;
uint16_t temp;
short temperature;
float result;
DS18B20_Change_Temperature();
DS18B20_Res();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); //skip rom
DS18B20_Write_Byte(0xbe); //covert
TL = DS18B20_Read_Byte(); //lsb
TH = DS18B20_Read_Byte(); //msb
if(TH >7){ //若读取到的温度为负数,则高低位都取反
TH = ~TH;
TL = ~TL;
temp = 0;
}else{ //读取到的温度为正
temp = 1;
}
temperature = TH;
temperature = temperature << 8;
temperature += TL;
result = (float)temperature * 0.0625;
printf("\nresult = %.3f",result);
if(temp){
return result;
}else{
return -result;
}
}
#ifndef _DS18B20_H_
#define _DS18B20_H_
#include
#include "cmsis_os2.h"
uint8_t DS18B20_Init(void);
void DS18B20_Res(void);
uint8_t DS18B20_Check(void);
void DS18B20_Write_Byte(uint8_t byte);
uint8_t DS18B20_Read_Byte(void);
float DS18B20_Read_Temperature(void);
#endif /* _DS18B20_H_ */
#include
#include
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "ds18b20.h"
#include "hi_time.h"
#define GPIO_DQ WIFI_IOT_IO_NAME_GPIO_7
WifiIotGpioValue DS18B20_DQ_IN = {0};
/******************************************************
* 函数名 :DS18B20_IO_IN
* 功能 :设置端口为输入
* 输入 :无
* 输出 :无
*******************************************************/
void DS18B20_IO_IN(void){
//设置GPIO_DQ为输入模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_IN);
//配置为浮空输入
IoSetPull(GPIO_DQ,WIFI_IOT_IO_PULL_NONE);
}
/******************************************************
* 函数名 :GPIO_GetInputValue
* 功能 :获取GPIO输入状态
* 输入 :id, *val
* 输出 :0/1
*******************************************************/
uint8_t GPIO_GetInputValue(WifiIotIoName id,WifiIotGpioValue *val){
GpioGetInputVal(id,val);
return *val;
}
/********************************************
* 函数名 :DS18B20_Init
* 功能 :初始化DS18B20
* 输入 :无
* 输出 :无
********************************************/
uint8_t DS18B20_Init(void){
//配置数据信号引脚GPIO_7(GPIO_DQ)
IoSetFunc(GPIO_DQ,WIFI_IOT_IO_FUNC_GPIO_7_GPIO);
//设置GPIO_DQ为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
//设置GPIO_DQ输出高电平
GpioSetOutputVal(GPIO_DQ,1);
//复位DS18B20
DS18B20_Res();
//等待DS18B20的回应
return DS18B20_Check();
}
/********************************************
* 函数名 :DS18B20_Res
* 功能 :复位DS18B20
* 输入 :无
* 输出 :无
********************************************/
void DS18B20_Res(void){
//设置GPIO_DQ为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
//拉低电平
GpioSetOutputVal(GPIO_DQ, 0);
//延时750us
usleep(750);
//拉高电平
GpioSetOutputVal(GPIO_DQ, 1);
//延时15us,为应答脉冲做准备
hi_udelay(15);
}
/********************************************
* 函数名 :DS18B20_Check
* 功能 :将引脚设置为输入模式,等待DS18B20拉低电平的回应
* 判断引脚低电平时间是否大于60us,小于240us
* 返回应答结果
* 输入 :无
* 输出 :返回1 无响应 返回0 有响应
* ******************************************/
uint8_t DS18B20_Check(void){
uint8_t t=0;
//配置GPIO_3为输入模式
DS18B20_IO_IN();
//等待应答,引脚一直为高,未被设备主动拉低。提供200us的超时时间
while(GPIO_GetInputValue(GPIO_DQ,&DS18B20_DQ_IN) && t<200){
t++;
hi_udelay(1);
}
//若超时仍未响应,则返回1
if(t>=200){
printf("\nError: Waiting Response Overtime!Non-Respond!");
return 1;
}else{
t=0;
}
//引脚响应,则判断引脚低电平时间是否大于60us,小于240us
while((!GPIO_GetInputValue(GPIO_DQ,&DS18B20_DQ_IN)) && t<240){
t++;
hi_udelay(1);
}
//响应时间过长,应答失败
if(t>=240){
printf("\nError: Responsing Overtime! \n");
return 1;
}
printf("\nResponse is OK !(t = %d)",t);
return 0;
}
/********************************************
* 函数名 :DS18B20_Write_Byte
* 功能 :写一个字节到DS18B20
* 输入 :要写入的字节
* 输出 :无
* ******************************************/
void DS18B20_Write_Byte(uint8_t byte){
uint8_t i,test;
//设置GPIO_3为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
for(i=1;i<=8;i++){
test = byte & 0x01;
byte = byte >> 1;
if(test){ //写1
GpioSetOutputVal(GPIO_DQ, 0);
hi_udelay(2);
GpioSetOutputVal(GPIO_DQ, 1);
hi_udelay(60);
}else{ //写0
GpioSetOutputVal(GPIO_DQ, 0);
hi_udelay(60);
GpioSetOutputVal(GPIO_DQ, 1);
hi_udelay(2);
}
}
}
/********************************************
* 函数名 :DS18B20_Read_Byte
* 功能 :读取一个字节
* 输入 :无
* 输出 :1/0
* ******************************************/
uint8_t DS18B20_Read_Bit(void){
uint8_t t=0;
//设置GPIO_3为输出模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_OUT);
GpioSetOutputVal(GPIO_DQ, 0); //拉低
hi_udelay(2);
GpioSetOutputVal(GPIO_DQ, 1); //释放
//设置GPIO_3为输入模式
DS18B20_IO_IN();
hi_udelay(12);
//获取输入电平值
if(GPIO_GetInputValue(GPIO_DQ,&DS18B20_DQ_IN)){
hi_udelay(50);
return 1;}
else{
hi_udelay(50);
return 0;}
}
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);
hi_udelay(2);
}
return data;
}
/********************************************
* 函数名 :DS18B20_Read_Temperature
* 功能 :温度读取
* 输入 :无
* 输出 :温度
* ******************************************/
void DS18B20_Change_Temperature(void){
DS18B20_Res();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0x44);
}
float DS18B20_Read_Temperature(void){
uint8_t TL,TH;
uint16_t temp;
short temperature;
float result;
DS18B20_Change_Temperature();
DS18B20_Res();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); //skip rom
DS18B20_Write_Byte(0xbe); //covert
TL = DS18B20_Read_Byte(); //lsb
TH = DS18B20_Read_Byte(); //msb
if(TH >7){
TH = ~TH;
TL = ~TL;
temp = 0;
}else{
temp = 1;
}
temperature = TH;
temperature = temperature << 8;
temperature += TL;
result = (float)temperature * 0.0625;
printf("\nresult = %.3f",result);
if(temp){
return result;
}else{
return -result;
}
}
1、延时
这里的实现需要导入hi_time.h头文件,调用hi_udelay()实现而不能用usleep()函数。1
2、输入模式的设置
不能仅用GpioSetDir(WifiIotGpioIdx id, WifiIotGpioDir dir)函数,还需加上上拉函数将GPIO引脚设置为浮空输入,将读取传感器的值打包成了一个独立的函数,如下
void DS18B20_IO_IN(void){
//设置GPIO_DQ为输入模式
GpioSetDir(GPIO_DQ,WIFI_IOT_GPIO_DIR_IN);
//配置为浮空输入
IoSetPull(GPIO_DQ,WIFI_IOT_IO_PULL_NONE);
}
STM32学习之DS18B20数字温度传感器 ↩︎ ↩︎
OpenHarmony学习笔记——Hi3861使用DHT11获取温湿度 ↩︎
第9讲_51单片机_DS18B20数字温度计模块 ↩︎
STM32F103驱动DS18B20温度传感器(程序注释超详细) ↩︎