Raspberry Pi 树莓派连接温度传感器DS18B20

来源:http://www.waveshare.net/study/article-607-1.html

本章讲解如果在linux系统下控制DS18B20

DS18B20是一个比较常用的温度传感器,采用单总线控制,以前用单片机编程控制时严格按照单总线的时序控制,今天来看看在linux系统下如何控制DS18B20,体验一下在linux世界,一切都是文件。

一、修改配置文件

1 sudo vi /boot/config.txt

(注:运行sudo raspi-config实际上也是修改这个文件,例如设置Advanced Options  -> I2C 启动i2C内核驱动,就是修个dtparam=i2c_arm=on 这一行)

在/boot/config.txt文件后面添加下面这一句,这一句就是树莓派添加Device Tree设备,dtoverlay=w1-gpio-pull表示添加单总线设备,gpioin=4默认管脚为4,如果DS18B20接到其他管脚则需要修改这个值,Pioneer 600扩展板DS18B20默认接到4,故不用修改。(注:管脚为BCM编号)

1 dtoverlay=w1-gpio-pullup,gpioin=4

在/boot/overlays/README中有关于树莓派Device Tree的详细介绍,在其中我们找到下面关于w1-gpio-pullup设备的介绍如下图。

二、查看模块是否启动

重启树莓派是设置生效,运行lsmod命令,如果发现红色方框的两个模块说明模块已启动。

如果没有发现,也可以运行如下命令加载模块

1 sudo modprobe w1_gpio
2 sudo modprobe w1_therm

三、 读取温度

如果没有问题,在/sys/bus/w1/devices中发现一个28-XXXX开头的文件夹,这个就是DS18B20的ROM,每个DS18B20都一样,在这个文件夹中读取w1_slave文件则会返回当前温度值。操作如下图:

1 sudo modprobe w1-gpio
2 sudo modprobe w1-therm
3 cd  /sys/bus/w1/devices
4 cd 28-00000xxx
5 cat w1_slave

返回数据中,第一行最后的YRS表示CRC校验成功,数据有效。第二行最后t=30500表示当前温度为30.5摄氏度。

如果接多个DS18B20,将会看到多个28-xxxx的文件,分别对应各个DS18B20。

四、软件编程

1、sysfs

01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <unistd.h>
04 #include <fcntl.h>
05 #include <dirent.h>
06 #include <string.h>
07 #include <time.h>
08  
09 int main(int argc, char *argv[])
10 {
11     char path[50] = "/sys/bus/w1/devices/";
12     char rom[20];
13     char buf[100];
14     DIR *dirp;
15     struct dirent *direntp;
16     int fd =-1;
17     char *temp;
18     float value;
19  
20     system("sudo modprobe w1-gpio");
21     system("sudo modprobe w1-therm");
22     if((dirp = opendir(path)) == NULL)
23     {
24         printf("opendir error\n");
25         return 1;
26     }
27  
28     while((direntp = readdir(dirp)) != NULL)
29     {
30         if(strstr(direntp->d_name,"28-00000"))
31         {
32             strcpy(rom,direntp->d_name);
33             printf(" rom: %s\n",rom);
34         }
35     }
36     closedir(dirp);
37  
38     strcat(path,rom);
39     strcat(path,"/w1_slave");
40     while(1)
41     {
42         if((fd = open(path,O_RDONLY)) < 0)
43         {
44             printf("open error\n");
45             return 1;
46         }
47  
48         if(read(fd,buf,sizeof(buf)) < 0)
49         {
50             printf("read error\n");
51             return 1;
52         }
53  
54         temp = strchr(buf,'t');
55         sscanf(temp,"t=%s",temp);
56         value = atof(temp)/1000;
57         printf(" temp : %3.3f °C\n",value);
58  
59         sleep(1);
60     }
61     return 0;
62 }

编译并执行,结果如图

1 gcc –Wall ds18b20.c –o ds18b20
2 sudo ds18b20

注:(1)system("sudo modprobe w1-gpio");system("sudo modprobe w1-therm");在程序的开头运行了一下modprobe命令

       (2) dirp = opendir(path) 打开/sys/bus/w1/devices/文件路径

(3)direntp = readdir(dirp) 读取当前路径下的文件或文件夹

(4)strstr(direntp->d_name,"28-00000")

 查找28-00000开头的文件,strstr为字符串操作函数,上面这条语句表示文件名字是否包含字符串“28-00000”,如果匹配则返回第一次匹配的地址,没有搜索到则返回NULL.

(5)strcpy(rom,direntp->d_name); strcpy为字符串复制函数。,将包含28-00000的文件名复制到rom字符串

(6)strcat(path,rom);strcat(path,"/w1_slave");  strcat为字符串连接函数,此时path的值为/sys/bus/w1/devices/28-00000xxxx/w1_slave

