Ott 072012
 

Nella scorso articolo abbiamo visto come creare un convertitore 1wire- RS232, oggi estendiamo l’argomento e colleghiamo il sensore DS18B20 direttamente ad Arduino. Se ricordate, avevamo detto che le porte digitali di Arduino sono l’ideale per collegare direttamente questo tipo di sensori dato che forniscono segnali da 0 a 5V nativamente, senza nessuna interposizione di alcun tipo di adattatore. Tutto ciò che ci servirà sarà, oltre ad Arduino, il sensore, qualche centimetro di cavo e una resistenza da 4.7K. In questo primo articolo vediamo  come fare i collegamenti ed il software mentre in un secondo articolo vedremo come usare l’ethernet shield per inviare i dati ad un web-server per visualizzare i dati raccolti tramite una pagina web.

Lo schema di collegamento è molto semplice ed è riassunto qui sotto; in particolare vi ho allegato sia lo schema con alimentazione diretta del sensore che con alimentazione parassita. Mi raccomando, in quest’ultimo caso, di mettere a massa il pin Vdd (il terzo), ve lo dico perchè in rete ho trovato degli schemi sbagliati in cui questo pin è lasciato vuoto, senza collegamenti.

Come vedete nulla di complicato, con una bradbord ci vuole davvero pochissimo tempo per collegare il sensore. Il software invece è un po’ più complicato rispetto ai precedenti esempi di base. Se ricordt l’articolo introduttivo u 1-wire, ricorderete che accennavo ai timing nella comunicazione con il sensore. Infatti la comunicazione avviente inviando sequenze di bit con tempistiche ben precise. Non preoccupatevi, non è mia intenzione entrare in questo lungo capitolo, ma capirete che se dovessimo fare tutto da noi dovremmo iniziare a studiare il bus 1wire, i suoi timing ed iniziare a preparare il software di comunicazione, lavoro tutt’altro che semplice. Per fortuna però c’è chi questo lavoro l’ha già fatto per cui non ciresta che scaricare la libreria già pronta. Per farlo andate sulla pagina per il download, scaricate la libreria e scompattatela direttamente nella directory libraries che trovate nel toolkit di sviluppo di arduino, quindi ci sarà una nuova cartella OneWire in mezzo alle pre-esisteniti SPI,SD,Ethernet,Servo,etc.

Il software funziona in questo modo: nella fase di inizializzazione scansiona il bus 1wire alla ricerca dei sensori connessi. Fra essi verifica quali sono i sensori di temperatura e ne memorizza gli indirizzi in un array. Finita questa fase entra nel loop principale nel quale và a leggere la temperatura di tutti i sensori per poi attendere 5 secondi e riprendere il ciclo di lettura. Le temperature vengono inviate sulla porta seriale dopo il codice esadecimale del singolo sensore.

Nella parte iniziale del software vediamo l’inclusione di OneWire.h che va’ appunto ad includere la libreria 1Wire che avevamo scaricato precedentemente. Nelle riche successive vengono definite alcune variabili globali che sono G_addr dimensionata per memorizzare gli indirizzi di 10 sensori e G_Devices che memorizza quanti sensori sono presenti nel bus. Si noti, poche istruzioni più in basso, il costruttore OneWire ow(8);  che definisce l’oggetto per la comunicazione col bus 1wire e che nello specifico caso indica essere collegato al pin digitale numero 8.

Il software utilizza la funzione lookUpSensors per la ricerca dei sensori sul bus. Purtroppo non abbiamo ancora sufficienti conoscenze sul funzionamento del bus per poter comprendere esattamente come funziona, vedremo in uno specifico articolo i dettagli più complessi, per ora basti comprendere che questa funzione memorizza gli indirizzi dei sensori trovati sul bus durante l’inizializzazione. Altre funzioni presenti nel software sono PrintAddress che si occupa di stampare l’indirizzo esadecimale di un sensore sulla porta seriale e GetTemp che dato l’indirizzo di un sensore e l’oggetto OneWire associato, restituisce la temperatura rilevata. Anche questa funzione risulta incomprensibile senza aver prima approfondito il funzionamento del bus, per cui per ora non ci resta che adattarci al semplice copia e incolla. Ho commentato i punti salienti del listato per migliorarne la comprensione.

#include <OneWire.h>

byte G_addr[10][8]; //qui memorizzo fino a 10 indirizzi
byte G_Devices; // variabile usata per tenere traccia del numero di sensori riconosciuti nel bus
OneWire ow(8); // inizializza il bus onewire sulla porta n°8 (se avete collegato i sensori su un'altro pin dovete modificare qui)

float GetTemp(OneWire *,byte *);
void PrintAddress(byte *);
void lookUpSensors();
int CheckSensor(byte *);

