Linux下用树莓派DS18B20温度传感器读取温度并上传至服务端

目录

一、DS18B20温度传感器

二、逻辑分析

三、实战操作

1、服务端

2、客户端

3、运行结果


一、DS18B20温度传感器

        DS18B20是比较常用到的温度传感器,采用单总线控制。是美国DALLAS半导体公司继DS1820之后最新推出的一种改进型智能温度传感器。关于该温度传感器的具体介绍可以看这里-DS18B20。

        以下是连接DS18B20的基本步骤:

(1)DS18B20有三个引脚:VCC(电源)、GND(地)和DQ(数据引脚),DQ引脚连接到微控制器的输入引脚,用于数据通信。

(2)DS18B20通过1-wire协议与主控制器通信,树莓派需要相应的1-wire库或者驱动程序。

(3)读取DS18B20获取的温度值,并进行相应温度转换和计算

二、逻辑分析

        我使用的是树莓派4B,DS18B20将踩到的的温度值存放在 /sys/bus/w1/devices/28-0317320a8aff/w1_slave 文件中(不同的传感器型号“28-”处会略有不同),在终端使用命令 cat   /sys/bus/w1/devices/28-0317320a8aff/w1_slave即可看到文件内容,如下图所示:

 ?前面那些数据我们不管他,可以看到“t=11250”,这个就是我这个设备上的实时温度(11.25℃)。了解到这些之后,我们来捋一捋代码里面要用什么样的方式来读取这个温度,并显示出来。

(1)socket编程,建立客户端与服务端的通信。对socket网络编程不熟悉的同学可以看《APUE学习之socket网络编程》。

(2)由于每个DS18B20的产品序列号不一样,那么温度保存文件的路径也就会不一样,我们没办法直接调用read来读取文件的内容。那该怎么办呢?用opendir()和readdir()的组合,打开每个设备都一样的默认路径(/sys/bus/w1/devices/),并读取路径下的内容。

(3)当打开上面的路径之后,因为型号的原因,大家的路径将有所不同,我们可以找出“28-”开头的的文件夹,并将其名称保存到一个缓存区中,然后用这个缓存区的内容来更新目标路径。

(4)用open()和read()读取目标路径的内容,找出其中“t=”的部分,并记录下来。随后上传至客户端。

三、实战操作

题目要求:

(1)利用网络socket编程,编写一个服务端和一个客户端,实现通信;

(2)使用树莓派DS18B20温度传感器每10秒采集一次温度,并上传至服务端。

代码如下:

1、服务端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <ctype.h>

#define BACKLOG          13     /*令listen最大监听数为13*/
#define PORT            8888    /*监听8888号端口*/

