Zainspirowany na eko.one.pl [1] [2] [3] pomysłami dotyczącymi pomiaru temperatury za pomocą czujników Dallas DS18B20, postanowiłem zrobić coś podobnie, ale z wykorzystaniem Arduino i Pythona.
Czujniki Dallasa Ds18B20 są obecnie najtańszymi i dość dokładnymi czujnikami temperatury. Czujnik umożliwia pomiar temperatury w zakresie -50*C do 125*C z dokładności do dwóch zer po przecinku. Zaletą czujników Dallasa jest wykorzystanie szyny 1-Wire, co minimalizuje plątaninę kabli. Mianowicie wykorzystujemy tylko 2 przewody: VCC i GND. Kolejna zaleta jest możliwość łączenie (równolegle) czujników, co powoduje, że możemy mieć magistrale 1Wire i potem podłączać sobie czujnik gdzie mamy ochotę. Od strony programowej też nie ma żadnych problemów, gdyż każdy czujnik posiada własny indywidualny numer seryjny.
Aby cokolwiek odczytać, trzeba mieć najpierw układ. Jak napisałem na początku chce to zrobić inaczej, czyli wykorzystując Arduino. W artykule wykorzystam tylko jeden czujnik temperatury, więc program kliencki napisany w Pythonie będzie dość prosty. Jeżeli zdobędę drugi czujnik rozszerzę ten artykuł.
Schemat podłączenia czujnika do Arduino wygląda następująco

Schemat nie wymaga chyba większego opisu. Jak napisałem wcześniej wykorzystujemy dwie linie sygnałowe. W celu odczytania temperatury musimy zaprogramować nasze Arduino poniższym programem:
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 7
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&amp;amp;oneWire);
double val = 0;
void setup(void)
{
Serial.begin(115200);
sensors.begin();
}
void loop(void)
{
sensors.requestTemperatures();
Serial.println("");
// usredniamy
val = 0;
for(int i = 0; i < 10; i++) {
val += sensors.getTempCByIndex(0);
delay(1000);
}
Serial.print(val/10);
}
Program wymaga nieco wytłumaczenia. W naszym programie wykorzystujemy bibliotekę DallasTemperature, którą można pobrać ze strony projektu. Pin Digital w programie ustawiony jest na 7, oczywiście możemy to sobie ustawić jak chcemy. W programie zaimplementowano proste uśrednianie 10 pomiarów, efektem czego na wyjściu mamy temperaturę podawaną co 1 sekundę.
Program do Arduino już mamy, teraz pora na oprogramowanie „klienckie” napisane w Pythonie:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pytemp.py
import serial
import time
ser = serial.Serial('/dev/ttyUSB0',115200, timeout=10)
read = ser.readline(eol="\r")
comp = read.split()
ser.close();
if comp == [] or comp[0] == '-127.00':
time.sleep(1)
else:
print time.strftime("%Y-%m-%d %H:%M:%S"), comp[0]
Wykorzystujemy bibliotekę pyserial i standardową „time”. Należy pamiętać, aby w programie klienckim używać takiej samej prędkości transmisji co w Arduino. Program odczytuje temperaturę i sprawdza czy nie jest wartością pustą oraz czy nie równa się -127. Wartość -127 oznacza, że są jakieś problemy z czujnikiem. W momencie, gdy odczytana zostanie poprawna wartość wyświetlana jest data godzina i nasza temperatura. Wygląda to mniej więcej tak:
2010-03-07 10:06:11 22.56
Mamy już program do odczytu potrzebnych nam danych, teraz trzeba to zautomatyzować. Do tych celów najlepszy jest cron. Dodajemy następującą regułkę
*/5 * * * * /scieczka/do/pytemp.py >> /home/user/temp.txt
Innymi słowy odczytaj temperaturę co 5 minut i zapisz w /home/user/temp.txt.
Pozostaje teraz wykorzystać coś do zobrazowania naszych pomiarów. Możliwości jest klika. Skupię się jednak na gnuplocie, który jest prosty w konfiguracji, poza tym generuję ciekawe wykresy. Posłużę się tutaj skryptem znalezionym na forum eko.one.pl[4]
#!/bin/sh
GNUPLOT_COMMAND="/tmp/gnuplot_cmd"
touch ${GNUPLOT_COMMAND}
cat > ${GNUPLOT_COMMAND} << __EOF__
set terminal png small size 800,500
set output '/home/user/temp.png'
set title "Wykres temperatury"
set xlabel "godzina"
set timefmt "%Y-%m-%d %H:%M:%S"
set xdata time
set ylabel "temperatura °C"
set format x "%H"
set grid
set key left
plot '/home/user/temp.txt' using 1:3 t 'dane rzeczywiste' with lines lt 1
quit
__EOF__
gnuplot ${GNUPLOT_COMMAND}
rm ${GNUPLOT_COMMAND}
Skrypt generuje wykres w formacie png. Wykres będzie wykreślany ze wszystkich otrzymanych danych, dlatego dla czytelności wykresów warto dodać podział na tygodniowy, miesięczny. Podział taki zostanie tutaj niedługo opublikowany.
Efekt końcowy:
Linki warte przejrzenia:
[1] http://eko.one.pl/temp.html
[2] http://eko.one.pl/?p=openwrt-temperatura
[3] http://eko.one.pl/?p=Termometr
[4] http://eko.one.pl/forum/viewtopic.php?pid=1516#p1516
[5] http://www.gnuplot.info/docs/gnuplot.html
[6] http://msos.igf.fuw.edu.pl/Nicefit/gnuplot.pdf


Opera/9.80 (Windows NT 6.1; U; pl) Presto/2.5.24 Version/10.53
Witam!
Mam pytanie- robię we podobny projekt tylko z 3 czujnikami. Chcę wyświetlać dane na wyświetlaczu i na serialu. Niestety, na LCD mam tylko „krzaczki”.
#include
#include
#include
#define ONE_WIRE_BUS 9
OneWire oneWire(ONE_WIRE_BUS);
LiquidCrystal lcd(5, 4, 3, 2, 1, 0);
DallasTemperature sensors(&oneWire);
void setup(void)
{
Serial.begin(9600);
lcd.begin(16, 2);
sensors.begin();
}
void loop(void)
{
float temp1=0, temp2=0, temp3=0;
Serial.print(„Requesting temperatures…”);
sensors.requestTemperatures();
delay(250);
temp1=sensors.getTempCByIndex(0);
temp2=sensors.getTempCByIndex(1);
temp3=sensors.getTempCByIndex(2);
Serial.println(„DONE”);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(temp1);
Serial.println(temp1);
lcd.setCursor(7,0);
lcd.print(temp2);
Serial.println(temp2);
lcd.setCursor(0,1);
lcd.print(temp3);
Serial.println(temp3);
delay(500);
}
Czy mój błąd może wynikać z tego, że próbuje podać zmienną typu float na LCD? Wnioskuje tak, ponieważ jeżeli temperaturę podaję tylko na LCD za pomocą: lcd.print(sensors.getTempCByIndex(0);) to program działa prawidłowo.