void setup(void)
{
Serial.begin(9600);// inizializza la porta seriale a 9600
G_Devices=0;      // imposta a 0 il numero di sensori attualmente riconosciuti
lookUpSensors(); // avvia la ricerca delle sonde di temperatura
}

void lookUpSensors()
{
byte address[8]; // questo array conterrà l'indirizzo locale dei sensori

Serial.print("--Ricerca avviata--"); // avvia la ricerca e lo scrive sulla porta seriale

while (ow.search(address)) // loop finchè trova nuovi dispositivi
{
// Se il primo byte dell'indirizzo è 0x10, si tratta di una sonda DS18S20
// il primo byte dell'indirizzo identifica il tipo di sensore
// se  0x10 è un DS18S20, se è 0x28 è un DS18B20 (notare la S e B)
if (address[0] == 0x10 || address[0] == 0x28)
{
if(CheckSensor(address)==1) //crc ok
{
Serial.println("");
if (address[0] == 0x10) Serial.print("Found DS18S20 : "); // notare che la S invece che la B
else if (address[0] == 0x28) Serial.print("Found DS18B20 : ");
PrintAddress(address);
for(int aa=0;aa<8;aa++) G_addr[G_Devices][aa]=address[aa]; // copia l'indirizzo
G_Devices++; // incrementa il numero di devices memorizzati
}
}

}//end while
Serial.println("");
Serial.println("--Ricerca terminata--");
}

void loop(void)
{
float temperatura; // uso questa variabile per tenere la lettura della temperatura
for(int num=0;num<G_Devices;num++) // vado a leggere tutti i sensori registrati
{
temperatura=GetTemp(&G_addr[num][0]); // lego la temperatura
PrintAddress(G_addr[num]);
Serial.print(" -> ");
Serial.println(temperatura);
}
delay(5000); // aspetto 5 secondi prima di fare una nuova misurazione
}

float GetTemp(byte * addr)
{
byte present = 0;
byte data[12];
int i;
byte address[8];
for(i=0;i<8;i++) address[i]=*(addr+i); //copia l'indirizzo nella stringa locale
ow.reset();
ow.select(addr);
ow.write(0x44,1);         // start conversion, with parasite power on at the end
delay(1000);     // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ow.reset();

ow.select(addr);
ow.write(0xBE);         // Read Scratchpad

for ( i = 0; i < 9; i++) data[i] = ow.read();// we need 9 bytes //Serial.print(data[i], HEX);

int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;

double result;

LowByte = data[0];
HighByte = data[1];

TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000;  // test most sig bit

if (SignBit) TReading = (TReading ^ 0xffff) + 1; // 2's comp // negative

Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

Whole = Tc_100 / 100;  // separate off the whole and fractional portions
Fract = Tc_100 % 100;

result = Whole;
result += ((double)Fract/100);

if(SignBit) result *= -1;

return result;

}

void PrintAddress(byte * address)
{
int i;
for (i=0;i<8;i++)
{
if (address[i] < 9) Serial.print("0");
Serial.print(address[i],HEX);
if (i<7) Serial.print("-");
}
}

int CheckSensor(byte * address)
{
if (OneWire::crc8(address, 7) != *(address+7)) return(-1);// faccio il controllo del CRC8, se fallito ritorno -1
else return(1); // cr8 OK, ritorno 1
}

Se avete compilato ed inviato la sketch ad Arduino, potete aprire il monitor seriale e vedrete una schermata simile alla seguente. Nel mio caso ci sono due sensori; ogni 5 secondi viene rilevata la temperatura e scritta vicino al codice esadecimale del sensore. Mi rendo conto di aver trattato in modo superficiale l’intimo funzionamento del bus, ma vorrei che trasparisse che pur non conoscendo il reale funzionamento di questi sensori, con pochi fili ed un sensore collegati ad Arduino conditi con poche linee di codice che potete benissimo copiare ottenete un termometro digitale. Potreste obiettare che con un sensore analogico la via sarebbe molto più semplice, certo, ma come li collegate 100 sensori? Secondo me il nocciolo della questione è questo:  se vi serve un sensore unico posizionano vicino al vostro Arduino allora meglio usare un  sensore analogico, ma se pensate di mettere una miriade di sensori in giro per la casa il bus 1-wire è sicuramente la soluzione giusta per voi. Inoltre non dimentichiamoci che sul bus 1-wire possono essere collegati altri tipo di sensori / dispositivi e non solo sensori di temperatura.

