【HamonyOS嵌入式】BearPi-HM_Nano控制DS18B20温度传感器(注释版)

文章目录

  • 前言
  • 一、使用步骤
  • 二、程序代码
    • 1、定义初始化部分
    • 2、读写功能部分
    • 3、获取温度部分
    • 4、完整代码
      • DS18B20.h
      • DS18B20.c
  • 三、实验结果
  • 四、移植难点
  • 参考资料


前言

关于DS18B20和的基本信息在此就不详细介绍了。本文代码部分主要参考了两篇文章1 2 ,具体时序图及解说可阅读这篇博客,对DS18B20的时序等工作原理的理解也参考了另一份博客3和视频 4 ,最终,成功将基于常见STM32开发板的DS18B20程序移植到了BearPi-HM_Nano开发板中,接下来将介绍如何开发板连接DS18B20数字温度传感器测量温度。

本实验在Hi3861开发环境下编译运行,得到的温度精度为小数点后三位。

温度传感器与小熊派开发板连接如下:
DQ------GPIO7 VDD------v5.5 GND-------GND
【HamonyOS嵌入式】BearPi-HM_Nano控制DS18B20温度传感器(注释版)_第1张图片


一、使用步骤

将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中的名字] }

二、程序代码

1、定义初始化部分

定义 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;
 
}

2、读写功能部分

写数据

/********************************************
 * 函数名   :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;
}

3、获取温度部分

/********************************************
 * 函数名   :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;
    }
}

4、完整代码

DS18B20.h

#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_ */

DS18B20.c

#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;
    }
}

三、实验结果

实验结果如下:
【HamonyOS嵌入式】BearPi-HM_Nano控制DS18B20温度传感器(注释版)_第2张图片
测量结果精度为小数点后三位。

四、移植难点

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);
}

参考资料


  1. STM32学习之DS18B20数字温度传感器 ↩︎ ↩︎

  2. OpenHarmony学习笔记——Hi3861使用DHT11获取温湿度 ↩︎

  3. 第9讲_51单片机_DS18B20数字温度计模块 ↩︎

  4. STM32F103驱动DS18B20温度传感器(程序注释超详细) ↩︎

你可能感兴趣的:(嵌入式开发,单片机,c语言,嵌入式硬件,物联网,华为)