Difference between revisions of "Raspberry Pi Tutorial Series: 1-Wire DS18B20 Sensor"
(Created page with "DS18B20 is a common temperature sensor which communicates over a 1-Wire bus that by definition requires only one data line. Usually, a certain MCU reads data from DS18B20 in s...") |
|||
(4 intermediate revisions by the same user not shown) | |||
Line 5: | Line 5: | ||
Select Advanced Option -> 1-Wire -> <Yes> | Select Advanced Option -> 1-Wire -> <Yes> | ||
− | In fact this tool edits the /boot/config.txt and appends this line: dtoverlay=w1-gpio. With this line, a GPIO to drive an external pullup is disabled by default. It's inconvenience in certain condition so we often change "dtoverlay=w1-gpio" to "dtoverlay=w1-gpio-pullup". We also specify GPIO 4 for I/O, so we change the line to "dtoverlay=w1-gpio-pullup,gpiopin=4". Just for instance, because GPIO 4 is used for I/O by default so "gpiopin=4" is not usually required. | + | In fact this tool edits the /boot/config.txt and appends this line: dtoverlay=w1-gpio. With this line, a GPIO to drive an external pullup is disabled by default. It's inconvenience in certain condition so we often change "dtoverlay=w1-gpio" to "dtoverlay=w1-gpio-pullup". We also specify GPIO 4 for I/O, so we change the line to "dtoverlay=w1-gpio-pullup,gpiopin=4". Just for instance, because GPIO 4 (BCM numbering, can be checked by this command: gpio readall) is used for I/O by default so "gpiopin=4" is not usually required. |
More details about "dtoverlay", please read the manual: /boot/overlays/README. | More details about "dtoverlay", please read the manual: /boot/overlays/README. | ||
Line 32: | Line 32: | ||
</pre> | </pre> | ||
Finally, we append this line to the config.txt file: "dtoverlay=w1-gpio-pullup,gpiopin=4" (no space in this line). | Finally, we append this line to the config.txt file: "dtoverlay=w1-gpio-pullup,gpiopin=4" (no space in this line). | ||
+ | == Check whether the module is started == | ||
+ | Connect the Data Pin of DS18B20 to the GPIO 4 of RPi (BCM numbering, corresponds to the physical 7 pin. The same below). The Pins GND/VCC are connected to 3.3V power supply. | ||
+ | Reboot the Raspberry Pi to enable the settings. Then list the 1-Wire module with this command: | ||
+ | lsmod | grep w1 | ||
+ | You get: | ||
+ | {|class=wikitable | ||
+ | | [[File:raspberry-pi-tutorial-series-1-wire-ds18b20-sensor-1.png]] | ||
+ | |} | ||
+ | It indicates the module is started. If you didn't find the w1 device, mount it with: | ||
+ | sudo modprobe w1_gpio | ||
+ | sudo modprobe w1_therm | ||
+ | == Read temperature == | ||
+ | Change the current directory to /sys/bus/w1/devices | ||
+ | cd /sys/bus/w1/devices | ||
+ | List the file and a 28-xxxxxxxxxxxx device directory (e.g. here is 28-00000674869d) will be found. This is the ROM of DS18B20. If more than one DS18B20 are connected, you will find a certain directories more than one. | ||
+ | cd 28-00000674869d | ||
+ | You can read the temperature from the w1_slave file in the directory. This is too good to be true! | ||
+ | cat w1_slave | ||
+ | {|class=wikitable | ||
+ | ! Read the temperature from the file w1_slave | ||
+ | |- | ||
+ | |[[File:raspberry-pi-tutorial-series-1-wire-ds18b20-sensor-2.png]] | ||
+ | |} | ||
+ | The YES in the first line indicates CRC check success (Data Valid ). The number following t= is the temperature, 28750 stands for 28.7 (C). | ||
+ | == Programming == | ||
+ | * These examples require a certain library, see: [[Libraries Installation for RPi]] | ||
+ | === sysfs === | ||
+ | <pre> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <unistd.h> | ||
+ | #include <fcntl.h> | ||
+ | #include <dirent.h> | ||
+ | #include <string.h> | ||
+ | #include <time.h> | ||
+ | |||
+ | int main(int argc, char *argv[]) | ||
+ | { | ||
+ | char path[50] = "/sys/bus/w1/devices/"; | ||
+ | char rom[20]; | ||
+ | char buf[100]; | ||
+ | DIR *dirp; | ||
+ | struct dirent *direntp; | ||
+ | int fd =-1; | ||
+ | char *temp; | ||
+ | float value; | ||
+ | // These tow lines | ||
+ | mount the device: | ||
+ | system("sudo modprobe w1-gpio"); | ||
+ | system("sudo modprobe w1-therm"); | ||
+ | // Check if /sys/bus/w1/devices/ exists. | ||
+ | if((dirp = opendir(path)) == NULL) | ||
+ | { | ||
+ | printf("opendir error\n"); | ||
+ | return 1; | ||
+ | } | ||
+ | // Reads the directories or files in the current directory. | ||
+ | while((direntp = readdir(dirp)) != NULL) | ||
+ | { | ||
+ | // If 28-00000 is the substring of d_name, | ||
+ | // then copy d_name to rom and print rom. | ||
+ | if(strstr(direntp->d_name,"28-00000")) | ||
+ | { | ||
+ | strcpy(rom,direntp->d_name); | ||
+ | printf(" rom: %s\n",rom); | ||
+ | } | ||
+ | } | ||
+ | closedir(dirp); | ||
+ | // Append the String rom and "/w1_slave" to path | ||
+ | // path becomes to "/sys/bus/w1/devices/28-00000xxxx/w1_slave" | ||
+ | strcat(path,rom); | ||
+ | strcat(path,"/w1_slave"); | ||
+ | while(1) | ||
+ | { | ||
+ | // Open the file in the path. | ||
+ | if((fd = open(path,O_RDONLY)) < 0) | ||
+ | { | ||
+ | printf("open error\n"); | ||
+ | return 1; | ||
+ | } | ||
+ | // Read the file | ||
+ | if(read(fd,buf,sizeof(buf)) < 0) | ||
+ | { | ||
+ | printf("read error\n"); | ||
+ | return 1; | ||
+ | } | ||
+ | // Returns the first index of 't'. | ||
+ | temp = strchr(buf,'t'); | ||
+ | // Read the string following "t=". | ||
+ | sscanf(temp,"t=%s",temp); | ||
+ | // atof: changes string to float. | ||
+ | value = atof(temp)/1000; | ||
+ | printf(" temp : %3.3f °C\n",value); | ||
+ | |||
+ | sleep(1); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </pre> | ||
+ | Save the file as "ds18b20.c" then compile and run with: | ||
+ | gcc -Wall ds18b20.c -o ds18b20 | ||
+ | sudo ./ds18b20 | ||
+ | === Python === | ||
+ | <pre> | ||
+ | |||
+ | import os | ||
+ | import glob | ||
+ | import time | ||
+ | |||
+ | # These tow lines mount the device: | ||
+ | os.system('modprobe w1-gpio') | ||
+ | os.system('modprobe w1-therm') | ||
+ | |||
+ | base_dir = '/sys/bus/w1/devices/' | ||
+ | # Get all the filenames begin with 28 in the path base_dir. | ||
+ | device_folder = glob.glob(base_dir + '28*')[0] | ||
+ | device_file = device_folder + '/w1_slave' | ||
+ | def read_rom(): | ||
+ | name_file=device_folder+'/name' | ||
+ | f = open(name_file,'r') | ||
+ | return f.readline() | ||
+ | |||
+ | def read_temp_raw(): | ||
+ | f = open(device_file, 'r') | ||
+ | lines = f.readlines() | ||
+ | f.close() | ||
+ | return lines | ||
+ | |||
+ | def read_temp(): | ||
+ | lines = read_temp_raw() | ||
+ | # Analyze if the last 3 characters are 'YES'. | ||
+ | while lines[0].strip()[-3:] != 'YES': | ||
+ | time.sleep(0.2) | ||
+ | lines = read_temp_raw() | ||
+ | # Find the index of 't=' in a string. | ||
+ | equals_pos = lines[1].find('t=') | ||
+ | if equals_pos != -1: | ||
+ | # Read the temperature . | ||
+ | temp_string = lines[1][equals_pos+2:] | ||
+ | temp_c = float(temp_string) / 1000.0 | ||
+ | temp_f = temp_c * 9.0 / 5.0 + 32.0 | ||
+ | return temp_c, temp_f | ||
+ | |||
+ | print(' rom: '+ read_rom()) | ||
+ | while True: | ||
+ | print(' C=%3.3f F=%3.3f'% read_temp()) | ||
+ | time.sleep(1) | ||
+ | </pre> | ||
+ | Save the file as "ds18b20.py" then execute with: | ||
+ | sudo python ds18b20.py | ||
+ | {|class=wikitable | ||
+ | ! colspan=2| expected result | ||
+ | |- | ||
+ | |[[File:raspberry-pi-tutorial-series-1-wire-ds18b20-sensor-3.png]] | ||
+ | |[[File:raspberry-pi-tutorial-series-1-wire-ds18b20-sensor-4.png]] | ||
+ | |} |
Revision as of 10:21, 19 August 2016
DS18B20 is a common temperature sensor which communicates over a 1-Wire bus that by definition requires only one data line. Usually, a certain MCU reads data from DS18B20 in strict accordance with Timing, but now we are going to control DS18B20 using a Raspberry and with the Raspbian OS. You will find that everything is file in the Linux.
Enable 1-Wire
Enable 1-Wire interface with the raspi-config tool.
sudo raspi-config
Select Advanced Option -> 1-Wire -> <Yes>
In fact this tool edits the /boot/config.txt and appends this line: dtoverlay=w1-gpio. With this line, a GPIO to drive an external pullup is disabled by default. It's inconvenience in certain condition so we often change "dtoverlay=w1-gpio" to "dtoverlay=w1-gpio-pullup". We also specify GPIO 4 for I/O, so we change the line to "dtoverlay=w1-gpio-pullup,gpiopin=4". Just for instance, because GPIO 4 (BCM numbering, can be checked by this command: gpio readall) is used for I/O by default so "gpiopin=4" is not usually required.
More details about "dtoverlay", please read the manual: /boot/overlays/README.
- Quote from /boot/overlays/README:
Name: w1-gpio Info: Configures the w1-gpio Onewire interface module. Use this overlay if you *don't* need a GPIO to drive an external pullup. Load: dtoverlay=w1-gpio,<param>=<val> Params: gpiopin GPIO for I/O (default "4") pullup Non-zero, "on", or "y" to enable the parasitic power (2-wire, power-on-data) feature Name: w1-gpio-pullup Info: Configures the w1-gpio Onewire interface module. Use this overlay if you *do* need a GPIO to drive an external pullup. Load: dtoverlay=w1-gpio-pullup,<param>=<val> Params: gpiopin GPIO for I/O (default "4") pullup Non-zero, "on", or "y" to enable the parasitic power (2-wire, power-on-data) feature extpullup GPIO for external pullup (default "5")
Finally, we append this line to the config.txt file: "dtoverlay=w1-gpio-pullup,gpiopin=4" (no space in this line).
Check whether the module is started
Connect the Data Pin of DS18B20 to the GPIO 4 of RPi (BCM numbering, corresponds to the physical 7 pin. The same below). The Pins GND/VCC are connected to 3.3V power supply. Reboot the Raspberry Pi to enable the settings. Then list the 1-Wire module with this command:
lsmod | grep w1
You get:
It indicates the module is started. If you didn't find the w1 device, mount it with:
sudo modprobe w1_gpio sudo modprobe w1_therm
Read temperature
Change the current directory to /sys/bus/w1/devices
cd /sys/bus/w1/devices
List the file and a 28-xxxxxxxxxxxx device directory (e.g. here is 28-00000674869d) will be found. This is the ROM of DS18B20. If more than one DS18B20 are connected, you will find a certain directories more than one.
cd 28-00000674869d
You can read the temperature from the w1_slave file in the directory. This is too good to be true!
cat w1_slave
Read the temperature from the file w1_slave |
---|
The YES in the first line indicates CRC check success (Data Valid ). The number following t= is the temperature, 28750 stands for 28.7 (C).
Programming
- These examples require a certain library, see: Libraries Installation for RPi
sysfs
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <dirent.h> #include <string.h> #include <time.h> int main(int argc, char *argv[]) { char path[50] = "/sys/bus/w1/devices/"; char rom[20]; char buf[100]; DIR *dirp; struct dirent *direntp; int fd =-1; char *temp; float value; // These tow lines mount the device: system("sudo modprobe w1-gpio"); system("sudo modprobe w1-therm"); // Check if /sys/bus/w1/devices/ exists. if((dirp = opendir(path)) == NULL) { printf("opendir error\n"); return 1; } // Reads the directories or files in the current directory. while((direntp = readdir(dirp)) != NULL) { // If 28-00000 is the substring of d_name, // then copy d_name to rom and print rom. if(strstr(direntp->d_name,"28-00000")) { strcpy(rom,direntp->d_name); printf(" rom: %s\n",rom); } } closedir(dirp); // Append the String rom and "/w1_slave" to path // path becomes to "/sys/bus/w1/devices/28-00000xxxx/w1_slave" strcat(path,rom); strcat(path,"/w1_slave"); while(1) { // Open the file in the path. if((fd = open(path,O_RDONLY)) < 0) { printf("open error\n"); return 1; } // Read the file if(read(fd,buf,sizeof(buf)) < 0) { printf("read error\n"); return 1; } // Returns the first index of 't'. temp = strchr(buf,'t'); // Read the string following "t=". sscanf(temp,"t=%s",temp); // atof: changes string to float. value = atof(temp)/1000; printf(" temp : %3.3f °C\n",value); sleep(1); } return 0; }
Save the file as "ds18b20.c" then compile and run with:
gcc -Wall ds18b20.c -o ds18b20 sudo ./ds18b20
Python
import os import glob import time # These tow lines mount the device: os.system('modprobe w1-gpio') os.system('modprobe w1-therm') base_dir = '/sys/bus/w1/devices/' # Get all the filenames begin with 28 in the path base_dir. device_folder = glob.glob(base_dir + '28*')[0] device_file = device_folder + '/w1_slave' def read_rom(): name_file=device_folder+'/name' f = open(name_file,'r') return f.readline() def read_temp_raw(): f = open(device_file, 'r') lines = f.readlines() f.close() return lines def read_temp(): lines = read_temp_raw() # Analyze if the last 3 characters are 'YES'. while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = read_temp_raw() # Find the index of 't=' in a string. equals_pos = lines[1].find('t=') if equals_pos != -1: # Read the temperature . temp_string = lines[1][equals_pos+2:] temp_c = float(temp_string) / 1000.0 temp_f = temp_c * 9.0 / 5.0 + 32.0 return temp_c, temp_f print(' rom: '+ read_rom()) while True: print(' C=%3.3f F=%3.3f'% read_temp()) time.sleep(1)
Save the file as "ds18b20.py" then execute with:
sudo python ds18b20.py
expected result | |
---|---|