Difference between revisions of "Raspberry Pi Tutorial Series: 1-Wire DS18B20 Sensor"
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 == | ||
+ | === 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 run modprobe commands to 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 of 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 | ||
+ | [[File:raspberry-pi-tutorial-series-1-wire-ds18b20-sensor-3.png|frame|Read the temperature]] |
Revision as of 04:10, 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
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 run modprobe commands to 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 of 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