DS18B20温度传感器
DS18B20是常用的数字温度传感器, 其输出的是数字信号, 具有体积小, 硬件开销低, 抗干扰能力强, 单线数字温度传感器.
接下来我们将在树莓派上通过文件i/o调用来获取温度.
逻辑分析
通过寻找相关路径, 打开文件, 进行读操作. 将文件内容打印到屏幕上.
在我们的了解中, 实时温度数据在 /sys/bus/w1/devices/28-041731f7c0ff/w1_slave 这个文件中.
我们可以通过调用read()函数直接读取该文件的内容, 并找到我们所需的温度, 打印到屏幕.
每一个ds18b20的产品序列号都是不一样, 它保存温度的路径也所有变换.
不同的ds18b20温度传感器, 我们可以看到在存放温度的路径下, 仅仅是/28-xxxxx/ 这一个文件不同
通过opendir()与readdir(), 打开 /sys/bus/w1/devices/ 此路径的文件夹. 并读取文件夹中的内容.
找到 /28-xxxxx/ 文件, 存放到一个缓冲区, 通过函数strncat()将此文件加到固定路径中.
通过 open() 和 read() 将存放在文件的数据读出来.
使用 strstr() 找到我们需要的温度将其打印.
涉及函数
opendir()函数
// opendir() 返回值:成功则返回DIR* 型态的目录流, 打开失败则返回NULL.
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); //用来打开参数name 指定的目录, 并返回DIR*形态的目录流.
readdir()函数
//readdir() 返回参数dir 目录流的下个目录进入点。
#include <sys/types.h>
#include <dirent.h>
struct dirent * readdir(DIR * dir); //参数为opendir()返回的DIR结构体指针,获取到文件夹的相关信息
struct dirent
{
ino_t d_ino; //d_ino 此目录进入点的inode
ff_t d_off; //d_off 目录文件开头至此目录进入点的位移
signed short int d_reclen; //d_reclen _name 的长度, 不包含NULL 字符
unsigned char d_type; //d_type d_name 所指的文件类型
har d_name[256]; //d_name 文件名
};
closedir()函数
#include<sys/types.h>
#include <dirent.h>
closedir(DIR *dir); //关闭打开的目录流
open()函数
#include <sys/types.h> //open()头文件
#include <sys/stat.h> //open()头文件
#include <fcntl.h> //open()头文件
int open(const char *pathname, int flags);
/* 第一个参数是需要打开文件的路径,
第二个参数简单来说可以是打开文件的方式. */
read()函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
/* 第一个参数为已经成功打开文件的返回值fd
第二个参数为读取文件的缓冲区
第三个参数为读多大到缓冲区 */
close()函数
#include <unistd.h>
int close(int fd); //关闭已经打开的文件
strncpy函数
#include <string.h>
char * strncpy(char *dest, const char *src, size_t n);
/* dest -- 指向用于存储复制内容的目标数组
src -- 要复制的字符串
n -- 要从源中复制的字符数
特别注意: strncpy src 所指向的字符串复制到 dest, 最多复制 n 个字符.
当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充. */
strstr()函数
#include <stdio.h>
#include <string.h>
char *strstr(char *str1, char *str2);
/* 找出str2在str1中首次出现的位置(不包括str2的结束符).
若找到,返回的是该位置的指针. 否词返回NULL. */
strncat()函数
#include <string.h>
char *strncat(char *dest, const char *src, size_t n);
/* 将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去
dest:目的字符串首地址
src:源字符首地址
n:指定需要追加字符串个数
返回值: 成功,返回dest字符串的首地址. 失败返回NULL. */
atof()函数
#include <stdlib.h>
double atof (const char* str);
/* 将字符串转换为double
返回转换后的浮点数;如果字符串 str 不能被转换为 double,那么返回 0.0。 */
程序源码
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 1024
int main(int argc, char *argv[])
{
int fd = -1; //文件描述符
int rv = -1; //文件读取返回值
int flag; //读取到28-文件的标志
char buf[BUFSIZE]; //温度缓冲区
char *ptr = NULL; //温度缓冲区指针
char dirbuf[100]; //目标路径缓冲区
char path[100] = "/sys/bus/w1/devices/";
double tem; //温度
DIR *dir; //opendir的返回类型
struct dirent *rdirent; //readdir返回的结构体指针
if( (dir=opendir(path)) == NULL )
{
perror("Opendir file failed");
return -2;
}
while((rdirent = readdir(dir)) != NULL)
{
if(strstr(rdirent->d_name, "28-")) //寻找28-开头的文件
{
strncpy(dirbuf, rdirent->d_name, sizeof(dirbuf)); //将该文件拷贝到目标路径缓冲区
flag = 1;
}
}
if(flag != 1)
{
printf("Can not found the temperature file.\n");
return -3;
}
closedir(dir);
strncat(path, dirbuf, sizeof(path)); //把找到的28-开头的文件追加到默认路径.
strncat(path, "/w1_slave", sizeof(path)); //将/w1_slave/追加到路径中.
printf("%s\n", path); //打印最终路径
if( (fd=open(path, O_RDONLY)) < 0 )
{
perror("Open temperature file failed");
return -2;
}
lseek(fd, 0, SEEK_SET); //将文件偏移量移动到开头
if( (rv=read(fd, buf, sizeof(buf))) <0 )
{
perror("Read temperature data failed");
return -3;
}
if( (ptr=strstr(buf, "t=")) != NULL) //寻找温度所在行, 且返回t所在位置.
{
ptr = ptr+2; //将地址偏移俩个字节, 得到温度.
tem = atof(ptr); //将字符串转换为double类型.
tem = tem/1000;
printf("Now the room temperature:%3.2f\n", tem);
}
else
{
perror("Can not read temperture");
return -4;
}
close(fd);
return 0;
}