Nov 272012
 

Oggi vediamo come funziona il sensore DS18B20 e come misurare e leggere la temperatura usando l’interfaccia seriale. L’articolo darà per scontato che si siano letti i due precedenti articoli, primo che descrive nel dettaglio i timing del bus 1wire e la correlazione con l’RS232 ed il secondo in cui è spiegato il codice C per comunicare con il bus 1Wire. Non mi ripeterò sull’adattatore seriale ed il collegamento del sensore in quanto abbiamo già affrontato l’argomento in questo articolo.

La memoria del DS18B20

Cominciamo perciò a valutare la parte più importante, ossia l’organizzazione della memoria del sensore che è disposta come da figura qui a lato. Tecnicamente viene chiamata Scratchpad che potremmo tradurre con “Bloc Notes” ed è una memoria di 8bytes più un byte di CRC. Come vedete dalla figura il byte 8 è occupato dal CRC e quelli compresi fra il 5 e 7 sono riservati, motivo per cui quelli di nostro interesse vanno da 0 a 4. I byte 0 e 1 contengono il dato di temperatura. E’ importante sapere che dopo un reset questi due byte contengono il valore 85 per cui, a meno di casi incredibili in cui la temperatura è esattamente 85 gradi celsius, la lettura di questo valore indica che il sensore ha subito un comando reset ma non ha mai ricevuto un comando di lettura della temperatura. Questo ci fà capire che per leggere la temperatura dobbiamo fare due operazioni distinte, ossia prima dobbiamo dire al sensore di misurare la temperatura e metterla in quei due byte di memoria, e poi fare un’operazione di lettura della memoria per leggere quel valore.

Poi ci sono due bytes che possono essere usati in due modi diversi. Infatti può essere impostata una soglia di temperatura minima e massima che viene mantenuta anche allo spegnimento del sensore e che se oltrepassate mettono il sensore “in allarme”. Un sensore “allarmato” può rispondere a determinati comandi e permette ricerche sul bus preferenziali, ad esempio un software anzichè misurare tutte le temperature di tutti i sensori sul bus potrebbe fare solamente una ricerca dei sensori “allarmati” e procedere di conseguenza. Noi non andremo ad utilizzare questa funzione, ma è utile sapere che se non viene usata si possono usare quei due byte per inserire dati a nostro piacimento.

Il registro i configurazione anche se composto da 8 bit, ne ha 6 riservati e due (5 e 6) che determinano il grado di precisione della misurazione della temperatura, che può essere di 9,10,11 o 12 bit. Il valore di default all’accensione è 12bit. Nella tabella a lato viene chiarito come al variare dei bit 5 e 6, contrassegnati con R0 e R1, varia non solo la risoluzione di lettura della temperatura, ma anche il tempo di conversione che raddoppia per ogni bit aggiuntivo. Un’ultima nota riguada il CRC che comprende i bytes precedenti e come tale cambia ad ogni lettura della temperatura.

In realtà in questo articolo non andremo ad approfondire tutti i dettagli, andiamo infatti a vedere unicamente come misurare e leggere la temperatura senza complicarci troppo la vita con le varie possibili configurazioni. Lo schema della memoria del sensore è però indispensabile in quanto senza di esso ci diventa impossibile comprendere il funzionamento del software che andiamo ad analizzare fra poco.

Leggiamo la temperatura

Come dicevamo ci sono due fasi necessarie per leggere la temperatura. La prima implica che venga inviato un comando di conversione della temperatura che fa’ si che il sensore valuti la temperatura e la scriva nei byte 1 e 2 della sua memoria. La seconda fase è una fase di lettura, ossia il master và a leggere la temperatura precedentemente memorizzata. La cosa importante da comprendere è che se facciamo solo letture consecutive, la temperatura non cambia in quanto senza uno specifico comando il sensore non prende nessun tipo di iniziativa. Ora rivediamo gli stessi passi in modo leggermente più approfondito che poi andiamo a spiegare.

  • 1) Il master invia un impulso di reset sul bus
  • 2) I vari slave rispondono con il “Presence Pulse”
  • 3) Il master invia un comando “Mach ROM” 0x55
  • 4) Il master invia la ROM del sensore che vuole leggere
  • 5) Il master invia il comando 0x44 per la conversione di temperatura
  • 6) Il master invia un nuovo impulso di reset
  • 7) Gli slave rispondono con il “Presence Pulse”
  • 8) Il master invia un comando “Mach ROM” 0x55
  • 9) Il master invia la ROM del sensore che vuole leggere
  • 10) Il master invia un comando 0xBE per leggere la memoria del sensore
  • 11) Il master legge i 9 bytes della memoria e lo slave li invia sequenzialmente.

Per quanto riguarda il reset iniziale non credo ci sia più nulla da aggiungere rispetto a quanto già detto nei passati articoli, ricordiamo che la funzione da noi scritta si riduce ad un banale OWReset(). Al terzo punto vediamo come inviare un comando al sensore. Nel caso specifico il comando è il 0x55, detto mach rom. Dopo questo comando i sensori rimangono in attesa di riceve un codice rom a 64 bit. A questo punto il master invia la rom del sensore che vuole andare ad interrogare e lo slave che presenta quel codice resterà in attesa di ulteriori comandi mentre tutti gli altri andranno in uno stato di quiescenza sino al prossimo reset. Per la selezione della ROM ho scritto il comando OWRomSelect che come argomento prende appunto un buffer con gli 8 byte della ROM che nel nostro software visto al precedente articolo sono memorizzati nell’iniziale scansione del bus. La funzione è così composta:

