Ο αισθητήρας DS18B20 (σκλάβος) μπορεί και επικοινωνεί με ένα μικροελεγκτή Arduino διαμέσου του πρωτοκόλλου 1-Wire. Σε αυτό το πρωτόκολλο, διάφοροι τύποι σημάτων ορίζονται: παλμός επαναφοράς, παλμός παρουσίας, εγγραφή του ψηφίου 0, εγγραφή του ψηφίου 1, διάβασμα του ψηφίου 0 και διάβασμα του ψηφίου 1. Σε αυτό το κείμενο, θεωρούμε την σύνδεση του μικροελεγκτή Arduino Nano με τον αισθητήρα DS18B20. Για να είναι ο κώδικας που θα γράψουμε κατανοητός και ξεκάθαρος, συνιστώ να χρησιμοποιήσετε τις επόμενες ντιρεκτίβες στην αρχή του προγράμματος σας για το Arduino, οι οποίες ορίζουν τις απαραίτητες σταθερές γι την καλή λειτουργία του sketch μας.
#define PIN 12
#define THERM_CMD_CONVERTTEMP 0x44
#define THERM_CMD_RSCRATCHPAD 0xbe
#define THERM_CMD_SKIPROM 0xcc
Επίσης θα χρειαστεί να εισάγουμε την βιβλιοθήκη, έτσι ώστε να μπορούμε μα απεικονίζουμε δεδομένα στην οθόνη lcd:
#include <LiquidCrystal.h>
Kαι πρέπει να δημιουργήσουμε το αντικείμενο:
LiquidCrystal lcd(0,1, 2, 3, 4, 5); // pins RS, E, DB4, DB5, DB6, DB7
Προσοχή: τα ορίσματα PS, E, DB4, DB5, DB6, DB7 εξαρτούνται με τον τρόπο που συνδέουμε το Arduino με την οθόνη υγρών κρυστάλλων.
Για να μπορέσει το lcd να επικοινωνήσει με το Arduino, για την απεικόνιση της θερμοκρασίας, είναι απαραίτητες οι επόμενες συναρτήσεις:
void thermInputMode(){
pinMode(PIN, INPUT);
}
void thermOutputMode(){
pinMode(PIN, OUTPUT);
}
void thermLow(){
digitalWrite(PIN, 0);
}
void thermHigh(){
digitalWrite(PIN, 1);
}
ΑΡΧΙΚΟΠΟΙΗΣΗ: ΠΑΛΜΟΙ ΕΠΑΝΑΦΟΡΑΣ ΚΑΙ ΠΑΛΜΟΙ ΠΑΡΟΥΣΙΑΣ
Όλη η επικοινωνία με το DS18B20 αρχίζει με τη διαδικασία αρχικοποίησης που αποτελείται από την αποστολή του παλμού επαναφοράς από τον αφέντη (μικροελεγκτή) ακολουθούμενος από τον παλμό παρουσίας από το DS18B20. Όταν ο αισθητήρας DS18B20 στείλει το παλμό παρουσίας σαν ανταπόκριση στο παλμό επαναφοράς του αφέντη, ο σκλάβος (DS18B20) γνωστοποιεί στον αφέντη ότι είναι πάνω στον δίαυλο δεδομένων και ότι είναι έτοιμος να λειτουργήσει.
Κατά τη διάρκεια της διαδικασίας αρχικοποίησης ο αφέντης μεταδίδει (ΤΧ) τον παλμό επαναφοράς με τράβηγμα του 1-Wire διαύλου δεδομένων σε κατάσταση low, το λιγότερο για χρονικό διάστημα 480μs. Μετά ο αφέντης ελευθερώνει το δίαυλο δεδομένων και μπαίνει σε κατάσταση διαβάσματος (RX). Καθώς ο δίαυλος δεδομένων ελευθερώνεται η 5ΚΩ αντίσταση pull-up τραβά τον 1-Wire δίαυλο δεδομένων σε κατάσταση high. Όταν το DS18B20 ανιχνεύσει αυτή την ακμή της ανόδου της τάσης, περιμένει για χρονικό διάστημα από 15μs έως 60μs και μετά μεταδίδει τον παλμό παρουσίας, τραβώντας τον 1-Wire δίαυλο δεδομένων σε κατάσταση low για χρονικό διάστημα από 60μs έως 240μs.
Ο κώδικας σε γλώσσα Arduino της παραπάνω διαδικασίας αρχικοποίησης, δίνεται παρακάτω:
byte thermReset(){
noInterrupts();
byte i;
thermOutputMode();
thermLow();
delayMicroseconds(480);
thermInputMode();
delayMicroseconds(60);
i=digitalRead(PIN);
delayMicroseconds(420);
interrupts();
return i;
}
READ/WRITE SLOTS
Ο αφέντης γράφει δεδομένα στο DS18B20 κατά τη διάρκεια “write time slots” και διαβάζει δεδομένα από το DS18B20 κατά τη διάρκεια “read time slots”. Ένα bit δεδομένων μεταφέρεται πάνω στον 1-Wire δίαυλο δεδομένων κατά τη διάρκεια ενός “write time slot” ή ενός “read time slot”
Write time slots
Υπάρχουν δυο τύποι “write time slots” το “write 1” και το “write 0”. Ο αφέντης χρησιμοποιεί το “write 1 time slot” για να γράψει το λογικό 1 στο DS18B20 και το “write 0 time slot” για να γράψει το λογικό 0 στο DS18B20. Όλα τα “write time slots” πρέπει να έχουν το λιγότερο χρονική διάρκεια 60μs και το λιγότερο 1μs χρονική απόσταση μεταξύ δυο ανεξάρτητων “write slots”. Και οι δυο τύποι “write slots” αρχίζουν από τον αφέντη τραβώντας την 1-Wire γραμμή δεδομένων σε κατάσταση low.
Για τη δημιουργία του “write 1 time slot” ο αφέντης τραβά την 1-Wire γραμμή low και θα πρέπει να την ελευθερώσει μετα από χρόνο 15μs. Καθώς η γραμμή ελευθερώνεται, η 5ΚΩ pull-up αντίσταση τράβα το δίαυλο δεδομένων σε κατάσταση high. Για την δημιουργία του “write 0 time slot” μετά το τράβηγμα από τον αφέντη τη γραμμή δεδομένων σε κατάσταση low, ο αφέντης πρέπει να συνεχίσει να την κρατά σε κατάσταση low για χρονικό διάστημα ενός “time slot” (το λιγότερο 60μs). Το DS18B20 δειγματοληπτεί την 1-Wire γραμμή δεδομένων κατά την διάρκεια ενός χρονικού παραθύρου που διαρκεί από 15μs εως 60μs μετά που ο αφέντης αρχίζει το “write time slot” Εάν η γραμμή δεδομένων είναι σε κατάσταση high κατά τη διάρκεια του δειγματοληπτικού παραθύρου, το λογικό 1 γράφεται στο DS18B20. Εάν η γραμμή δεδομένων είναι σε κατάσταση low, το λογικό 0 γράφεται στο DS18B20.
Read time slots
Το DS18B20 μπορεί να μεταδίδει δεδομένα στον αφέντη, όταν ο αφέντης δημιουργεί “read time slots”. Επομένως ο αφέντης δημιουργεί “read time slots” αμέσως μετά την εντολή Read Scratchpad [Beh] ή Read Power Supply [B4h], έτσι ώστε το DS18B20 να παρέχει τα αιτούμενα δεδομένα. Επιπρόσθετα ο αφέντης μπορεί να δημιουργήσει “read time slot” μετά την εντολή Convert T [44h] ή την Recall E2 [B8h] για να ανιχνεύσει την κατάσταση εκτέλεσης εντολής στο DS18B20.
Όλες οι “read time slots” πρέπει να έχουν το λιγότερο χρονική διάρκεια 60μs και το ελάχιστο χρονικό διάστημα 1μs μεταξύ των “read slots”. Ένα “read time slot” αρχίζει από τον αφέντη τραβώντας την 1-Wire γραμμή δεδομένων σε κατάσταση low το λιγότερο 1μs και μετά ο αφέντης ελευθερώνει την γραμμή (βλέπε το διάγραμμα). Μετά που ο αφέντης αρχίσει ένα “read time slot”, το DS18B20 ανταποκρίνεται μεταδίδοντας το λογικό 1 ή το λογικό 0 στη γραμμή δεδομένων. Το DS18B20 μεταδίδει το λογικό 1 αφήνοντας τη γραμμή δεδομένων σε κατάσταση high και μεταδίδει το λογικό 0 τραβώντας τη γραμμή δεδομένων σε κατάσταση low. Όταν μεταδίδει το λογικό 0 το DS18B20 θα ελευθερώσει τη γραμμή δεδομένων στο τέλος του “time slot” και τότε η γραμμή δεδομένων θα τραβηχτεί σε κατάσταση high με την pull-up αντίσταση μπαίνοντας σε αδρανή κατάσταση. Τα δεδομένα από την έξοδο του DS18B20 είναι έγκυρα για 15μs μετά την πτώση σε low της αρχής του “read time slot”. Επομένως, ο αφέντης πρέπει να ελευθερώσει τη γραμμή δεδομένων μέσα σε χρόνο 15μs μετά την αρχή του “read time slot” και μετά να δειγματοληπτήσει τη γραμμή δεδομένων.
ΛΕΙΤΟΥΡΓΙΑ READ / WRITE
Θα σας δείξουμε πως να κάνετε συναρτήσεις στην Arduino, οι οποίες θα γράφουν και θα διαβάζουν ανεξάρτητα bits από το DS18B20 και μετά άλλες συναρτήσεις με τις οποίες διαβάζουν και θα γράφουν ολόκληρα bytes.
Διαβάζοντας / γράφοντας ανεξάρτητα bits
Κατά την διαδικασία εγγραφής, τραβάμε τη γραμμή δεδομένων σε κατάσταση low κατά το ξεκίνημα. Εάν θέλουμε να γράψουμε το λογικό 0 θα κρατήσουμε τη γραμμή δεδομένων σε κατάσταση low μέχρι το τέλος της χρονικής διάρκειας (60μs), αλλά αν θέλουμε να γράψουμε το λογικό 1, μετά την αρχή με μια καθυστέρηση 1μs ελευθερώνουμε τη γραμμή. Μια υλοποίηση σε γλώσσα Arduino δείχνεται ακολούθως.
void thermWriteBit(byte num){
noInterrupts();
thermOutputMode();
thermLow();
delayMicroseconds(2);
if(num) thermInputMode();
delayMicroseconds(60);
thermInputMode();
interrupts();
}
Από την άλλη μεριά, έχουμε τη διαδικασία διαβάσματος. Είναι αρκετά όμοια, αλλά έχει μερικές διαφορές. Ξεκινάμε τραβώντας τη γραμμή δεδομένων σε κατάσταση low για χρονικό διάστημα 1μs. Μετά πρέπει να ελευθερώσουμε τη γραμμή δεδομένων και να περιμένουμε για 14μs (14+1=15μs όπως φαίνεται στο διάγραμμα). Μετά από αυτό, μπορούμε να διαβάσουμε την τιμή της γραμμής δεδομένων, η οποία θα είναι σε κατάσταση high όταν το DS18B20 μεταδίδει το λογικό 1 και σε κατάσταση low όταν μεταδίδει το λογικό 0. Στο τέλος πρέπει να περιμένουμε 45μs μέχρι το τέλος του χρονικού διαστήματος των 60μs. Μια υλοποίηση σε γλώσσα Arduino δείχνεται ακολούθως.
byte thermReadBit(){
nointerrupts();
byte num=0;
thermOutputMode();
thermLow();
delayMicroseconds(2);
thermInputMode();
delayMicroseconds(14);
if(digitalRead(PIN)) num=1;
delayMicroseconds(45);
interrupts():
return num;
}
Διαβάζοντας / γράφοντας bytes
Τώρα που μπορούμε να διαβάσουμε ή να γράψουμε ανεξάρτητα bits, για να διαβάσουμε ή η να γράψουμε bytes είναι αρκετά εύκολο: Κάνουμε βρόγχους των οκτώ κύκλων και αποθηκεύουμε τα αποτελέσματα σε μια μεταβλητή. Μια υλοποίηση σε γλώσσα Arduino δείχνεται ακολούθως.
byte thermReadByte(){
noInterrupts();
byte i=8, n=0;
while(i--){
n>>=1;
n|=(thermReadBit()<<7);
}
interrupts();
return n;
}
void thermWriteByte(byte num){
noInterrupts();
byte i=8;
while(i--){
thermWriteBit(num&1);
num>>=1;
}
interrupts();
}
ΤΟ ΤΕΛΕΥΤΑΙΟ ΒΗΜΑ: ΔΙΑΒΑΖΟΝΤΑΣ ΤΗ ΘΕΡΜΟΚΡΑΣΙΑ
Τώρα που μπορούμε να γράψουμε και να διαβάσουμε από το θερμόμετρο DS18B20, είναι ώρα να μάθουμε πως να διαβάζουμε τη θερμοκρασία. Η θερμοκρασία αποθηκεύεται στα πρώτα δυο bytes της περιοχής μνήμης του D18B20, η οποία είναι μεγέθους εννέα bytes. Τώρα είναι η ώρα να κάνουμε υλοποίηση της διαδικασία διαβάσματος της θερμοκρασίας σε γλώσσα Arduino.
Όλες οι απαραίτητες συναρτήσεις για το διάβασμα της θερμοκρασίας από τον αισθητήρα και η απεικόνιση της στην οθόνη lcd βρίσκονται μέσα στη συνάρτηση loop() οι οποίες εκτελούνται επαναλαμβανόμενα κάθε ενα δευτερόλεπτο με την απεικόνιση της θερμοκρασίας.
Ο κώδικας που ακολουθεί λειτουργεί για ένα αισθητήρα DS18B20 στην γραμμή δεδομένων και διαμορφώθηκε για ανάλυση 12-bits.
void loop() {
thermReset();
thermWriteByte(THERM_CMD_SKIPROM);
thermWriteByte(THERM_CMD_CONVERTTEMP);
while(!thermReadBit());
thermReset();
thermWriteByte(THERM_CMD_SKIPROM);
thermWriteByte(THERM_CMD_RSCRATCHPAD);
tempLow=tempHigh=0;
tempLow=thermReadByte();
tempHigh=thermReadByte();
tempValue=0;
tempValue = tempLow>>4;
tempValue |= ( (tempHigh & 7) << 4);
lcd.clear();
lcd.print(tempValue, DEC);
delay(1000);
}
Στη συνάρτηση setup( ) αρχικοποιούμε και καθαρίζουμε την μονάδα απεικόνισης Lcd οπως φαίνεται στον ακόλουθο κώδικα:
void setup() {
lcd.begin(16, 2);
lcd.clear();
}
Εγγραφή κώδικα
Τα παραπάνω κομμάτια κώδικα μπορείτε να τα ενώσετε μαζί για γράψετε ένα sketch για το Arduino που θα μετρά τη θερμοκρασία περιβάλλοντος με τον αισθητήρα τύπου DS18B20
Για να μπορέσετε να μετρήσετε τη θερμοκρασία πιο εύκολα τοποθετήστε τις συναρτήσεις σε μια βιβλιοθήκη που θα πρέπει να την ενσωματώσετε στο περιβάλλον Arduino IDE. Μπορείτε να την κατεβάσετε κάνοντας κλικ εδώ.
Τοποθετήστε το αρχείο zip που θα κατεβάσατε σε κάποια θέσει στον υπολογιστή σας και ενσωματώσετε το στο περιβάλλον Arduino με την εντολή Σχέδιο>Συμπερίληψη Βιβλιοθήκης>Προσθήκη βιβλιοθήκης ZIP.
Για να μετρήσουμε τη θερμοκρασία κάνοντας χρήση την καινούργια βιβλιοθήκη ds18b20pl γράψτε το ακόλουθο απόσπασμα κώδικα:
#include "ds18b20pl.h"
#include <LiquidCrystal.h>
LiquidCrystal lcd(0,1, 2, 3, 4, 5);
ds18b20pl temp(12);
byte temperature=0;
void setup() {
lcd.begin(16, 2);
lcd.clear();
}
void loop() {
temperature=temp.getTemperature();
lcd.clear();
lcd.print("Temperature");
lcd.print(temperature)
delay(1000);
}