Raspberry Pi Tutorial Series: 1-Wire DS18B20 Sensor
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