void OWR::OWRomSelect(char * address)
{
  OWWriteByte(0x55); //mach rom
  for (int xx=0;xx<8;xx++) OWWriteByte(address[7-xx]);
}

Come vedete viene prima inviato il comando con la funzione OWWriteByte e, successivamente, con la stessa funzione vengono inviati tutti i byte della ROM, a partire dal byte meno significativo che è nell’ultima posizione, al più significativo che è nella posizione zero.

A questo punto viene inviato il comando 0x44 per la conversione della temperatura che sarà eseguito unicamente dallo slave che avevamo prima selezionato. Qui dobbiamo fare però un’aggiunta importante. Abbiamo visto dalla tabella sopra che la fase di conversione della temperatura con una risoluzione di 12 bit dura 750ms. In questa fase non devono essere inviati comandi sul bus, inoltre, se il nostro sensore è alimentato in modalità passiva, dobbiamo tenere il sensore alimentato per tutto questo tempo. Per farlo è sufficiente tenere la linea ad un valore alto, cosa a cui pensa la resistenza di pullup. Noi ci limitiamo unicamente ad inserire un’attesa nel nostro software: io ho impostato un secondo. Se non rispettate questo tempo avrete risultati del tutto imprevedibili, nelle mie prove, ad esempio, avevo un sensore che convertiva correttamente la temperatura, mentre tutti gli altri restavano al valore di reset di 85 gradi.

A questo punto faccio un nuovo reset, invio di nuovo il comando di mach rom e poi invio il comando di lettura della memoria (0xBE). A questo punto il master usa la funzione OWReadByte per 9 volte in modo da leggere la memoria del sensore un byte alla volta.  Fatto ciò abbiamo copia della memoria del sensore nella RAM del nostro PC e dobbiamo solamente interpretare i valori digitali per trasformarli in un valore analogico.

Ricordo che le tabelle che riporto sono sempre prese dalla documentazione ufficiale. Se guardate in rete troverete un sacco di algoritmi per trasformare il valore binario in una temperatura comprensibile a noi umani, ma tenete conto che la maggior parte di questi algoritmi deriva dal fatto che sono stati originariamente impiegati in vari processori e come tali sono ottimizzati per usare il minor numero di risorse possibile. Indipendentemente dalla piataforma, però, i primi due passi sono uguali per tutti. Per prima cosa dobbiamo unire i due bytes in un unico intero a 16 bit, per farlo è sufficiente un’istruzione del tipo TReading = (HighByte << 8) + LowByte; dove HighByte e LowByte nella figura sopra sono rispettivamente chaimati MS e LS. Fatto ciò verifichiamo il segno con un semplice SignBit = TReading & 0x8000; e nel caso il numero sia negativo procediamo con il complemento a 2 del numero (if (SignBit) TReading = (TReading ^ 0xffff) + 1;). Credo che per chi legge questi tutorial sappia cos’è il complemento a 2 per cui non mi soffermo sull’argomento, in caso contrario ci sono un sacco di spiegazioni in rete.

Una volta raggiunto questo punto il discorso è in discesa. Sapendo che la risoluzione di questo sensore è di 0.0625 gradi celsius, basta moltiplicare questo valore per quello che abbiamo estratto dalla memoria del sensore dopo il complemento a due. Per finire, se il segno è negativo, negativizziamo il risultato ed il tutto è completo

void OWR::OWReadTemp()
{
  int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
  double result;
  unsigned char mybyte[9];

  for(int kk=0;kk<OWbus->DeviceCount;kk++)
  {
    if(!OWReset()) continue;
    OWRomSelect((char*)&OWbus->ROM[kk][0]); // seleziono la ROM
    OWWriteByte(0x44); // avvia conversione temperatura
    wxThread::Sleep(1000); // linea alta per 1000ms

    if(!OWReset()) continue; // nuovo reset
    OWRomSelect((char*)&OWbus->ROM[kk][0]); // seleziona rom
    OWWriteByte(0xBE); // comando lettura memoria sensore

    for(int z=0;z<9;z++) mybyte[z]=OWReadByte(); //leggo la memoria

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

    TReading = (HighByte << 8) + LowByte;  // unisco i due bytes
    SignBit = TReading & 0x8000;  // testo il bit più significativo
    if (SignBit) TReading = (TReading ^ 0xffff) + 1; //  complemento a 2

    result=TReading*0.0625;  // ottengo la temperatura in celsius

    if(SignBit) result *= -1;  // eventualmente inverto il segno

    temp[kk]=result;  // e la memorizzo in un array
    Txt->AppendText("Temperatura: "+FloatTowxT(result));
  } // for

}

Con questo abbiamo concluso la serie introduttiva di articoli sul bus 1wire. Spero abbiate apprezzato questi articoli visto che in rete non si trovano molti approfondimenti nella nostra lingua e spesso gli articoli in inglese non sono altro che la copia uno dell’altro, scritti in maniera superficiale e poco approfondita.