DS18B20温度传感器在树莓派下获取实时温度

1. DS18B20温度传感器的介绍

DS18B20是美信公司的一款温度传感器,树莓派可以通过1-Wire和DS18B20进行通信,最终将温度读出。1-Wire总线的硬件接口很简单,只需要把18B20的数据引脚和树莓派的一个IO口接上就可以通信。硬件的简单,随之而来的,就是软件时序的复杂。1-Wire总线的时序比较复杂(这里就不讲了),我们来看一下DS18B20的硬件原理图,如图下图所示。

2.代码流程分析

2.1获取实时温度值

先来看一张图:
在这里插入图片描述
我们要在/sys/bus/w1/devices/28-041731f7c0ff/w1_slave路径下获取实时温度,即t=12062。首先打开文件(用到open函数),然后读文件(用到read函数),在读到的数据中找出"t=12062"这个字符串(用到strstr函数),此时用指针保存该字符串的首地址,但"t="并不是我们需要的数据,所以此时我们应该将指针+2,直接指向实时温度数据。还应注意的是此时我们获得的数据是一个字符串,所以要用到atof函数(将字符串转成float类型),当然温度值肯定是两位数,所以还得除以1000。最终获得实时温度值。

这部分代码如下:

60    if((fd=open(path1,O_RDONLY))<0)  //根据目标路径以只读形式打开文件,并加上错误判断
 61      {
 62         printf("open file %s failure: %s\n",path1,strerror(errno));//打开文件失败
 63         return -3;
 64      }
 65 
 66    if(read(fd,buff,sizeof(buff))<0)           //读取文件内容,并保存在buff中 同是加上错误判断
 67    {
 68       printf("read %s error :%s\n",path1,strerror(errno));//读文件失败
 69       return -4;
 70    }
 71 
 72    ptr=strstr(buff,"t=")+2;  // 跳过"t="字符串 所以加2 直接指向温度数据
 73 
 74    if(!ptr)
 75     {
 76       printf("error:can not get temperature\n");// buff为空 获取温度失败
 77       return -5;
 78     }
 79 
 80      temperature=atof(ptr)/1000;//atof()函数将字符串转成float型
 81      printf("The sampling temperature of DS18B20 is %f \n",temperature);

2.2获取温度值存放路径

但是此时还是一个bug,因为每个DS18B20的产品序列号不一样,那么温度保存文件的路径也就会不一样,所以我们编写程序的时候,为了得到更广泛的适用性并不能直接用read()去读取相应路径下的文件。(这是一个工程师应该考虑的)
/sys/bus/w1/devices/这一部分路径都是固定的,定义一个数组存放该路径,打开该路径下的文件列表(opendir函数),然后while
循环访问该文件列表
,找到以"28-“开头的序列号(strstr函数),再将该序列号存入缓冲区(strcpy函数),然后将缓冲区中的数据连接在固定路径后(strncat函数),最后再次更新路径**添加上路径"w1_slave”😗*单总线从动设备(strncat函数)。

这部分代码如下:

29   if((dirp=opendir(path1))==NULL)
 30   {
 31   printf("opendir %s error :%s\n",path1,strerror(errno));//打开PATH1失败
 32   return -1;
 33   }
 34   while((direntp=readdir(dirp))!=NULL)//循环访问文件列表
 35   {
 36     if(strstr(direntp->d_name,"28-"))//找到以"28-"开头的温度传感器序列号
 37     {
 38       strcpy(temp,direntp->d_name);//存入缓冲区
 39       found=1;//返回找到标志符
 40     }
 41   }
 42 
 43   closedir(dirp);//及时关闭文件夹
 44 
 45   if(!found)//未找到ds18b20
 46   {
 47     printf("can not find ds18b20 in %s\n",path1);
 48     return -2;
 49   }
 50 
 51   strncat (path1,temp,sizeof(temp));   //将序列号作为路径的一部分
 52   strncat (path1,"/w1_slave",9);      //再次更新路径(添加w1_slave):单总线从动设备

2.3用到的库函数