Se unite i contenuti di questo articolo con quello in cui si spiegava il collegamento di un relè ecco che ne salta fuori un termostato che potete tranquillamente usare magari per sostituire un vechio termostato analogico. Certo sarebbe meglio aggiungere un display e almeno un potenziometro per regolare la temperatura, ma già così com’è potrebbe essere usato come un rudimentale termostato a temperatura fissa.

  8 Responses to “Arduino e sensore 1wire DS18B20”

  1.  

    ciao, innanzitutto, complimenti per il sito e per i progetti interessantissimi.e’ possibile nella schermata seriale sostituire i codici deisensori con un nome?
    mi piacerebbe aggiungere un display ed un paio di relais ma non riesco a capire come integrarli (a livello di sketch)
    grazie mille e di nuovo, complimenti

    •  

      Ciao. Immagino che con “nome” intendi qualcosa tipo “temperatura esterna”, o “temperatura bagno”, etc. Certo che puoi farlo, ma ti sarà meno semplie del previsto. La via più semplice è quello di scovare le varie ROM dei sensori collegati, poi modificare la sketch in modo che se riconosce quel valore fra quelli noti ti scrive il nome da te scelto, altrimenti lascia il numero della ROM. Devii perciò crearti un doppio array all’inizio per memorizzare sia gli indirizzo noti, sia le stringhe da stampare. A questo punto deve essere modificata la funzione PrintAddress che per prima cosa deve verificare se la ROM è tra quelle conosciute e nel caso affermativo stampa il nome da te scelto, altrimenti scrive il codice della ROM. Il lato negativo di questo approccio è che per ogni sensore aggiunto devi modificare la sketch. L’alternativa è sfruttare la porta usb per comunicare con la sketck, in questo caso si potrebbe configurare Arduino per accettare comandi dall’esterno e quindi diventerebbe possibile modificare, aggiungere o rimuovere i nomi direttamente da PC, ma ciò implica un maggior numero di modifiche. Uno dei prossimi progetti sarà proprio un termostato con display, però non ho il materiale in casa per cui devo prima reperire i materiali che mi servono.
      Per quanto riguarda l’applicazione pratica ti consiglio di aggiungere due array all’inizio, uno di tipo byte G_addr_Noti[10][8]; ed uno G_addr_Nomi[10][30]; // previsti 30 caratteri per nome. Poi nella fase di inizializzazione copi metti i nomi delle ROM note nel primo array (mettendo a 0 quelle che non usi) e nell’altro ci metti i nomi. Poi nella PrintAddress fai prima un confronto per verificare la presenza o meno fra le ROM note e con un if decidi se stampare il nome o la ROM. Se non ti bastano queste notizi fammi sapere, magari faccio io le modifiche e le metto in un articoletto di approfondimento.

      •  

        Intanto ottime spiegazioni e complimenti, mi interessa molto per la domotica della mia casa per controllare le temperature ambientali e regolarle usando arduino come termostato che controlla le valvole dei termosifoni (on off delle mandate) .
        Mi interessa moltissimo questa modifica del nome.

  2.  

    Ciao e vivissimi complimenti!
    Quanti sensori si riescono a leggere con la configurazione da te descritta? C’è un limite fisico oppure se ne possono mettere abbastanza da riempire tutta la casa?
    Grazie

    •  

      Grazie per i complimenti, mi fanno sempre molto piacere.
      Per quanto riguarda la tua domanda, la risposta era esposta nella breve descrizione del bus 1-wire che ho fatto nell’articolo che trovi al seguente indirizzo: http://www.mcmajan.com/mcmajanwpr/?p=971 . Comunque a meno che tu non abbia un castello come casa, i limiti del bus 1wire sono trscurabili. In rete esiste una guida tecnica molto dettagliata su come calcolare il numero di sensori in rapporto alla configurazione della rete 1-wire ma è molto tecnico e necessita di conoscenze più approfondite che in parte vengono descritte in 3 articoli successivi a questo, dove di parla di 1 wire e porta seriale. Comunque, senza scendere in dettagli, la cosa migliore è ricordare che possiamo mettere 100 sensori entro 100 metri di distanza; è sicuramente un’approsimazione ma va più che bene per capire se rientriamo nei limiti del nostro progetto. Ricorda che questi sono limiti per singola linea ma nessuno ci vieta di usare in contemporanea più linee in parallelo anche su singolo Arduino. S hai altre domande scrivi pure, magari con qualche giorno di ritardo ma rispondo sempre.

    •  

      If you can’t manage to get the etirne circuit flexible, a compromise would to make the strips connecting the boards to be flexible. Key Factor: Since its flexible, the number 1 priority should be durability. These boards should last as long as the normal Arduino boards, or your customers will feel cheated. To do this, you may need to compromise on flexibility so that perhaps each square is stiff, but the ribbon connecting them is flexible.Potential Uses: I think I would put it on a RC battery inside of an RC car. They have pretty small dimensions, but since this board is so small, I would be able to squeeze it where any other board wouldn’t fit. I would then connect the driving servo and the motor controller (ESC) to it and drive it around I would then put a review up on my site, showing the flexibility and durability of the newest Arduino.

  3.  

    Ciao, quali altri sensori 1-wire possono essere collegati ? Esiste un elenco completo ?