现在是物联网, 大数据的时代, 多么多么火笔者就不再累赘,
而智能家居是物联网中重要的一部分, 这里跟大家分享一个用树莓派探测室内温度的简单应用。
原理很简单, 其实温度传感器已经将温度值测好, 存在相应的文件中,而我们需要干的就是写一段执行代码自动地找到相应的文件夹,然后在相应的文件中读出对我们有用的数据然后稍加处理, 最后打印给我们看。
这样我们就不用人为的去获取温度值。
这样获取到的温度值还并不是以摄氏度为单位的数值,所以我们还需要在代码中处理。
关于硬件的知识这里不讲,主要讲软件的实现,
从原理中我们可以看出此项目用到的知识就是我们C语言中学的文件I/O,还有字符串处理。
下面我们简单回顾一下文件I/O 和字符串处理的API函数。
int open(const char *path, int oflag, *mode*);
返回值 int fd 文件描述符(file description), open系统调用返回的文件描述符一定是最小的、未使用的文件描述符数值。即3,因为0标准输入,1标准输出,2标准出错系统默认会打开。
参数:
1.*path: 要打开的文件、设备的路径名
2.**oflag: ** 由多个选项进行 或 运算构造oflag参数
必选:O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写)
可选:O_APPEND 每次写时都追加到文件的尾端。
O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode
O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作设置非阻塞模式方式。
O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY…
3.mode: oflag带O_CREAT选项时,必须带该参数用来指定打开文件的权限模式,如066。
ssize_t read(fd,buf,sizeof(buf));
如果返回fd小于0说明读文件错误,可以用streror(errno)获取错位原因
如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。
read之前必须清空buff
menset(buf,0,sizeof(buff);
int close(int fd);
该函数用来关闭一个打开的文件,关闭一个文件时还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有打开的文件。
DIR *opendir(const char *pathname); //参数是路径名称
struct dirent * readdir(DIR *dirp);
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
int closedir(DIR *dirp);
extern char *strstr(char *str1, const char *str2);
str1: 被查找目标 string expression to search.
str2: 要查找对象 The string expression to find.
返回值:若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
char *strncpy(char *dest, const char *src, size_t n)
dest – 指向用于存储复制内容的目标数组。
src – 要复制的字符串。
n – 要从源中复制的字符数。
extern char *strncat(char *dest,char *src,int n)
参数说明:src为源字符串,dest为目的字符串,n为指定的src中的前n个字符。
所在库名:#include
函数功能:把src所指字符串的前n个字符添加到dest结尾处,覆盖dest结尾处的’/0’,实现字符串连接。
返回说明:返回指针,连接后的字符串。
extern int strlen(char *s);
功能:计算字符串s的长度
说明:返回s的长度,不包括结束符NULL。
这个代码只是简单的文件打开,文件读取的代码,较为死板,在工作中往往芯片的产品序列号会改变,所以一旦变了,你就需要重新修改代码,通用性较差,但是代码书写相对比较简单。
int main(int argc, char *argv[])
{
fd = open("获取温度文件的路径", O_RDONLY); //打开文件
read(fd, buf, sizeof(buf)); //从文件中读取全部字符串
strstr(buf, "t="); //找到温度数值的字符串
temp = atof(ptr)/1000; //将字符串转换成日常单位数值
printf("temperature is %f\n", temp); //打印温度值
close(fd); //关闭文件描述符
return 0;
}
因为需要读取不同芯片的温度,所以这段的代码需要在上面代码的基础上添加对文件夹的操作
int main(int argc, char *argv[])
{
rv = get_temperature(&temp); //获取温度的函数
printf(" temperature: %f\n", temp); //打印温度值
return 0;
}
//下面是获取温度函数的伪代码
int get_temperature(float *temp)
{
dirp = opendir( w1_path ); //打开ds18b20上一层的文件夹
direntp = readdir(dirp); //读取文件夹下的所有文件夹
strstr(direntp->d_name, "28-") ; //在所有文件中找出ds开头的芯片的文件
strncpy( chip_sn, direntp->d_name, sizeof(chip_sn)); //将读出的文件夹拷贝到这段buf中
closedir(dirp); //关闭文件夹
//下面两条起拼接的作用
strncat(w1_path, chip_sn, sizeof(w1_path)-strlen(w1_path)); //将ds18b20接到w1_path后
strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path)); //将w1_path接到新的w1_path后
ptr = strstr(buf, "t="); //在文件中获取温度值
*temp = atof(ptr)/1000; //处理温度值
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int fd = -1;
char *ptr = NULL;
float temp = 0;
char buf[128];
fd = open("/sys/bus/w1/devices/28-041731f7c0ff/w1_slave", O_RDONLY);
if( fd < 0 )
{
printf("open failure %s\n", strerror(errno));
return -1;
}
printf("open success\n");
memset(buf, 0, sizeof(buf));
if( read(fd, buf, sizeof(buf)) < 0 )
{
printf("read failure fd %d: %s\n", fd, strerror(errno));
return -2;
}
printf("buf: %s\n", buf);
ptr = strstr(buf, "t=");
if( !ptr )
{
printf("can not find t= string %s\n", strerror(errno));
return -3;
}
ptr += 2;
printf("ptr : %s\n", ptr);
temp = atof(ptr)/1000;
printf("temperature is %f\n", temp);
close(fd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int get_temperature(float *temp); //函数声明
//主函数
int main(int argc, char *argv[])
{
float temp;
int rv ;
rv = get_temperature(&temp);
if( rv < 0 )
{
printf("ERROR: get temperature failure %d\n", rv);
return -1;
}
printf(" temperature: %f\n", temp);
return 0;
}
//获取温度函数定义
int get_temperature(float *temp)
{
char w1_path[64] = "/sys/bus/w1/devices/";
char chip_sn[20];
char buf[128];
DIR *dirp = NULL;
struct dirent *direntp = NULL;
int fd = -1;
char *ptr = NULL;
int found = 0;
dirp = opendir( w1_path );
if( !dirp )
{
printf("opendir error %s\n", strerror(errno));
return -1;
}
while ( (direntp = readdir(dirp)) != NULL)
{
if( strstr(direntp->d_name, "28-") )
{
strncpy( chip_sn, direntp->d_name, sizeof(chip_sn));
found = 1;
}
}
closedir(dirp);
if( !found )
{
printf("can not find ds18b20 in %s\n", w1_path);
return -2;
}
strncat(w1_path, chip_sn, sizeof(w1_path)-strlen(w1_path));
strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));
if( (fd = open(w1_path, O_RDONLY)) < 0 )
{
printf("open %s error : %s\n", w1_path, strerror(errno));
return -3;
}
if( read(fd, buf, sizeof(buf)) < 0 )
{
printf("read %s error : %s\n",w1_path, strerror(errno));
return -4;
}
ptr = strstr(buf, "t=");
if( !ptr )
{
printf("error: can not get string \n");
return -5;
}
ptr += 2;
*temp = atof(ptr)/1000;
close(fd);
return 0;
}