Raspberry Pi – Temperatuur sensor DS18B20 uitlezen
Hardware
De DS18B20 (of QT18B20) is een nauwkeurige digitale temperatuur sensor, het is een Dallas one-wire device en werkt op 3.3-5v, je kan meerdere sensoren aansluiten via dezelfde pinnen en deze uitlezen.
Afwijking: ±0,5°C bij −50°C en +85°C
Specificaties:
– 1-Wire interface vereist slechts 1 pin voor communicatie
– 9/10/11/12 bits resolutie (in te stellen)
– 64-bit serial code opgeslagen in een geïntegreerde ROM
– Kan worden gevoed vanuit datalijn.
– Voeding bereik is 3,0 V tot 5,5 V
– Meet temperaturen van -55 ° C tot +125 ° C
– ± 0,5 ° C nauwkeurigheid van -10 ° C tot +85 ° C
Pinout
Pin: | Functie |
1 | GND |
2 | Digitale uitgang |
3 | Vdd (+3.3v) |
Wat heb je nodig?
1) Weerstand van 4,7 kΩ (als pull-up)
1) Python 2.x
Aansluiten op de Raspberry Pi
Sluit de DS18B20 sensor aan zoals aangegeven op onderstaand schema:
Ps. de weerstand is nodig voor de pull-up!
DS18B20 pin: | Raspberry Pi pin: |
---|---|
1 (GND) | GND |
2 (Digitale uitgang) | GPIO4 |
3 (Vdd (+3.3v) | +3.3v |
Meerdere sensoren aansluiten
Normale Voeding
Als je de normale voeding gebruikt, dan is de onderstaande schakeling wat je nodig hebt om meerdere sensoren aan te sluiten.
Parasiet Voeding
In deze methode sluiten we in principe pin 1 en 3 van de sensor kort en trekt de sensor stroom via de data pin.
Schema om meerdere sensoren aan te sluiten:
Meetresolutie instellen
Het is mogelijk om de meetresolutie van de sensor te cconfigureren dat kan met het inladen van de dallas bibliotheek:
Voor 12-Bit: sensors.setResolution(temp1, 12);
Maar des te preciezer, hoe langer het duurt voordat data opgevraagd wordt:
Mode | Resol | Conversion time |
9 bits | 0.5°C | 93.75 ms |
10 bits | 0.25°C | 187.5 ms |
11 bits | 0.125°C | 375 ms |
12 bits | 0.0625°C | 750 ms |
Zie voorbeeld code onder.
(bron)
1-Wire module laden
Normaal is de 1-wire module niet geladen, als je ls /sys/bus/ (geeft inhoud van de folder weer) zou uitvoeren, staat w1 er niet bij:
1 2 3 |
pi@raspberry ~ $ ls /sys/bus/ amba clocksource cpu hid iscsi_flashnode platform sdio usb clockevents container event_source i2c mmc scsi spi workqueue |
Om de 1-Wire module te laden moeten we 2 commando’s uitvoeren, namelijk sudo modprobe w1-gpio en sudo modprobe w1_therm , om dit in 1 lijn uit te voeren op de raspberry pi, gebruik dan het volgende commando:
sudo modprobe w1-gpio && sudo modprobe w1_therm
Al je daarna nog een keer de inhoud bekijkt van /sys/bus/ , dan zie je nu w1 er wel bij staan.
1 2 3 |
pi@raspberry ~ $ ls /sys/bus/ amba clocksource cpu hid iscsi_flashnode platform sdio usb workqueue clockevents container event_source i2c mmc scsi spi w1 |
1-Wire module automatisch laden
Om nu niet elke keer deze regel in te hoeven tikken om de 1-wire module te laden als je de raspberyr pi (her)start, kun je deze regels toevoegen aan het opstart script /etc/modules
1) Tik in op de raspberry pi:
sudo nano /etc/modules
2) Plak deze regels onderaan het bestand:
1 2 |
w1-gpio pullup=1 w1-therm |
Druk op CTRL+O en dan ENTER om op te slaan, CTRL+X om nano af te sluiten.
3) Herstart de raspberry pi met het commando: sudo reboot
Na het opstarten word de 1-wire module automatisch geladen.
GPIO en de nieuwe kernel
Er zijn problemen bekend dat de GPIO toewijzingen niet altijd goed werken, het onderstaande kan het probleem verhelpen door “/boot/config.txt” te bewerken.
1) Bewerk “/boot/config.txt” met het commando: sudo nano /boot/config.txt
2) Zet onderaan deze inhoud:
1 2 |
# 1-wire settings dtoverlay=w1-gpio |
Druk op CTRL+O en dan ENTER om op te slaan, CTRL+X om nano af te sluiten.
3) Herstart de raspberry pi met het commando: sudo reboot
Foutmeldingen?
In het dmesg log komen deze regels voor:
w1_master_driver w1_bus_master1: Family 0 for 00.X00000000000.XX is not registered.
Dit is geen foutmelding maar een “standaard” melding op de 1-wire bus dat er niets is aangesloten!
Waar bevind zich de sensor en de data?
LET OP: de folder “w1_bus_master1” is bij een nieuwe kernel er bij gekomen:
RPi 1,2,3 met oude kernel: /sys/bus/w1/devices/[sensorid]/w1_slave
RPi 2,3 met nieuwe kernel: /sys/bus/w1/devices/w1_bus_master1/[sensorid]/w1_slave
Nadat je de 1-wire module hebt geladen, vind je alle temperatuur modules in: /sys/bus/w1/devices/w1_bus_master1/
De data staat in de folder van de “gevonden sensoren”: /sys/bus/w1/devices/w1_bus_master1/[ID van de sensor]/w1_slave
Om de data weer te geven, gebruik het commando: cat /sys/bus/w1/devices/w1_bus_master1/[ID van de sensor]/w1_slave
Hieronder zie je een voorbeeld:
Zien hoeveel sensoren er zijn gevonden kan met het commmando:
cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count
Temperatuur uitlezen via BASH
Snel en eenvoudig de temperatuur uitlezen van een sensor via de bash kan met deze regel (pas het ID aan aan je eigen situatie):
1 |
cat /sys/bus/w1/devices/28-0000054871cb/w1_slave | sed -n 's/^.*\(t=[^ ]*\).*/\1/p' | sed 's/t=//' | awk '{x=$1}END{print(x/1000)}' |
Makkelijk en snel een bash gebruiken
1) Creëer een bestand “temp1” in “/usr/bin“, met het commando: sudo nano /usr/bin/temp1
2) Zet daarin deze inhoud;
1 2 |
#!/bin/bash cat /sys/bus/w1/devices/28-0000054871cb/w1_slave | sed -n 's/^.*\(t=[^ ]*\).*/\1/p' | sed 's/t=//' | awk '{x=$1}END{print(x/1000)}' |
3) Druk op CTRL+O en dan ENTER om op te slaan, CTRL+X om nano af te sluiten.
4) Zet de rechten van het bestand zo dat het uitgevoerd mag worden met het commando: sudo chmod +x /usr/bin/temp1
Temperatuur uitlezen via Python
Het is mogelijk om dus de waarde die je ziet dmv het “cat” commando:
1 2 |
7d 01 4b 46 7f ff 03 10 24 : crc=24 YES 7d 01 4b 46 7f ff 03 10 24 t=23812 |
in een string te zetten en zo “knippend” naar de temperatuur waarde te gaan:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# Importeer bibliotheek voor systeemfuncties. import sys # Definieer een array (temp). temp = {} sensorids = ["28-0000054871cb"] # loop net zo lang alles sensors af dat in het array hieboven staan. for sensor in range(len(sensorids)): #tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave") #RPi 1,2 met oude kernel. tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave") #RPi 2,3 met nieuwe kernel. # Lees alle dat uit het "bestand" in een variabele. text = tfile.read() # Sluit het "bestand" nadat we het gelezen hebben. tfile.close() # We gaan nu de tekst splitsen per nieuwe regel (\n) # en we selecteren de 2e regel [1] (1e regel = [0]) secondline = text.split("\n")[1] # Splits de regel in "woorden", er wordt gespleten op de spaties. # We selecteren hier het 10 "woord" [9] (tellend vanaf 0) temperaturedata = secondline.split(" ")[9] # De eerste 2 karakters zijn "t=", deze moeten we weghalen. # we maken meteen van de string een integer (nummer). temperature = float(temperaturedata[2:]) # De temperatuurwaarde moeten we delen door 1000 voor de juiste waarde. temp[sensor] = temperature / 1000 # print de gegevens naar de console. print "sensor", sensor, "=", temp[sensor], "graden." |
Gegevens wegschrijven naar CSV bestand (1 sensor)
Je kan de gegevens ook opslaan in een CSV bestand, onderstaand script maakt ook gebruik van de commandolijn parameters en slaat gegevens op in een bestand (per maand) in “/usr/src/DS_DATA_[YYYY]_[MM].csv”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# Importeer bibliotheek voor systeemfuncties. import sys # Importeer bibliotheek voor tijdfuncties. import time # Importeer bibliotheek voor CSV functies. import csv # Definieer een array (temp). temp = {} # Definieer variabelen. DY = time.strftime("%Y") DM = time.strftime("%m") DD = time.strftime("%d") TH = time.strftime("%H") TM = time.strftime("%M") sensorids = ["28-0000054871cb"] # loop net zo lang alles sensors af dat in het array hieboven staan. for sensor in range(len(sensorids)): #tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave") #RPi 1,2 met oude kernel. tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave") #RPi 2,3 met nieuwe kernel. # Lees alle dat uit het "bestand" in een variabele. text = tfile.read() # Sluit het "bestand" nadat we het gelezen hebben. tfile.close() # We gaan nu de tekst splitsen per nieuwe regel (\n) # en we selecteren de 2e regel [1] (1e regel = [0]) secondline = text.split("\n")[1] # Splits de regel in "woorden", er wordt gespleten op de spaties # We selecteren hier het 10 "woord" [9] (tellend vanaf 0) temperaturedata = secondline.split(" ")[9] # De eerste 2 karakters zijn "t=", deze moeten we weghalen. # we maken meteen van de string een integer (nummer). temperature = float(temperaturedata[2:]) # De temperatuur waarde moeten we delen door 1000 voor de juiste waarde. temp[sensor] = temperature / 1000 # print de gegevens naar de console. # print "sensor", sensor, "=", temp[sensor], "graden." data = [DY, DM, DD, TH, TM, temp[sensor]] # Array aanvullen indien meerdere sensoren! # Sla gegevens op in een bestand (per maand) in /usr/src/DHT_DATA_[YYYY]_[MM].csv csvfile = "/home/pi/DS_DATA_" + DY + "_" + DM + ".csv" # Open het csv bestand en schijf door achter de bestaande inhoud. with open(csvfile, "a") as output: writer = csv.writer(output, delimiter=";", lineterminator='\n') writer.writerow(data) |
De inhoud van het CSV bestand ziet er zo uit:
1 2 3 4 |
2015;05;01;17;49;23.625 2015;05;01;17;50;23.625 2015;05;01;17;51;28.5 2015;05;01;17;51;30.812 |
Gegevens wegschrijven naar CSV bestand (2 sensoren)
Je kan de gegevens ook opslaan in een CSV bestand, onderstaand script maakt ook gebruik van de commandolijn parameters en slaat gegevens op in een bestand (per maand) in “/usr/src/DS_DATA_[YYYY]_[MM].csv”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# Importeer bibliotheek voor systeemfuncties. import sys # Importeer bibliotheek voor tijdfuncties. import time # Importeer bibliotheek voor CSV functies. import csv # Definieer een array (temp). temp = {} # Definieer variabelen. DY = time.strftime("%Y") DM = time.strftime("%m") DD = time.strftime("%d") TH = time.strftime("%H") TM = time.strftime("%M") sensorids = ["28-0000054871cb"] # loop net zo lang alles sensors af dat in het array hieboven staan. for sensor in range(len(sensorids)): #tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave") #RPi 1,2 met oude kernel. tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave") #RPi 2,3 met nieuwe kernel. # Lees alle dat uit het "bestand" in een variabele. text = tfile.read() # Sluit het "bestand" nadat we het gelezen hebben. tfile.close() # We gaan nu de tekst splitsen per nieuwe regel (\n) # en we selecteren de 2e regel [1] (1e regel = [0]) secondline = text.split("\n")[1] # Splits de regel in "woorden", er wordt gespleten op de spaties # We selecteren hier het 10 "woord" [9] (tellend vanaf 0) temperaturedata = secondline.split(" ")[9] # De eerste 2 karakters zijn "t=", deze moeten we weghalen. # we maken meteen van de string een integer (nummer). temperature = float(temperaturedata[2:]) # De temperatuur waarde moeten we delen door 1000 voor de juiste waarde. temp[sensor] = temperature / 1000 # print de gegevens naar de console. # print "sensor", sensor, "=", temp[sensor], "graden." # "%.1f" % VARIABELE = 1 decimaal # "%.2f" % VARIABELE = 2 decimalen ware_temp0 = "%.2f" % temp[0] # correctie indien nodig ware_temp0 = float(ware_temp0) + 0 ware_temp1 = "%.2f" % temp[1] # correctie indien nodig ware_temp1 = float(ware_temp1) + 0 data = [DY, DM, DD, TH, TM, ware_temp0, ware_temp1] # Sla gegevens op in een bestand (per maand) in /usr/src/DHT_DATA_[YYYY]_[MM].csv csvfile = "/home/pi/DHT_DATA_" + DY + "_" + DM + ".csv" # Open het csv bestand en schijf door achter de bestaande inhoud. with open(csvfile, "a") as output: writer = csv.writer(output, delimiter=";", lineterminator='\n') writer.writerow(data) |
De inhoud van het CSV bestand ziet er zo uit:
1 2 3 4 |
2015;05;01;17;49;23.62;23.74 2015;05;01;17;50;23.62;23.74 2015;05;01;17;51;28.50;29.00 2015;05;01;17;51;30.81;30.60 |
Script om Serienummer(s) bekijken
1 2 3 4 5 6 7 8 |
#!/usr/bin/env python import glob for sensor in glob.glob("/sys/bus/w1/devices/*/w1_slave"): id = sensor.split("/")[5] print id |
Bronnen: reuk.co.uk / projects.privateeyepi.com / blog.vokiel.com / iada.nl / raspberrypi.stackexchange.com