目录
-
树莓派
Raspberry Pi(中文名为“树莓派”,简写为RPi,(或者RasPi / RPI) [1] 是为学习计算机编程教育而设计),只有信用卡大小的微型电脑,其系统基于Linux。 随着Windows 10 IoT的发布,我们也将可以用上运行Windows的树莓派。 自问世以来,受众多计算机发烧友和创客的追捧,曾经一“派”难求。别看其外表“娇小”,内“心”却很强大,视频、音频等功能通通皆有,可谓是“麻雀虽小,五脏俱全”。
-
DS18B20
DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。 [1] DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。
主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
-
项目实现的简单介绍
-
由于DS18B20是遵循单线协议(oneline), 1-wire 单总线是Maxim 全资子公司 Dallas 的一项专有技术。与目前多数标准串行数据通信方式,如SPI/I2C/MICROWIRE 不同,它采用单根信号线,既传输时钟,又传输数据,而且数据传输是双向的。它具有节省 I/O 口线资源、结构简单、成本低廉、便于总线扩展和维护等诸多优点。1-wire 单总线适用于单个主机系统,能够控制一个或多个从机设备。当只有一个从机位于总线上时,系统可按照单节点系统操作;而当多个从机位于总线上时,则系统按照多节点系统操作。
-
为什么我们要用文件I/O来实现温度获取呢???
因为DS18B0会把他获取到的温度数据存放在一个文件中,而且DS18B20会有一个专门的产品序列号,类似于我们的身份证号,所以我们会用strstr函数来查找这个唯一的序列号,也就找到唯一的文件例如:strstr(direntp->d_name,"28-")。
废话不多说,先撸代码
-
代码示例
#ifndef __DS18B20_H__
#define __DS18B20_H__
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <stdlib.h>
#define BUF_SIZE 1024
#define CHIP_SIZE 100
#define DIR_PATH_SIZE 100
#endif
int ds18b20_get_temperature(float *tmp);//基于DS18B20温度获取实现函数
int main (int argc, char **argv)
{
float value;
if((ds18b20_get_temperature(&value))<0)
{
printf("Get temperature failure: %s\n",strerror(errno));
}
printf("T = %.2f\n",value);
return 0;
}
int ds18b20_get_temperature(float *tmp)
{
if(tmp == NULL)
{
printf("Failure : %s",strerror(errno));
return 0;
}
int fd = -1;
int rv = 0;
char buf[BUF_SIZE];
char chip[CHIP_SIZE];
char DIR_PATH[DIR_PATH_SIZE] ="/sys/bus/w1/devices/"; //DS18B20的温度实时存储文件
char *ptr = NULL;
int find = 0;
DIR *dirp = NULL;
struct dirent *direntp = NULL;
if((dirp = opendir(DIR_PATH))==NULL)
{
printf("Open %s failure %s\n\a",DIR_PATH,strerror(errno));
return -1;
}
while((direntp= readdir(dirp))!=NULL)
{
if(strstr(direntp->d_name,"28-")) //查找字串
{
memset(chip,0,sizeof(chip));
strncpy(chip,direntp->d_name,sizeof(chip));
find = 1;
break;
}
}
if(!find)
{
puts("No such devices\a");
goto cleanup;
return -2;
}
closedir(dirp);
strncat(DIR_PATH,chip,sizeof(DIR_PATH));
strncat(DIR_PATH,"/w1_slave",sizeof(DIR_PATH));
if((fd = open(DIR_PATH,O_RDONLY))<0)
{
printf("open %s failure %s\a\n",DIR_PATH,strerror(errno));
goto cleanup;
return -3;
}
memset(buf,0,sizeof(buf));
lseek(fd,0,SEEK_SET);
if((rv = read(fd,buf,sizeof(buf)))<0)
{
printf("Read %s failure %s\n\a",DIR_PATH,strerror(errno));
goto cleanup;
return -4;
}
ptr = strstr(buf,"t=")+2;
if(!ptr)
{
puts("Gte value failure\a\n");
return -5;
}
*tmp = atof(ptr)/1000; //字符串转化位float的数据
cleanup:
close(fd);
}
-
基本API介绍及其详解
- oepndir( )
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); //打开指定的文件目录
- readdir( )
#include <dirent.h> struct dirent *readdir(DIR *dirp); //read open 函数打开的目录文件
- strstr( )
#include <string.h> char *strstr(const char *haystack, const char *needle); 在haystack从查找needle的子串
- strcpy()
#include <string.h> void *memset(void *s, int c, size_t n); //将s的这段内存初始化位c值,我们一般把c值设为,最后n位这段内存的大小
-
strncpy/strcpy
#include <string.h> char *strcpy(char *dest, const char *src); //这个函数一般不安全,容易导致内存溢出 char *strncpy(char *dest, const char *src, size_t n); //这个函数有最后的字节数限制,不会导致内存溢出,
- closedir
#include <sys/types.h> #include <dirent.h> int closedir(DIR *dirp); //关闭打开的文件句柄
-
strncat
#include <string.h> char *strcat(char *dest, const char *src); //同样这个函数也不安全,存在内存溢出的问题 char *strncat(char *dest, const char *src, size_t n);//将dest连接在src之后,n的大小回限制内存溢出的问题
-
atof
#include <stdlib.h> double atof(const char *nptr); //将字符串转化为float
-
至于一些其他的进本系统调用函数大家可以看看我的这篇文章(https://blog.csdn.net/qq_44045338/article/details/104587274),我就不一一例举了。
-
运行结果