1 DS18B20简介
(1) ds18b20介绍
DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点,是通过一线协议来配置的传感器,刚好拿实验室的树莓派来做一下获取温度的小项目。
(2) DS18B20连接树莓派
配置内核启动后自动加载一线协议驱动
-
连接引脚
-
输入命令进行配置
pi@raspberrypi:~ $ sudo raspi-config //打开配置选项
按Enter选中
继续按Enter选中
- 打开内核文件
pi@raspberrypi:~ $ vim /boot/config.txt
在最后添加连接的引脚,我们连接了22(BCM编码)
dtoverlay=w1-gpio-pullup,gpiopin=22
- 重启树莓派
pi@raspberrypi:~ $ sudo reboot
- 重启系统后,确认系统有自动加载一线协议的驱动模块
pi@raspberrypi:~/ds18b20 $ lsmod | grep w1
当树莓派配置好DS18B20数字温度传感器后,该温度信息通常保存在下面路径中,我们只需要读取文件中的温度即可:
/sys/bus/w1/devices/28-XXXXXXXX/w1_slave
查看路径文件下温度数据:
(3) 流程简述
1 调用opendir()和readdir()来打开读取文件路径(默认文件路径“/sys/bus/w1/devices/”)
在这里我们注意到为什么不是全部路径 (/sys/bus/w1/devices/28-XXXXXXXX/w1_slave) 而是只截取到 (/sys/bus/w1/devices/),这是因为“28-XXXXX”是产品序列号,如果我们换了一个DS18B20进行获取温度,产品序列号XXXXX改变,那此路径就不能用了,而这一产品序列号XXXXX目录无论变成什么永远在(/sys/bus/w1/devices/)路径下,所以我们只打开读取路径到这里
2 寻找“28-”开头的文件,将其存入缓冲区
接下来在(默认文件路径“/sys/bus/w1/devices/”)下通过strstr()函数找到“28-”打头的文件,并且存入缓冲区,方便更改
3 调用closedir()关闭文件**
4 通过strncat链接文件路径
调用strncat将(默认文件路径“/sys/bus/w1/devices/”)和存入缓冲区的(“28-XXXXX”)连接起来,然后再调用strncat()将“/w1_slave”路径连接起来,此时需要读取数据的路径就完整了,进行实时获取产品序列号的文件目录,以便实时读取温度
5 调用open()和read()来打开文件,读取文件,找到温度(t=)打头的数据
利用strstr()再匹配(“t=”)打头的数据
6 调用close()关闭文件
7 将数据进行处理然后打印即可
将获得的字符类型数据转换成单精度类型数据,只打印数据,不打印“t=”
2 项目代码介绍
(1)文件I/O的API函数
open()
int open(const char *path, int oflag, ... /*mode_t mode*/);
open()系统调用用来打开一个文件,并且返回一个文件描述符(fd),并且该文件描述符是当前进程最小,并未使用的文件描述符数值,即3,因为0是标准输入,1是标准输出,2是标准出错。
参数: path: 要打开的文件、设备的路径
oflag: 由多个选项进行“或”运算构造oflag参数 。
必选: O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写)
可选: O_APPEND 每次写时都追加到文件的尾端。
O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode
O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此 选项为文件的本次打开和后续的I/O操作
设置非阻塞模式方式:
O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY…
mode: oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如066。 否则不需要。
使用示例代码:
int fd;
fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
fd = open(“text.txt”, O_WRONLY|O_APPEND);
read()
ssize_t read(int fd, void*buf, size_t nbytes);
read()函数是用来打开文件描述符对应的文件中读取数据放到buf指向的内存空间中去,最多不要超过nbytes个字节,这里的nbytes一般指的是buf剩余空间的大小。如果read成功,则返回实际读到的字节数(由nbtyes或读懂到文件尾决定,其中EOF宏用来判断是否到了文件尾),如果返回值小于0则表示出错,如哦尝试读取一个没有权限读取的文件时就会抛错。
close()
int close(int fd);
该函数用来关闭一个打开的文件描述符,关闭一个文件时还会释放该进程加载该文件上的所有记录锁。当一个进程终止时,内核将会自动关闭它所打开的文件。
opendir()
DIR *opendir(const char *pathname)
opendir()是用来打开指定的目录文件,并返回DIR *形态的目录流,和open()类似,接下来对目录的搜索和读取都要使用此返回值,该返回值是指向DIR结构体的指针,失败返回 NULL。
readdir()
struct dirent *readdir(DIR *dirp)
readdir()函数的参数是opendir()返回的DIR *结构体指针也就是dirp,通过这个结构体,我们可以读取文件夹的相关信息(文件名,长度等),并返回一个direntp的指针,该结构体就用来存放这些信息,失败时返回NULL
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符*/
}
closedir()
关闭目录路流
(2)项目代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
char path[100] = "/sys/bus/w1/devices/"; //局部变量存储大概路径
char buf1[1024];
char buf2[100];
char *ptr = NULL;
int fd = -1;
int rv = -1;
int flag = 0;
float temp;
DIR *dirp;
struct dirent *direntp;
if((dirp = opendir(path)) == NULL)
{
printf("Opendir %s error: %s\n",path,strerror(errno));
return -1;
}
while((direntp = readdir(dirp)) != NULL)
{
if(strstr(direntp->d_name, "28-"))
{
strncpy(buf2, direntp->d_name, sizeof(buf2));
flag = 1;
}
}
closedir(dirp);
if(!flag)
{
printf("Can not find 28- in the path\n");
return -2;
}
strncat(path, buf2, sizeof(path)-strlen(path));
strncat(path, "/w1_slave",sizeof(path)-strlen(path));
if((fd = open(path,O_RDONLY)) < 0)
{
printf("Open %s failure: %s\n",path,strerror(errno));
return -3;
}
if((rv = read(fd,buf1,sizeof(buf1))) < 0)
{
printf("Read %s failure;%s\n",path,strerror(errno));
return -4;
}
close(fd);
if((ptr = strstr(buf1,"t=")) != NULL)
{
temp = atof(ptr+2)/1000;
printf("The current temperature: %.2f℃\n",temp);
}
else
{
printf("Can not get the current temperture\n");
return -5;
}
return 0;
}
· 运行结果
获取到了我们想要的温度!!!