(7)fd = open(path,O_RDONLY); read(fd,buf,sizeof(buf)打开文件并读取数据

(8)temp = strchr(buf,'t'); 查找字符‘t第一次出现的位置, 

(9)sscanf(temp,"t=%s",temp); sscanf函数是从一个字符串中读进与指定格式相符的数据,此处为从第二行数据中扫描出温度值

(10) value = atof(temp)/1000; atof函数把字符串转化为浮点数。

2、python

01 import os
02 import glob
03 import time
04  
05 os.system('modprobe w1-gpio')
06 os.system('modprobe w1-therm')
07  
08 base_dir = '/sys/bus/w1/devices/'
09 device_folder = glob.glob(base_dir + '28*')[0]
10 device_file = device_folder + '/w1_slave'
11 def read_rom():
12     name_file=device_folder+'/name'
13     f = open(name_file,'r')
14     return f.readline()
15  
16 def read_temp_raw():
17     f = open(device_file, 'r')
18     lines = f.readlines()
19     f.close()
20     return lines
21  
22 def read_temp():
23     lines = read_temp_raw()
24     while lines[0].strip()[-3:] != 'YES':
25         time.sleep(0.2)
26         lines = read_temp_raw()
27     equals_pos = lines[1].find('t=')
28     if equals_pos != -1:
29         temp_string = lines[1][equals_pos+2:]
30         temp_c = float(temp_string) / 1000.0
31         temp_f = temp_c * 9.0 / 5.0 + 32.0
32         return temp_c, temp_f
33  
34 print(' rom: '+ read_rom())
35 while True:
36     print(' C=%3.3f  F=%3.3f'% read_temp())
37 time.sleep(1)

运行程序,运行结果如图

1 sudo python ds18b20.py

注:(1)程序的开头运行了一下modprobe命令

      (2) device_folder = glob.glob(base_dir + '28*')[0]

        device_file = device_folder + '/w1_slave'

     定义设备文件夹和设备文件,glob.globbase_dir + '28*'))函数为获得base_dir路径下所有28开头的文件。

(3)while lines[0].strip()[-3:] != 'YES':   判断w1-value第一行的最后三个字符是否为‘YES

(4)equals_pos = lines[1].find('t=')  查找第二行中‘t=出现的位置

 (5)  temp_string = lines[1][equals_pos+2:]  取温度数据

总结:对比上面两个两个程序,我们可以发现python程序更加简单方便。

DS18B20是一个比较常用的温度传感器,采用单总线控制,以前用单片机编程控制时严格按照单总线的时序控制,今天来看看在linux系统下如何控制DS18B20,体验一下在linux世界,一切都是文件。

一、修改配置文件

1 sudo vi /boot/config.txt

(注:运行sudo raspi-config实际上也是修改这个文件,例如设置Advanced Options  -> I2C 启动i2C内核驱动,就是修个dtparam=i2c_arm=on 这一行)

在/boot/config.txt文件后面添加下面这一句,这一句就是树莓派添加Device Tree设备,dtoverlay=w1-gpio-pull表示添加单总线设备,gpioin=4默认管脚为4,如果DS18B20接到其他管脚则需要修改这个值,Pioneer 600扩展板DS18B20默认接到4,故不用修改。(注:管脚为BCM编号)

1 dtoverlay=w1-gpio-pullup,gpioin=4

在/boot/overlays/README中有关于树莓派Device Tree的详细介绍,在其中我们找到下面关于w1-gpio-pullup设备的介绍如下图。

二、查看模块是否启动

重启树莓派是设置生效,运行lsmod命令,如果发现红色方框的两个模块说明模块已启动。

如果没有发现,也可以运行如下命令加载模块

1 sudo modprobe w1_gpio
2 sudo modprobe w1_therm

三、 读取温度

如果没有问题,在/sys/bus/w1/devices中发现一个28-XXXX开头的文件夹,这个就是DS18B20的ROM,每个DS18B20都一样,在这个文件夹中读取w1_slave文件则会返回当前温度值。操作如下图:

1 sudo modprobe w1-gpio
2 sudo modprobe w1-therm
3 cd  /sys/bus/w1/devices
4 cd 28-00000xxx
5 cat w1_slave

返回数据中,第一行最后的YRS表示CRC校验成功,数据有效。第二行最后t=30500表示当前温度为30.5摄氏度。

如果接多个DS18B20,将会看到多个28-xxxx的文件,分别对应各个DS18B20。

四、软件编程

1、sysfs

