简单通用的DS18B20温度测量程序文件

DS18B20是一个非常简单的温度传感器,对于像我这样单片机萌新是比较友好的。网上关于它的介绍非常多,包括原理、引脚、通信、以及51单片机、STM32的各种代码等等。本人写了一个简单的ds18b20.c库文件分享给大家,该文件内的函数可以实现单个元件的单次测温功能,温度精确到整数。这个程序在STM32F103C8上进行了实际测试,但是稍加修改就可以移植到其他类型的单片机上。

DS18B20的引脚定义、线路连接、工作时序、指令含义等,在他人写的文章中有详细阐述,在这里不再介绍。值得注意的是,经过我多次测试,发现在有VCC供电的情况下,VCC稳定在3.1V以上,才能正常测温;而如果使用数据线供电,在我单片机3.3V的VCC下没法正常测温(或许5V的VCC可以,但我没试验过)所以不推荐这种方法。

首先是头文件ds18b20.h:

#ifndef INC_DS18B20_H_
#define INC_DS18B20_H_


#define DS18_GPIO_Port GPIOB
#define DS18_Pin GPIO_PIN_0


unsigned char ds18b20_Init(void);
char readtemp(void);
void ds18b20start(void);


#endif /* INC_DS18B20_H_ */

头文件中#define 这两行是对ds18b20数据线对应管脚的定义,用户需要根据自己单片机上连接的管脚进行修改。需要注意的是,下面ds18b20_Init()中并没有包含管脚的初始化。用户需要在调用该函数之前先完成对GPIO管脚的初始化操作,将其配置成为开漏输出模式并配置上拉电阻。(我用的STM32Cube,自动生成了对GPIO管脚的初始化函数)

下面三个函数是main函数中需要调用的函数。具体调用方法如下:

  1. 在初始化时调用ds18b20_Init()函数。

  1. 每次测量温度前,都要先调用ds18b20start()函数。

  1. 调用完ds18b20start()后,需要等至少500ms,其测量完温度后再调用readtemp()函数进行读取(单位是摄氏度)。

接下来是这些函数的具体实现,即ds18b20.c:

/*
 * ds18b20.c
 *
 *  Created on: Dec 20, 2021
 *      Author: ASUS
 * 使用前必读
 * 需要修改的部分包括:
 * 1.在DELAY_Us中,修改__NOP()的数量,CPU频率是多少MHz,就用多少个NOP.
 * 2.添加或修改DS18_GPIO_Port,DS18_Pin的重定义内容,使之匹配对应的端口。
 * 3.如HAL_GPIO_WritePin()和HAL_GPIO_ReadPin没有定义,则自己写一个。
 * 4.在主程序中,需要对响应的GPIO端口进行初始化,设置为开漏输出和上拉电阻模式。
 * 本文件只有单次测量温度的程序。调用函数的方法:
 * 开机先用ds18b20_Init(void)初始化。每次测量前先用ds18b20start()开始测温,等大约0.5s后用readtemp()读取结果。
 */

#include "ds18b20.h"
#include "main.h"


void DELAY_Us(unsigned int  count)
{
    while(count--)
    {
        __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
        __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    }
}

unsigned char ds18b20_Init(void)
{
    /*****初始化DS18B20*****/

      unsigned char x=0;
      HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,1);    //DQ复位
      DELAY_Us(30);    //稍做延时
      HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,0);      //单片机将DQ拉低
      DELAY_Us(500);   //精确延时,大于480us
      HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,1);       //拉高总线
      DELAY_Us(100);
      x=HAL_GPIO_ReadPin(DS18_GPIO_Port,DS18_Pin);      //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
      DELAY_Us(500);
      return x;

}

void ds18b20_Write1byte(unsigned char data)
{
    unsigned char i=0;
    for(i=8;i>0;i--)
    {
        HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,0);
        DELAY_Us(3);
        HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,data&0x01);
        DELAY_Us(70);
        HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,1);
        DELAY_Us(3);
        data>>=1;

    }
    DELAY_Us(30);
}

unsigned char ds18b20_Read1byte(void)
{
    unsigned char i,j,dat;
     dat=0;
    for (i=1;i<=8;i++)
    {
        HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,0);
        DELAY_Us(3);
        HAL_GPIO_WritePin(DS18_GPIO_Port,DS18_Pin,1);
        DELAY_Us(18);
        j=HAL_GPIO_ReadPin(DS18_GPIO_Port,DS18_Pin);
        DELAY_Us(50);
        dat=(j<<7)|(dat>>1);
    }
    return dat;
}

void ds18b20start(void)
{
    ds18b20_Init();
    ds18b20_Write1byte(0xcc);

    ds18b20_Write1byte(0x44);
}

char readtemp(void)
{
    unsigned char TL=0x01,TH=0x07;
    char temp;
    ds18b20_Init();
    ds18b20_Write1byte(0xcc);
    ds18b20_Write1byte(0xbe);
    TL=ds18b20_Read1byte();
    DELAY_Us(1);
    TH=ds18b20_Read1byte();
    temp=(char)((TH<<4)|TL>>4);
    return temp;
}

这里首先一个函数是微秒级延时函数DELAY_Us()。这里使用了一个简单的__NOP()做延时。这实际上对应着CPU的汇编指令,表示延时一个时钟周期,什么都不做。所以用户需要根据CPU时钟频率修改__NOP()的个数,频率是多少MHz就加多少个__NOP()。当然,不同单片机的指令名称可能有所不同,用户自行替换就行了。

用户还需要修改的一部分是对GPIO端口的读写操作函数。我这里用的STM32HAL库,所以用的是HAL_GPIO_WritePin()和HAL_GPIO_ReadPin()函数。如果大家没有此库函数,就在本文件下面写一个,重新定义一下。

用户修改完上述部分后,就可以在主程序中调用ds18b20.h中的三个函数,进行温度的测量了。测量的结果就可以根据你喜欢的方式进行输出~(不过这就不是本文件需要包含的内容了)

如果有错误,还请在评论区指正。如果想看多点测温,欢迎在评论区留言,想看的人多我就写一写(嘿嘿

物联沃分享整理
物联沃-IOTWORD物联网 » 简单通用的DS18B20温度测量程序文件

发表评论