W tym poście chciałbym opisać sposób obsługi termometru DS18B20 w oparciu o interfejs 1-Wire.
[Źródło: https://www.raspberrypi.org/products/raspberry-pi-3-model-b/]
Standardowy system:
Aby uruchomić interfejs 1-Wire należy wejść w ustawienia układu:
- sudo raspi-config
Następnie należy przejść do opcji numer 5 (Interfacing options) następnie P7 1-Wire gdzie nastąpi uruchomienie interfejsu. Następnie należy ponownie uruchomić system.
Po uruchomieniu interfejsu można sprawdzić poprawność wprowadzonych ustawień po wpisaniu komendy lsmod.
Linie danych interfejsu One Wire można podłączyć do każdego pinu danych dostępnego na Rapsberry Pi. Natomiast domyślnym pinem jest GPIO4.
Po podłączeniu czujnika do Raspberry odczytanie adresu termometru odbywa się przez sprawdzenie dostępnych urządzeń podłączonych do magistrali:
- ls /sys/bus/w1/devices
W celu odczytania temperatury z danego czujnika należy użyć następującego polecenia:
- cat /sys/bus/w1/devices/28-0000059373c9/w1_slave
Powyższy numer urządzenia odpowiada numerowi czujnika DS18B20 gdzie 28 to kod rodziny. Pozostały numer w ciągu odpowiada 48 bitowy unikalny numer czujnika.
Odpowiedzią na powyższą komendę będzie aktualna temperatura odczytana z czujnika (w tym przypadku będzie to 22,500 st.C)
Wartość crc=45 YES informuje czy transmisja pomiędzy czujnikiem a urządzeniem nadrzędnym została przeprowadzona poprawnie.
Jeśli czujnik miałby być podłączony do innego wyprowadzenia należy zmodyfikować plik /boot/config.txt, gdzie bez modyfikacji znajdują się następujące ustawienia:
- //...
- //...
- //...
- dtoverlay=w1-gpio
Jak wspomniałem wcześniej powoduje to uruchomienie interfejsu 1-Wire z standardowymi ustawieniami. (GPIO Pin 4).
Aby ustawić np. pin GPIO 22 należy wprowadzić następujące informacje do pliku:
- //...
- //...
- //...
- dtoverlay=w1-gpio,pullup=1,gpiopin=22
Odczyt temperatury Python:
Poniżej prosty program odczytujący temperaturę z podłączonych czujników.
- import glob
- #Convert Celsius to Fahrenheit:
- def CelsiusToFahrenheit(cel):
- return ((cel * 9.0/5.0) + 32.0)
- #Convert Fahrenheit to Celsius:
- def FahrenheitToCelsius(fah):
- return ((fah - 32) * 5.0/9.0)
- #Convert Celsius to Kelvin:
- def CelsiusToKelvin(cel):
- return (cel + 273.15)
- #Search for connected DS18B20
- def find_devices():
- return glob.glob('/sys/bus/w1/devices/28-*')
- #Read temperature for device
- def read_temp(path):
- lines = []
- with open(path + '/w1_slave') as f:
- lines = f.readlines()
- #Not all lines has been readed
- if len(lines) != 2:
- return False, 0
- #Device return CRC Error
- if lines[0].find('YES') == -1:
- return False, 0
- d = lines[1].strip().split('=')
- #two strings in array
- if len(d) != 2:
- return False, 0
- celTemp = int(d[1])
- #return operation status, readed temperature
- return True, celTemp
- if __name__ == '__main__':
- #Get connected devices
- devices = find_devices()
- #Print data from all connected devices
- for device in devices:
- print('Device Data Loc - ' + device)
- valid, raw = read_temp(device)
- if valid:
- cel = raw / 1000.0
- far = CelsiusToFahrenheit(cel)
- kel = CelsiusToKelvin(cel)
- print('%i [RAW] - %0.2f [F] - %0.2f [K] - %0.3f [C]' % (raw, far, kel, cel))
Wynik działania programu to:
Można także użyć bibliotek w1thermsensor. W tym celu należy ją najpierw zainstalować.
- //Dla python3 lub python2
- sudo apt-get install python3-w1thermsensor
- sudo apt-get install python-w1thermsensor
Poniżej program wykorzystujący odczyt temperatury z powyższej biblioteki:
- import w1thermsensor
- ds18b20Sensor = w1thermsensor.W1ThermSensor()
- tempInCel = ds18b20Sensor.get_temperature()
- print('%0.3f [C]' % (tempInCel))
Wynik działania programu:
Odczyt temperatury C:
Poniżej przykład wykorzystujący odczyt temperatury z czujnika DS18B20 w języku C. Odczyt nastąpi z wykorzystaniem plików systemowych, podobnie jak w przypadku pierwszego przykładu w języku Python.
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <dirent.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/types.h>
- #define SENSORPATH "/sys/bus/w1/devices"
- #define MAX_NUMBER_OF_SENSORS 2
- #define PROBENAMELEN 100
- char probepath[MAX_NUMBER_OF_SENSORS][PROBENAMELEN];
- char probename[MAX_NUMBER_OF_SENSORS][PROBENAMELEN];
- FILE *probefd[MAX_NUMBER_OF_SENSORS];
- float ConvertRawToCelsius(int raw) {
- return (raw/1000.0);
- }
- float ConvertCelsiusToFahrenheit(float cel) {
- return ((cel * 9.0/5.0) + 32.0);
- }
- float ConvertCelsiusToKelvin(float cel) {
- return (cel + 273.15);
- }
- uint8_t findprobes(void) {
- struct dirent *pDirent;
- DIR *pDir;
- uint8_t ds18b20SensorsNumbers = 0;
- pDir = opendir(SENSORPATH);
- if (pDir == NULL) {
- fprintf(stderr, "Cannot open directory\n");
- return 0;
- }
- while ((pDirent = readdir(pDir)) != NULL)
- {
- if(strstr(pDirent->d_name, "28-") != NULL)
- {
- snprintf(probepath[ds18b20SensorsNumbers], PROBENAMELEN-1, "%s/%s/w1_slave", SENSORPATH, pDirent->d_name);
- snprintf(probename[ds18b20SensorsNumbers], PROBENAMELEN-1, "%s", pDirent->d_name);
- ds18b20SensorsNumbers++;
- }
- }
- closedir(pDir);
- return ds18b20SensorsNumbers;
- }
- int main(int argc, char **argv)
- {
- float temperature;
- char *temp;
- char buf[100];
- uint8_t connectedSensors = 0;
- printf("DS18B20 test program\r\n");
- connectedSensors = FindSensors();
- if (connectedSensors == 0) {
- fprintf(stderr, "Error: No DS18B20 compatible probes located.\r\n");
- exit(1);
- }
- else {
- printf("Number of connected sensors: %i\r\n", connectedSensors);
- }
- for(uint8_t c = 0; c < connectedSensors; c++)
- {
- probefd[c] = fopen(probepath[c], "r");
- if (probefd[c] == NULL) {
- fprintf(stderr, "Error: Can't receive data\r\n");
- exit(1);
- }
- else {
- printf("Data readed from sensor %i\r\n", (c+1));
- }
- fgets(buf, sizeof(buf)-1, probefd[c]);
- printf(buf);
- /* Check if CRC is correct */
- printf("CRC Checking - ");
- if(strstr(buf, "YES") != NULL) {
- printf("OK\r\n");
- } else {
- printf("Error\r\n");
- exit(1);
- }
- memset(buf, 0, sizeof(buf));
- fgets(buf, sizeof(buf)-1, probefd[c]);
- printf(buf);
- temp = strstr(buf, "t=");
- temp += 2;
- temperature = ConvertRawToCelsius(atoi(temp));
- printf("---------------------------\r\n");
- printf("Sensor number %i\r\n", (c+1));
- printf("Probe %s\r\n", probename[c]);
- printf("Temp: %i [RAW]; %2.3f [C]; %2.3f [F]; %3.3f [K]\r\n", (atoi(temp)), temperature,
- ConvertCelsiusToFahrenheit(temperature), ConvertCelsiusToKelvin(temperature));
- fclose(probefd[c]);
- }
- exit(0);
- }
Wynik działania programu z podłączonym jednym czujnikiem jest następujący:
NodeJs:
- npm install --save ds18b20-raspi
- const sensor = require('ds18b20-raspi');
- const tempC = sensor.readSimpleC();
- console.log(`${tempC} degC`);
- // async version
- sensor.readSimpleC((err, temp) => {
- if (err) {
- console.log(err);
- } else {
- console.log(`${temp} degC`);
- }
- });