文件IO操作—树莓派获取温度ds18b20
- 问题描述:通过树莓派获取室内温度
- 思路:首先登陆到树莓派上,使用cat命令查看 /sys/bus/w1/devices/28-041731f7c0ff/w1_slave 文件可以得到当前温度(不同树莓派的28-后的值不一样,要根据自己的实际情况查看),得到当前的温度为11.5℃。
其实,通过树莓派获取温度也就是对文件w1_slave的读取操作。但是由于不同设备的名称不一样,为使代码具有可移植性,在打开文件w1_slave之前先找到28-041731f7c0ff(041731f7c0ff这串字符由设备生产厂家决定,每个设备不同,但是/sys/bus/w1/devices/都是不变的)。先对/sys/bus/w1/devices/使用文件夹操作,打开该文件夹,查看文件夹当中的文件,使用字符串查找函数strstr找到以"28-"开头的文件。找到该文件后,将文件名加到 /sys/bus/w1/devices/之后,再加上/w1_slave就得到了完整的路径。
接下来就是通过这个获取到的路径打开文件,对文件进行读取操作。从文件中读取到的数据都是字符,然后使用字符串查找函数strstr找到以"t="开头的字符得到温度,但是此时获取到的温度依然是字符串,要想获得想要的温度,需要将字符转换为数值,使用atof()将字符转换为浮点数,再将得到的结果除以1000就得到了温度。
cat /sys/bus/w1/devices/28-041731f7c0ff/w1_slave
b8 00 4b 46 7f ff 0c 10 8c : crc=8c YES
b8 00 4b 46 7f ff 0c 10 8c t=11500
- 代码展示
/*************************
2 *文件名称:ds18b20.c
3 *作 者: xxx
4 *摘 要:树莓派获取温度
5 *完成日期:2021年1月29日
6 *************************/
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <dirent.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #define BUFSIZE 1024
16
17 int main(int argc, char *argv[])
18 {
19 char path[64] = "/sys/bus/w1/devices/";
20 char path_28[32];
21 char buf[BUFSIZE];
22 char *ptr;
23 int fd = -1;
24 int rv = -1;
25 int found = -1;
26 DIR *dirp;
27 struct dirent *direntp;
28 float temp;
29
30 if ((dirp = opendir(path)) == NULL)
31 {
32 printf("opendir failure: %s\n", strerror(errno));
33 }
34
35 while ((direntp = readdir(dirp)) != NULL)
36 {
37 if (strstr(direntp->d_name,"28-"))
38 {
39 strcpy(path_28, direntp->d_name);
40 found=1;
41 }
42 }
43 closedir(dirp);
44
45 if (found != 1)
46 {
47 printf("Can not found ds18b20 in %s\n", path);
48 return -1;
49 }
50 strncat(path, path_28, sizeof(path));
52 strncat(path, "/w1_slave", sizeof(path));
53
54 if ((fd = open(path, O_RDONLY)) < 0)
55 {
56 printf("Open file %s failure:%s\n", path, strerror(errno));
57 goto cleanup;
58 }
59
60 if ((rv = read(fd, buf, sizeof(buf))) < 0)
61 {
62 printf("Read data from %s failure: %s\n", strerror(errno));
63 goto cleanup;
64 }
65
66 ptr = strstr(buf, "t=") + 2;
67
68 if (!ptr)
69 {
70 printf("Get temperature failure!\n");
71 goto cleanup;
72 }
73
74 temp=atof(ptr)/1000;
75 printf("ds18b20 get temperature: %.4f ℃\n",temp);
76 cleanup:
77 close(fd);
78
79 return 0;
80 }
运行结果
kaoyan@Public_RPi:~/xiongyuanyuan $ gcc ds18b20.c
kaoyan@Public_RPi:~/xiongyuanyuan $ gcc ds18b20.c -o ds18b20
kaoyan@Public_RPi:~/xiongyuanyuan $ ./ds18b20
ds18b20 get temperature: 11.5000 ℃
- 代码详解:
19-28行:变量定义。将文件路径定义在一个字符数组path中,定义一个字符数组path_28用于存放查找到的"28-xxxxx",定义字符数组buf用作缓冲区存放从文件中读取到的数据,定义字符指针ptr存放"t=xxxxx"的首地址;fd表示该文件的文件描述符,rv表示对文件进行读操作后的结果返回值,found标志是否找到在文件夹中找到"28-xxxx"这个文件,dirp存放打开文件夹的返回值,direntp存放读文件夹的返回值;temp存放温度的值。
30-33行:判断打开文件夹是否成功。当返回值为空时,表示打开文件夹失败,错误原因的代号会存到 errno中,使用strerror可以将错误代号转换为字符串
35-42行:循环读取文件夹中的文件,直到读完为止。判断读到的文件是否以"28-“开头,如果是就将该名称存到path_28数组中,并将found的值置为1表示找到了。
43行:对文件夹的操作完毕,关闭该文件夹。
45-49行:通过判断found的值来知晓是否找到"28-”,found不为1表示未找到,输出提示信息并结束函数。
50行:使用strncat函数将找到的"28-xxx"加到path数组中
52行:使用strncat函数将/w1_slave加到path数组中
54-58行:以只读方式打开文件,如果fd<0表示打开失败,输出错误提示并跳转到cleanup处
60-64行:读取文件数据,当rv<0表示读文件失败,输出错误提示并跳到cleanup处,读取到的数据存在缓冲区buf数组中
66行:在buf数组中找到"t="地址,将其加2获得温度字符首地址
68-72行:当ptr为假时,表示未获取到温度,输出提示信息
74行:得到的温度是一个字符串,要对其进行数值操作需要先将它转换成数值(浮点型),再将得到的数值结果除以1000就是温度了
75行:输出温度,输出的结果显示4位小数
77行: 关闭文件
注意:在关闭文件和文件夹时,函数中的参数不是文件名,而是它们对应的文件描述符