智能家居之树莓派探测温度(基于文件I/O的简单应用)

1, 关于项目的简单介绍

现在是物联网, 大数据的时代, 多么多么火笔者就不再累赘,
智能家居是物联网中重要的一部分, 这里跟大家分享一个用树莓派探测室内温度的简单应用。
原理很简单, 其实温度传感器已经将温度值测好, 存在相应的文件中,而我们需要干的就是写一段执行代码自动地找到相应的文件夹,然后在相应的文件中读出对我们有用的数据然后稍加处理, 最后打印给我们看。
这样我们就不用人为的去获取温度值。

  • 下面我们用命令的方式获取温度(就是手动获取)

在这里插入图片描述

这样获取到的温度值还并不是以摄氏度为单位的数值,所以我们还需要在代码中处理。
在这里插入图片描述


2, 背景知识的简单回顾

关于硬件的知识这里不讲,主要讲软件的实现,
从原理中我们可以看出此项目用到的知识就是我们C语言中学的文件I/O,还有字符串处理。
下面我们简单回顾一下文件I/O字符串处理的API函数。

2.1, 文件 I/O 的API函数

open()

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。

  • 例: int fd;
  • fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
  • fd = open(“text.txt”, O_WRONLY|O_APPEND);
    其中fd就代表文件text.text

read()

ssize_t   read(fd,buf,sizeof(buf));

如果返回fd小于0说明读文件错误,可以用streror(errno)获取错位原因
如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。

read之前必须清空buff
menset(buf,0,sizeof(buff);

close()

int  close(int   fd);

该函数用来关闭一个打开的文件,关闭一个文件时还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有打开的文件。

opendir()

DIR *opendir(const char  *pathname);  //参数是路径名称
  • 失败返回NULL

readdir()

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 */
           };

closedir()

int  closedir(DIR *dirp);

2.2, 字符串的API函数

strstr()

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。

strncpy()

char *strncpy(char *dest, const char *src, size_t n)

dest – 指向用于存储复制内容的目标数组。
src – 要复制的字符串。
n – 要从源中复制的字符数。

strncat()

extern char *strncat(char *dest,char *src,int n)

参数说明:src为源字符串,dest为目的字符串,n为指定的src中的前n个字符。
所在库名:#include <string.h>
函数功能:把src所指字符串的前n个字符添加到dest结尾处,覆盖dest结尾处的’/0’,实现字符串连接。
返回说明:返回指针,连接后的字符串。

strlen()

extern int strlen(char *s);

功能:计算字符串s的长度
说明:返回s的长度,不包括结束符NULL。

2.3, 其他函数

snprintf()


3, 伪代码

3.1 固定芯片的伪代码(简易版)

这个代码只是简单的文件打开,文件读取的代码,较为死板,在工作中往往芯片的产品序列号会改变,所以一旦变了,你就需要重新修改代码,通用性较差,但是代码书写相对比较简单。


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;
}

3.2 可变芯片的伪代码(升级版)

在这里插入图片描述

因为需要读取不同芯片的温度,所以这段的代码需要在上面代码的基础上添加对文件夹的操作


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;
}

4, 具体代码实现

4.1 固定芯片的代码(较简单,通用性差)


#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>

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;
}

4.2 可变芯片的代码(较复杂,通用性好)


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>

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;

}


发布了11 篇原创文章 · 获赞 22 · 访问量 2211

猜你喜欢

转载自blog.csdn.net/weixin_46027505/article/details/104657410