又是我们一线协议(1-Wire)温度采样的老朋友DS18B20传感器,之前在单片机和树莓派当中我们都有用到,这次我们通过IGKBoard来进行温度采样。
一、 DS18b20传感器介绍
DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。
主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
二、DS18B20硬件连接
1.DS18B20引脚
DS18B20主要连接时三个引脚:
- GND:接地引脚需要连接到GND扩展引脚上。
- DQ:DQ为DS18B20的数据通信引脚,需要连接在具有一线协议的GPIO引脚上。
- VDD:因为DS18B20传感器的工作电压为3~5.5V,所以改引脚连到3.3V或5V供电引脚上。
2.连接开发板
在IGKBoard开发板上的引脚中,物理引脚 #7 (GPIO1_IO18) 在Linux系统启动时如果启用了 w1 overlay 后,它将会默认作为 DS18B20 传感器的一线协议接口使用。
所以可以如下这样连接:
注意:忽略掉我的那根红色杜邦线
三、驱动配置
首先,因为我们的DQ引脚连接在了IGKBoard开发板扩展接口的#7引脚上,而我们所需用着个引脚来做DS18B20的一线协议支持,所以我们需要修改对应的config配置文件:
cd /run/media/mmcblk1p1
vi config.txt
注意:如果没有config.txt文件则自己新建
添加如下:
# Enable extra overlays
dtoverlay_extra=w1
如果已有则dtoverlay_extra直接在后面添加,用空格隔开。
重启后可用如下命令来查看驱动是否已经成功加载:
dmesg | grep 1-wire
四、源代码与运行测试
首先我们需要知道如何去获取我们的温度值,在我们的/sys/bus/w1/devices/下可以找到我们的DS18B20温度传感器相关文件如下:
root@igkboard:~# cd /sys/bus/w1/devices/
root@igkboard:/sys/bus/w1/devices# ls
28-082250269950 w1_bus_master1
082250269950为DS18B20芯片的产品序列号,温度就在/sys/bus/w1/devices/28-082250269950/w1_slave中,所以我们写一个程序ds18b20.c来获取温度。
源代码:ds18b20.c
/*********************************************************************************
* Copyright: (C) 2023 Deng Yonghao<dengyonghao2001@163.com>
* All rights reserved.
*
* Filename: ds18b20.c
* Description: This file IGKBoard use DS18B20 to get temperature.
*
* Version: 1.0.0(2023年03月13日)
* Author: Deng Yonghao <dengyonghao2001@163.com>
* ChangeLog: 1, Release initial version on "2023年03月13日 21时48分32秒"
*
********************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int ds18b20_get_temperature(float *temp);
int main(int argc, char **argv)
{
float temp;//温度值有小数位用浮点型
int rv;
rv = ds18b20_get_temperature(&temp);
if(rv<0)
{
printf("ERROR: de18b20 get temperature failure, return value: %d", rv);
return -1;
}
/*由于℃是非ASCII打印字符,所以用'C代替*/
printf("ds18b20 get temperature: %f 'C\n", temp);
return 0;
}
int ds18b20_get_temperature(float *temp)
{
int fd = -1;//open()打开文件的文件描述符
int found = 0;//是否找到DS18B20的标志,默认为0
int rv = 0;//函数返回值,默认设置为0表示成功返回
char chip_sn[32];//DS18B20 芯片序列号文件名
char buf[128];//read()读数据存储buffer
char *ptr =NULL;//字符指针,用来字符串处理
DIR *dirp = NULL;//opendir()打开的文件夹句柄
struct dirent *direntp = NULL;//readdir()读文件夹内容时的目录项
char w1_path[64]="/sys/bus/w1/devices/";//一线协议设备的路径
//const char *w1_path[64]="/sys/bus/w1/devices/";//一线协议设备的路径
/*进行函数参数的合法性检测,通过 $temp 传入一个空指针,下面的代码就有可能出现段错误*/
if( !temp )
{
return -1;
}
/*打开 "/sys/bus/w1/devices/" 文件夹*/
dirp=opendir(w1_path);
if( !dirp )
{
printf("open floder %s failure: %s\n", w1_path, strerror(errno));
return -2;
}
/*通过direntp->d_name寻找每个文件或文件夹,知道找到包含“28-”的文件,然后将文件名保存至chip_sn中,并将found设为1,然后跳出循环*/
while( NULL != (direntp=readdir(dirp)) )
{
if( strstr(direntp->d_name, "28-"))
{
strncpy(chip_sn, direntp->d_name, sizeof(chip_sn));
found = 1;
break;
}
}
/*文件夹打开用完后要关闭*/
closedir(dirp);
/*判断是否找到对应的文件*/
if( !found )
{
printf("Can not find ds18b20 chipset in %s\n", w1_path);
return -3;
}
/*合成完整路径:/sys/bus/w1/devices/28-xxxxx/w1_slave到w1_path中*/
strncat(w1_path, chip_sn, sizeof(w1_path)-strlen(w1_path));
strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));
/*打开DS18B20采样文件*/
if( (fd=open(w1_path, O_RDONLY)) < 0)
{
printf("open %s failure: %s\n", w1_path, strerror(errno));
return -4;
}
/*清空buffer*/
memset(buf, 0, sizeof(buf));
/*读取文件中的内容将会触发DS18B20温度传感器采样,然后这里读取文件内容到buf中*/
if(read(fd, buf, sizeof(buf)) < 0)
{
printf("read data from fd=%d failure %s\n", fd, strerror(errno));
rv = -5;
goto cleanup;
}
/*采样温度值是在字符串"t="后面,这里我们从buf中找到"t="字符串的位置并保存到ptr指针中*/
ptr=strstr(buf, "t=");
if( !ptr )
{
printf("ERROR: Can not find t= string\n");
rv = -6;
goto cleanup;
}
/*因为此时ptr是指向 "t="字符串的地址(即't'的地址),那跳过2个字节(t=)后面的就是采样温度值*/
ptr += 2;
*temp = atof(ptr)/1000;
//printf("temperature: %f\n", *temp);
cleanup:
close(fd);
return rv;
}
我们通过交叉编译后下载到开发板中,如何赋予权限后运行测试如下:
总结
本章中我们通过DS18B20传感器来采样,并通过程序找到对应传感器通过一线协议采样的温度值,然后通过程序将获取的温度输出。