commit | author | age
|
14da47
|
1 |
/********************************************************************************* |
G |
2 |
* Copyright: (C) 2023 LingYun IoT System Studio |
|
3 |
* All rights reserved. |
|
4 |
* |
|
5 |
* Filename: ds18b20.c |
|
6 |
* Description: This file is temperature sensor DS18B20 source code |
|
7 |
* |
|
8 |
* Version: 1.0.0(2023/8/10) |
|
9 |
* Author: Guo Wenxue <guowenxue@gmail.com> |
|
10 |
* ChangeLog: 1, Release initial version on "2023/8/10 12:13:26" |
|
11 |
* |
|
12 |
* Pin connection: |
|
13 |
* |
|
14 |
* DS18B20 Module IGKBoard |
|
15 |
* VCC <-----> 3.3V |
|
16 |
* DQ <-----> #Pin7(GPIO1_IO18) |
|
17 |
* GND <-----> GND |
|
18 |
* |
|
19 |
* /run/media/mmcblk1p1/config.txt: |
|
20 |
* |
|
21 |
* # Eanble 1-Wire overlay |
|
22 |
* dtoverlay_w1=yes |
|
23 |
* |
|
24 |
********************************************************************************/ |
|
25 |
|
|
26 |
#include <stdio.h> |
|
27 |
#include <stdlib.h> |
|
28 |
#include <unistd.h> |
|
29 |
#include <fcntl.h> |
|
30 |
#include <dirent.h> |
|
31 |
#include <string.h> |
|
32 |
#include <time.h> |
|
33 |
#include <errno.h> |
|
34 |
|
|
35 |
int ds18b20_get_temperature(float *temp); |
|
36 |
|
|
37 |
int main(int argc, char *argv[]) |
|
38 |
{ |
|
39 |
float temp; /* 温度值有小数位,所以使用浮点数 */ |
|
40 |
|
|
41 |
if( ds18b20_get_temperature(&temp) < 0 ) |
|
42 |
{ |
|
43 |
printf("ERROR: ds18b20 get temprature failure\n"); |
|
44 |
return 1; |
|
45 |
} |
|
46 |
|
|
47 |
/* 打印DS18B20的采样温度值,因为℃是非ASCII打印字符,所以这里用 'C 代替 */ |
|
48 |
printf("DS18B20 get temperature: %f 'C\n", temp); |
|
49 |
|
|
50 |
return 0; |
|
51 |
} |
|
52 |
|
|
53 |
/* |
|
54 |
* 函数说明: 该函数用来使用 DS18B20 温度传感器采样获取当前的温度值; |
|
55 |
* 参数说明: $temp: 通过指针返回DS18B20的采样温度 |
|
56 |
* 返回说明: ==0 表示成功, <0 表示失败 |
|
57 |
*/ |
|
58 |
int ds18b20_get_temperature(float *temp) |
|
59 |
{ |
|
60 |
const char *w1_path = "/sys/bus/w1/devices/"; |
1e563e
|
61 |
char ds_path[50]; |
G |
62 |
char chip[20]; |
|
63 |
char buf[128]; |
|
64 |
DIR *dirp; |
|
65 |
struct dirent *direntp; |
|
66 |
int fd =-1; |
|
67 |
char *ptr; |
|
68 |
int found = 0; |
|
69 |
int rv = 0; |
14da47
|
70 |
|
G |
71 |
|
|
72 |
/* 在C语言编程时,进入函数的第一件事应该进行函数参数的合法性检测,检查参数非法输入。 |
|
73 |
* 否则调用者"不小心"通过 $temp 传入一个空指针,下面的代码就有可能出现段错误。 |
|
74 |
*/ |
|
75 |
if( !temp ) |
|
76 |
{ |
|
77 |
return -1; |
|
78 |
} |
|
79 |
|
|
80 |
/* 打开 "/sys/bus/w1/devices/" 文件夹,如果打开失败则打印错误信息并退出。 */ |
|
81 |
if((dirp = opendir(w1_path)) == NULL) |
|
82 |
{ |
|
83 |
printf("opendir error: %s\n", strerror(errno)); |
|
84 |
return -2; |
|
85 |
} |
|
86 |
|
|
87 |
/* 1, 因为文件夹下可能有很多文件,所以这里使用while()循环读取/sys/bus/w1/devices/ |
|
88 |
* 文件夹下的所有目录项,其中 direntp->d_name 就是目录里的每个文件/文件夹的文件名。 |
|
89 |
* |
|
90 |
* 2, 接下来我们使用 strstr() 函数判断文件名中是否包含 "28-",如果找到则将完整的 |
|
91 |
* 文件名通过strcpy()函数保存到 chip 中;并设置 found 标志为1,跳出循环。 |
|
92 |
*/ |
|
93 |
while((direntp = readdir(dirp)) != NULL) |
|
94 |
{ |
|
95 |
if(strstr(direntp->d_name,"28-")) |
|
96 |
{ |
|
97 |
/* find and get the chipset SN filename */ |
|
98 |
strcpy(chip,direntp->d_name); |
|
99 |
found = 1; |
|
100 |
break; |
|
101 |
} |
|
102 |
} |
|
103 |
|
|
104 |
/* 文件夹打开用完后,要记得第一时间关闭 */ |
|
105 |
closedir(dirp); |
|
106 |
|
1e563e
|
107 |
/* found在定义时初始化为0,如果上面没有找到 "28-" 文件则其值依然为0,否则将被置为1 */ |
14da47
|
108 |
if( !found ) |
G |
109 |
{ |
|
110 |
printf("Can not find ds18b20 in %s\n", w1_path); |
|
111 |
return -3; |
|
112 |
} |
|
113 |
|
1e563e
|
114 |
/* 使用snprintf() 生成完整路径/sys/bus/w1/devices/28-xxxxx/w1_slave */ |
14da47
|
115 |
snprintf(ds_path, sizeof(ds_path), "%s/%s/w1_slave", w1_path, chip); |
G |
116 |
|
1e563e
|
117 |
/* 接下来打开 DS18B20 的采样文件 */ |
14da47
|
118 |
if( (fd=open(ds_path, O_RDONLY)) < 0 ) |
G |
119 |
{ |
|
120 |
printf("open %s error: %s\n", ds_path, strerror(errno)); |
|
121 |
return -4; |
|
122 |
} |
|
123 |
|
|
124 |
/* 读取文件中的内容将会触发 DS18B20温度传感器采样,这里读取文件内容保存到buf中 */ |
|
125 |
if(read(fd, buf, sizeof(buf)) < 0) |
|
126 |
{ |
|
127 |
printf("read %s error: %s\n", ds_path, strerror(errno)); |
|
128 |
|
1e563e
|
129 |
/* 1, 这里不能直接调用 return直接返回,否则的话前面open()打开的文件描述符就没有关闭。 |
14da47
|
130 |
* 这里设置 rv 为错误码-5,通过 goto 语句跳转到函数后面统一进行错误处理。 |
G |
131 |
* |
|
132 |
* 2, 在C语言编程时我们应该慎用goto语句进行"随意"的跳转,因为它会降低代码的可读性。但这里是 |
|
133 |
* goto语句的一个非常典型应用,我们经常会用它来对错误进行统一的处理。 |
|
134 |
*/ |
|
135 |
rv = -5; |
|
136 |
goto cleanup; |
|
137 |
} |
|
138 |
|
|
139 |
/* 采样温度值是在字符串"t="后面,这里我们从buf中找到"t="字符串的位置并保存到ptr指针中 */ |
|
140 |
ptr = strstr(buf, "t="); |
|
141 |
if( !ptr ) |
|
142 |
{ |
|
143 |
printf("ERROR: Can not get temperature\n"); |
|
144 |
rv = -6; |
|
145 |
goto cleanup; |
|
146 |
} |
|
147 |
|
|
148 |
/* 因为此时ptr是指向 "t="字符串的地址(即't'的地址),那跳过2个字节(t=)后面的就是采样温度值 */ |
|
149 |
ptr+=2; |
|
150 |
|
|
151 |
/* 接下来我们使用 atof() 函数将采样温度值字符串形式,转化成 float 类型。*/ |
|
152 |
*temp = atof(ptr)/1000; |
|
153 |
|
|
154 |
/* 1,在这里我们对函数返回进行集中处理,其中 cleanup 为 goto 语句的标号; |
|
155 |
* 2,在函数退出时,我们应该考虑清楚在前面的代码中做了哪些事,这些事是否需要进行反向操作。如 |
|
156 |
* 打开的文件或文件夹是否需要关闭,malloc()分配的内存是否需要free()等。 |
|
157 |
* 3, 在最开始我们定义rv并赋初值为0(表示成功)是有原因的,如果前面的代码任何一个地方出现错误, |
|
158 |
* 则会将rv的值修改为相应的错误码,否则rv的值将始终为0(即没有错误发生),这里将统一返回。 |
|
159 |
*/ |
|
160 |
cleanup: |
|
161 |
close(fd); |
|
162 |
return rv; |
|
163 |
} |