1、strstr()函数:
原型: extern char *strstr(char *str1, const char *str2);
作用:用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。
2、atof()函数:
原型: double atof(const char *nptr);
作用: 把字符串转换成浮点数
3、strcpy()函数:
原型:char *strcpy(char *dest, const char *src);
作用:把 src 所指向的字符串复制到 dest,该函数返回一个指向最终的目标字符串 dest 的指针。
4、strncat()函数:
因为strcat()函数无法检测第一个数组是否能够容纳第二个字符串,这时就要用到strncat()函数。
原型:char *strncat(char *dest,const char *src,int n);
作用:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处‘\0’),并添加‘\0’

3.完整代码

1 #include <stdio.h>    //头文件全部可以通过man+函数名找到
  2 #include <string.h>
  3 #include <sys/types.h>
  4 #include <sys/stat.h>
  5 #include <fcntl.h>
  6 #include <dirent.h>
  7 #include <unistd.h>
  8 #include <errno.h>
  9 #include <stdlib.h>
 10 
 11 #define PATH   "/sys/bus/w1/devices/"   //宏定义温度传感器的存放路径
 12 #define PATH1_SIZE    100               //宏定义路径大小
 13 #define BUFF_SIZE     100               //宏定义缓冲区大小
 14 
 15 
 16 int main(int argc,char **argv)
 17 {
 18   char          path1[PATH1_SIZE]=PATH;          //局部变量保存温度传感器的路径
 19   int           fd=-1;                           //初始化文件描述符
 20   DIR           *dirp;                           //文件列表指针,opendir函数的返回类型,用来指定打开的文件夹
 21   struct        dirent  *direntp;               //系统调用的struct dirent的指针变量 readdir返回的结构体指针,用来指向打开文件夹的内容
 22   char          temp[15];                       //缓冲区用来存放温度传感器的序列号
 23   int           found=0;                        //找到序列号的标志,=0 未找到 ,=1 找到
 24   char          buff[BUFF_SIZE];                //存放温度的缓冲区
 25   char          *ptr=NULL;                      //指向实时温度缓冲区的指针
 26   float         temperature=0.00;              //实时温度数据
 27 
 28 
 29   if((dirp=opendir(path1))==NULL)
 30   {
 31   printf("opendir %s error :%s\n",path1,strerror(errno));//打开PATH1失败
 32   return -1;
 33   }
 34   while((direntp=readdir(dirp))!=NULL)//循环访问文件列表
 35   {
 36     if(strstr(direntp->d_name,"28-"))//找到以"28-"开头的温度传感器序列号
 37     {
 38       strcpy(temp,direntp->d_name);//存入缓冲区
 39       found=1;//返回找到标志符
 40     }
 41   }
 42 
 43   closedir(dirp);//及时关闭文件夹
 44 
 45   if(!found)//未找到ds18b20
 46   {
 47     printf("can not find ds18b20 in %s\n",path1);
 48     return -2;
 49   }
 50 
 51   strncat (path1,temp,sizeof(temp));   //将序列号作为路径的一部分
 52   strncat (path1,"/w1_slave",9);      //再次更新路径(添加w1_slave):单总线从动设备
 53 
 54 
 55 
 56 /****************前面一部分为找到目标路径,后一部分是在目标路径下打开文件并读取部分文件内容***************************/
 57 
 58 
 59 
 60    if((fd=open(path1,O_RDONLY))<0)  //根据目标路径以只读形式打开文件,并加上错误判断
 61      {
 62         printf("open file %s failure: %s\n",path1,strerror(errno));//打开文件失败
 63         return -3;
 64      }
 65 
 66    if(read(fd,buff,sizeof(buff))<0)           //读取文件内容,并保存在buff中 同是加上错误判断
 67    {
 68       printf("read %s error :%s\n",path1,strerror(errno));//读文件失败
 69       return -4;
 70    }
 71 
 72    ptr=strstr(buff,"t=")+2;  // 跳过"t="字符串 所以加2 直接指向温度数据
 73 
 74    if(!ptr)
 75     {
 76       printf("error:can not get temperature\n");// buff为空 获取温度失败
 77       return -5;
 78     }
 79 
 80      temperature=atof(ptr)/1000;//atof()函数将字符串转成float型
 81      printf("The sampling temperature of DS18B20 is %f \n",temperature);
 82 
 83      return 0;//成功返回
 84 }
           

4.输出结果

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值