01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <unistd.h>
04 #include <fcntl.h>
05 #include <dirent.h>
06 #include <string.h>
07 #include <time.h>
08  
09 int main(int argc, char *argv[])
10 {
11     char path[50] = "/sys/bus/w1/devices/";
12     char rom[20];
13     char buf[100];
14     DIR *dirp;
15     struct dirent *direntp;
16     int fd =-1;
17     char *temp;
18     float value;
19  
20     system("sudo modprobe w1-gpio");
21     system("sudo modprobe w1-therm");
22     if((dirp = opendir(path)) == NULL)
23     {
24         printf("opendir error\n");
25         return 1;
26     }
27  
28     while((direntp = readdir(dirp)) != NULL)
29     {
30         if(strstr(direntp->d_name,"28-00000"))
31         {
32             strcpy(rom,direntp->d_name);
33             printf(" rom: %s\n",rom);
34         }
35     }
36     closedir(dirp);
37  
38     strcat(path,rom);
39     strcat(path,"/w1_slave");
40     while(1)
41     {
42         if((fd = open(path,O_RDONLY)) < 0)
43         {
44             printf("open error\n");
45             return 1;
46         }
47  
48         if(read(fd,buf,sizeof(buf)) < 0)
49         {
50             printf("read error\n");
51             return 1;
52         }
53  
54         temp = strchr(buf,'t');
55         sscanf(temp,"t=%s",temp);
56         value = atof(temp)/1000;
57         printf(" temp : %3.3f °C\n",value);
58  
59         sleep(1);
60     }
61     return 0;
62 }

编译并执行,结果如图

1 gcc –Wall ds18b20.c –o ds18b20
2 sudo ds18b20

注:(1)system("sudo modprobe w1-gpio");system("sudo modprobe w1-therm");在程序的开头运行了一下modprobe命令

       (2) dirp = opendir(path) 打开/sys/bus/w1/devices/文件路径

(3)direntp = readdir(dirp) 读取当前路径下的文件或文件夹

(4)strstr(direntp->d_name,"28-00000")

 查找28-00000开头的文件,strstr为字符串操作函数,上面这条语句表示文件名字是否包含字符串“28-00000”,如果匹配则返回第一次匹配的地址,没有搜索到则返回NULL.

(5)strcpy(rom,direntp->d_name); strcpy为字符串复制函数。,将包含28-00000的文件名复制到rom字符串

(6)strcat(path,rom);strcat(path,"/w1_slave");  strcat为字符串连接函数,此时path的值为/sys/bus/w1/devices/28-00000xxxx/w1_slave

(7)fd = open(path,O_RDONLY); read(fd,buf,sizeof(buf)打开文件并读取数据

(8)temp = strchr(buf,'t'); 查找字符‘t第一次出现的位置, 

(9)sscanf(temp,"t=%s",temp); sscanf函数是从一个字符串中读进与指定格式相符的数据,此处为从第二行数据中扫描出温度值

(10) value = atof(temp)/1000; atof函数把字符串转化为浮点数。

2、python

01 import os
02 import glob
03 import time
04  
05 os.system('modprobe w1-gpio')
06 os.system('modprobe w1-therm')
07  
08 base_dir = '/sys/bus/w1/devices/'
09 device_folder = glob.glob(base_dir + '28*')[0]
10 device_file = device_folder + '/w1_slave'
11 def read_rom():
12     name_file=device_folder+'/name'
13     f = open(name_file,'r')
14     return f.readline()
15  
16 def read_temp_raw():
17     f = open(device_file, 'r')
18     lines = f.readlines()
19     f.close()
20     return lines
21  
22 def read_temp():
23     lines = read_temp_raw()
24     while lines[0].strip()[-3:] != 'YES':
25         time.sleep(0.2)
26         lines = read_temp_raw()
27     equals_pos = lines[1].find('t=')
28     if equals_pos != -1:
29         temp_string = lines[1][equals_pos+2:]
30         temp_c = float(temp_string) / 1000.0
31         temp_f = temp_c * 9.0 / 5.0 + 32.0
32         return temp_c, temp_f
33  
34 print(' rom: '+ read_rom())
35 while True:
36     print(' C=%3.3f  F=%3.3f'% read_temp())
37 time.sleep(1)

运行程序,运行结果如图

1 sudo python ds18b20.py

注:(1)程序的开头运行了一下modprobe命令

      (2) device_folder = glob.glob(base_dir + '28*')[0]

        device_file = device_folder + '/w1_slave'

     定义设备文件夹和设备文件,glob.globbase_dir + '28*'))函数为获得base_dir路径下所有28开头的文件。

(3)while lines[0].strip()[-3:] != 'YES':   判断w1-value第一行的最后三个字符是否为‘YES

(4)equals_pos = lines[1].find('t=')  查找第二行中‘t=出现的位置

 (5)  temp_string = lines[1][equals_pos+2:]  取温度数据

总结:对比上面两个两个程序,我们可以发现python程序更加简单方便。

猜你喜欢

转载自blog.csdn.net/weixuedianzi/article/details/65935296