树莓派-利用DS18B20检测温度

一、DS18B20概述与连接

DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。这里不对DS18B20进行详细描述。
传感器的引脚有三个:

引脚 功能
VCC 提供3.3v电源
DQ 一线通讯协议
GND 地线
二、使能一线通讯协议(待补充)
pi@raspberrypi:~ $ sudo raspi-config

选择5,进入接口选项配置
再使能1-wire协议

pi@raspberrypi:~ $ vim /boot/config.txt 

再最后面添加
dtoverlay=w1-gpio-pullup,gpiopin=4
4就是pin7,采用BCM GPIO标准。

pi@raspberrypi:~ $ lsmod | grep w1
w1_therm               16384  0
w1_gpio                16384  0
wire                   40960  2 w1_gpio,w1_therm

确定是否系统是否加载一线协议的驱动模块。

三、分析

DS18B20连接树莓派后,其在linux操作系统中的存在形式为文件。其路径为/sys/bus/w1/devices/。此路径下如果出现28-开头的文件夹,说明DS18B20成功连接上树莓派。28-后的字符串代表该芯片的出厂ID,不同的DS18B20芯片其出厂ID不同。
如果DS18B20成功连接树莓派(即找到对应文件夹),进入目录,有如下:

pi@raspberrypi:/sys/bus/w1/devices/28-041731f7c0ff $ ls
driver  hwmon  id  name  power  subsystem  uevent  w1_slave

w1_slave文件中存储了DS18B20采集到的数据。

pi@raspberrypi:/sys/bus/w1/devices/28-041731f7c0ff $ cat w1_slave 
d3 01 4b 46 7f ff 0c 10 bf : crc=bf YES
d3 01 4b 46 7f ff 0c 10 bf t=29187

其中循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。这里不做分析(我也不懂)。
t=29187为我们需要的温度数据,此时温度为29.187℃。

四、代码

代码分析

/**********************************************************************

    > File Name: ds18b20.c

    > Author: 0nism

    > Created Time: Sun 16 Sep 2018 10:07:56 UTC

***********************************************************************/

#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int ds18b20_get_temperature(float *); 

int main(int argc, char *argv[])
{
    float temp = 0;

    if (ds18b20_get_temperature(&temp) < 0)
    {   
        printf("ERROR: DS18B20 get temperature failure\n");
        return 1;
    }   

    printf("DS18B20 get temperature: %f C\n", temp);

    return 0;
}


int ds18b20_get_temperature(float * temp)
{
    //  1-wire 下设备目录字符串     
    char            w1_path[50] = "/sys/bus/w1/devices/";
    
    //  芯片ID字符串
    char            chip[20];

    char            buf[128];

    DIR             *dirp;

    struct dirent   *direntp;

    int             fd = -1; 

    char            *ptr;

    float           value;

    //  传感器存在标志位
    int             found = 0;

    //  如果传入的参数错误
    if (!temp)
        return -1; 

    //  如果打开目录失败,返回空指针
    //  DIR opendir(const char *dirpath)
    if ((dirp = opendir(w1_path)) == NULL)
    {   
        //  strerror()返回参数errnum描述的出错字符串
        //  errno 是记录系统的最后一次错误代码
        printf("opendir error:%s\n", strerror(errno));
        return -2; 
    }   
    
    //  读取DIR中的数据,读完返回NULL
    //  struct dirent *readdir(DIR *dirp)
    //  dirent directory entry
    while ((direntp = readdir(dirp)) != NULL)
    {
        //  char *strstr(const char *haystack, const char *needle);
        //  从needle中寻找目标字符串haystack第一次出现的位置,'\0'不会被比较
        if (strstr(direntp->d_name, "28-"))
        {
            //  char *strcpy(char *dest, const char *src);
            //  不安全strncpy,'\0'也会被复制
            strcpy(chip, direntp->d_name);

            //  找到了ds18b20
            found = 1;
        }
    }
        closedir(dirp);

    if (!found)
    {
        printf("Error: Can not find ds18b20 in %s\n", w1_path);
        return -3;
    }

    /*
     *  char *strncat(char *dest, const char *src, size_t n);
     *  把src放到dest后,dest的'\0被覆盖',src的'\0被复制'
     *  n代表最多使用src中的n个字节
     */

    //  将芯片名加在w1_path后
    strncat(w1_path, chip, sizeof(w1_path));

    //  将要读取的文件名放在w1_path下
    strncat(w1_path, "/w1_slave", sizeof(w1_path));

    //  打开w1_slave
    if ((fd = open(w1_path, O_RDONLY)) < 0)
    {
        printf("open %s error: %s\n", w1_path, strerror(errno));
        return -4;
    }

    //  读取数据
    if (read(fd, buf, sizeof(buf)) < 0)
    {
        printf("read %s error: %s\n", w1_path, strerror(errno));
        return -5;
    }

    //  找到t=,使ptr指向目标数据
    ptr = strstr(buf, "t=") + 2;

    if (!ptr)
    {
        printf("ERROR: Can not get temperature\n");
        return -6;
    }

    //  double atof(const char *nptr);  
    *temp = atof(ptr)/1000;

    return 0;
}    

代码修改

/**********************************************************************

    > File Name: my_ds18b20.c

    > Author: 0nism

    > Created Time: Mon 17 Sep 2018 02:12:48 UTC

***********************************************************************/

#include <fcntl.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>

int ds18b20_get_temperature(float *); 

int main(int argc, char *argv[])
{
    float temp = 0;

    if ( ds18b20_get_temperature(&temp) < 0)
    {   
        printf("get temperature error.\n");
        return 1;
    }   

    printf("Temperature is %f C\n", temp);

    return 0;
}

int ds18b20_get_temperature(float * temp)
{
    char w1_path[50] = "/sys/bus/w1/devices/";
    
    char buf[128];

    int fd = -1; 

    char ID[20];

    DIR *dirp;

    struct dirent *direntp;

    int found = 0;

    char *ptr;

    if (temp == NULL)
    {   
        printf("argument error");
        return -1; 
    }   

    if ( (dirp = opendir(w1_path)) == NULL)
    {   
        printf("open %s failure.\n", w1_path);  
        return -2; 
    }   

    while ( (direntp = readdir(dirp)) != NULL)
    {   
        if (strstr(direntp->d_name, "28-") != NULL)
        {   
            strncpy(ID, direntp->d_name, 20 - strlen(ID));
            found = 1;
        }  
    }
    closedir(dirp);

    if (found != 1)
    {
        printf("can't find ds18b20.\n");
        return -3;
    }

    strncat(w1_path, ID, sizeof(w1_path)-strlen(w1_path));
    strncat(w1_path, "/w1_slave", 50-strlen(w1_path));

    if ( (fd = open(w1_path, O_RDONLY)) < 0)
    {
        printf("open %s failure.\n", w1_path);
        return -4;
    }

    if ( read(fd, buf, sizeof(buf)) < 0)
    {
        printf("read %s failure.", w1_path);
        return -5;
    }
    close(fd);

    ptr = strstr(buf, "t=");

    if ( ptr == NULL)
    {
        printf("get temperature failure.\n");
        return -6;
    }

    *temp = atof(ptr + 2)/1000;

    return 0;
}
 

猜你喜欢

转载自blog.csdn.net/qq_39023220/article/details/82758985