int main(int argc,char *argv[])
{
        int                     fd = -1;
        int                     client_fd = -1;
        int                     rv = -1;
        struct sockaddr_in      server_addr;
        struct sockaddr_in      client_addr;
        socklen_t               client_len = sizeof(client_addr);
        char                    buf[1024];

        if((fd=socket(AF_INET,SOCK_STREAM,0))<0)
        {
                printf("Socket failure:%s
",strerror(errno));
        }

        memset(&server_addr,0,sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(PORT);
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        if((bind(fd,(struct sockaddr *)&server_addr,sizeof(server_addr)))<0)
        {
                printf("bind failure:%s
",strerror(errno));
                return -2;
        }

        listen(fd,BACKLOG);
        printf("
Waitting for client...
");


        if((client_fd=accept(fd,(struct sockaddr *)&client_addr,&client_len))<0)
        {
                printf("Accept failure:%s
",strerror(errno));
                return -3;
        }
        printf("Connected with client [%d]
",client_fd);
        while(1)
        {

                memset(&buf,0,sizeof(buf));

                if((rv=read(client_fd,buf,sizeof(buf))) <= 0)
                {
                        printf("Read failure or get disconnect:%s
",strerror(errno));
                        return -4;
                }

                printf("read %d Byte data from client [%d] :%s
",rv,client_fd,buf);

                if(write(client_fd,buf,rv)<0)
                {
                        printf("Write failure:%s
",strerror(errno));
                        return -5;
                }

        }

        close(client_fd);
        close(fd);

}
                                         

2、客户端

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define PORT    8888            
#define IP      "127.0.0.1"

int get_temperature(float *temp);       /*该函数用于ds18b20采集温度*/

int main(int argc,char *argv[])
{

        int                     fd = -1;
        int                     rv = -1;
        struct sockaddr_in      servaddr;
        socklen_t               len = sizeof(servaddr);
        int                     r = -1;
        char                    t[16];
        float                   temp;
        char                    buf[128];

        fd = socket(AF_INET,SOCK_STREAM,0);
        if(fd < 0)
        {
                printf("create sockfd failure:%s
",strerror(errno));
                return -1;
        }
        printf("create socket_fd [%d] successfully!
",fd);

        memset(&servaddr,0,sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port   = htons(PORT);
        inet_aton(IP,&servaddr.sin_addr);



        if((rv = connect(fd,(struct sockaddr*)&servaddr,len)) < 0)
        {
                printf("client connect failure:%s
",strerror(errno));
                return -2;
        }
                printf("client connect successfully!
");
        while(1)
        {

                if((r = get_temperature(&temp)) < 0)
                {
                        printf("get temperature failure:%s
",strerror(errno));
                        return -7;
                }
                printf("get temperature successfully and temperature is %.2f!
",temp);

                memset(t,0,sizeof(t));
                sprintf(t,"%.2f",temp);

                if((write(fd,t,sizeof(t))) < 0)
                {
                        printf("write failure:%s
",strerror(errno));
                        return -8;
                }
                printf("write bytes:%s
",t);

                if((rv = read(fd,buf,sizeof(buf))) <= 0)
                {
                        printf("read failure or get disconnect:%s
",strerror(errno));
                        return -9;
                }
                printf("read [%d] bytes:%s
",rv,buf);

                sleep(10);
        }

        close(fd);
        return 0;

}

int get_temperature(float *temp)
{

        int             fd = -1;
        int             found = 0;
        char            w1_path[64] = "/sys/bus/w1/devices/";
        DIR             *dirp = NULL;
        struct dirent   *direntp = NULL;
        char            chip_sn[32];
        char            buf[128];
        char            *ptr;

        if( !(dirp = opendir(w1_path)) )
        {
                printf("open directory failure:%s
",strerror(errno));
                return -3;
        }

        while( direntp = readdir(dirp) )
        {

                if( strstr(direntp->d_name,"28-") )
                {
                        strncpy(chip_sn,direntp->d_name,sizeof(chip_sn));
                        found = 1;      /*found用于确保是否能找到温度存储的文件*/
                }
        }
        if( !found )
        {
                printf("can not find ds18b20 directory!
");
                return -4;
        }

        strncat(w1_path,chip_sn,sizeof(w1_path)-strlen(w1_path));               /*更新文件路径*/
        strncat(w1_path,"/w1_slave",sizeof(w1_path)-strlen(w1_path));

        closedir(dirp);


        fd = open(w1_path,O_RDONLY);    /*打开文件*/
        if(fd < 0)
        {
                printf("open file failure:%s
",strerror(errno));
                return -5;
        }


        lseek(fd,0,SEEK_SET);           /*不设置文件偏移量可能造成读不到任何内容*/
        memset(buf,0,sizeof(buf));
        read(fd,buf,sizeof(buf));

        ptr = strstr(buf,"t="); /*找到t=字符串*/
        if(NULL == ptr)
        {
                printf("can not find t= string
",strerror(errno));
                return -6;
        }

        ptr += 2;       /*将指针ptr移至t=后的温度值处*/
        *temp = atof(ptr)/1000;         /*进行温度转换和相应计算*/

        close(fd);

        return 0;

}

3、运行结果

服务端:

客户端:

         到这里,这道问题就已经成功解决了!加油,相信你自己,你一定是最棒的!