Corso di programmazione PICMicro in C – Approfondimenti – Il bus One-Wire. Ricavare il ROM Code

In un articolo precedente abbiamo visto come interfacciare Arduino ad una sonda di temperatura DS18S20. Su Arduino l’impresa è stata abbastanza facile in quanto esistono librerie già pronte. Per par condicio ora vedremo ora come fare la stessa cosa con i picmicro, ma un po’ alla volta dal momento che personalmente non ho trovato librerie già pronte e fatte bene. A tal proposito riprendo le informazioni già scritte per il protocollo 1-wire (che è la modalità di comunicazione digitale utilizzata appunto dalla sonda di temperatura DS18S20) cercando di approfondirle in maniera da renderne chiaro il funzionamento e per poter essere d’aiuto nello scriversi una propria libreria anche per altri dispositivi che non siano necessariamente picmicro.

Per fare gli esempi mi riferirò al datasheet della sonda DS18S20

Il protocollo 1-wire, inventato dalla Dallas Semiconductor è sostanzialmente un protocollo di comunicazione seriale asincrono half-duplex: su di un unico filo viaggiano tutti i segnali (Tx e Rx) e non c’è una linea di clock. Una delle peculiarità di tale protocollo prevede che i dispositivi che la utilizzano possano funzionare anche in modalità parassita: la tensione di alimentazione può essere prelevata dalla stessa linea dati riducendo a 2 i fili necessari per il collegamento (GND + linea dati).

Questa funzione è molto più comoda di quello che possa sembrare. I dispositivi ibutton, ad esempio, che sono semplici “bottoni di memoria”, la sfruttano in maniera egregia: lo stesso case di rivestimento del bottone costituisce i due pin di collegamento.

La modalità di funzionamento parassita è ottenuta tramite un condensatore, interno al dispositivo, che si carica durante la transizione a livello logico alto della linea dati e quindi fornisce energia alla circuiteria interna per tutte le fasi successive. Questa funzione  in alcuni casi permette addirittura di eludere ancor più i disturbi dato che questi non possono essere captati dalla linea di alimentazione. Questa modalità, però, a volte può causare problemi in quanto alcune procedure potrebbero richiedere un tempo superiore al tempo di scarica del condensatore interno. Avviene in pratica che il condensatore si scarica mentre le operazioni non sono ancora terminate causando bei grattacapi (es.: casi in cui bisogna leggere e scrivere in celle di memoria eeprom che richiedono più tempo e un maggiore assorbimento). Questo problema può essere evitato in vari modi: vedremo tra poco come.

Il funzionamento del protocollo 1-wire concettualmente è abbastanza semplice: la linea dati è collegata ad I/O open-drain, per cui c’è una resistenza di pull-up, comune a tutti i dispositivi, che tiene la linea dati normalmente a livello logico alto (questa resistenza è in genere da 4.7KΩ).

In una linea di comunicazione 1-wire viene identificato un dispositivo Master (che gestisce le comunicazioni) e uno o più dispositivi Slave (che rispondono solo se interrogati). Non essendoci un clock i dispositivi dovranno comunicare in tempi prestabiliti (come avviene sulla RS232, con la sola differenza che qui non si può selezionare il baudrate e la linea di comunicazione è una sola). La restrizione su tali tempi diviene più forte nel caso in cui si utilizzi la modalità di alimentazione parassita: non possiamo correre il rischio che la sonda si trovi col condensatore scarico e quindi disalimentata.

Per evitare i problemi di scarica del condensatore in modalità parassita, si può fornire temporaneamente una situazione di “strong-pullup” ottenuta mediante un mosfet pilotato dal dispositivo master. Il mosfet in pratica, entrando in conduzione, elude la resistenza di pullup collegando la linea direttamente al positivo di alimentazione e garantendo, quindi, un maggior apporto di corrente:

Altre volte, invece, basta mettere una resistenza di pull-up di valore più basso. E’ comunque forse più facile alimentare il dispositivo in maniera normale senza complicarsi troppo la vita (e qualora il dispositivo lo permetta – l’iButton per esempio non lo permette):

I Tempi

Prima di cominciare ogni comunicazione, il dispositivo master deve emettere un segnale di reset. Il master configura il pin dedicato alla comunicazione come uscita e la linea dati viene tenuta a livello logico basso per almeno 480µS. Questa operazione serve ad indicare ai dispositivi presenti sul bus che è presente il Master ed è pronto per operare. Passato questo tempo, il master configura il pin come ingresso (alta impedenza) e si mette quindi in “ascolto”: in queste condizioni la linea si trova a livello logico alto grazie alla resistenza di pullup. Nel momento in cui i dispositivi sulla linea rilevano che dopo i 480µS di livello basso si ha una transizione a livello alto per almeno 15 – 60µS, allora inviano un impulso di presenza: portano la linea a livello basso per un tempo variabile tra 60 e 240µS. Il Master rileva questa condizione e capisce che sulla linea c’è almeno un dispositivo 1-wire:

La comunicazione sul bus 1-wire avviene per Time Slots, ovvero per “porzioni di tempo”. Ci sono i Time Slots di scrittura e i Time Slots di lettura. Un singolo Time Slot (sia esso di lettura o di scrittura) interessa un singolo bit di dati da trasferire, una comunicazione intera, quindi, è costituita da più Time Slots in sequenza.

Un time slot di scrittura dura dai 60 ai 120µS massimo. Quando dovrà essere trasmesso un bit ad 1 la linea dati viene tenuta a livello basso per massimo 15µS, per il resto del tempo la linea verrà tenuta alta dalla resistenza di pullup. Quando dovrà essere trasmesso un bit a 0 la linea dati viene tenuta a livello basso per massimo 60µS (quindi un tempo più alto). Tra un time slot e il successivo ci deve essere almeno 1µS di “recupero” in cui la linea viene tenuta a livello alto. Ogni bit, inoltre, viene inviato dopo aver messo la linea a livello basso per almeno 1µS:

I time slots di lettura sono complementari. Il Master “avvia” un time slot di lettura portando la linea a livello basso per almeno 1µS dopodichè rilascia il bus (ovvero si mette in stato di alta impedenza) consentendo ai dispositivi di prendere il controllo della linea e quindi rispondere. I dati inviati dai dispositivi slave dovranno essere campionati dopo 15µS che il master ha portato la linea a livello basso. I dati sono inviati in gruppi di 8 bit a partire dal più significativo verso il meno significativo.

La lettura della libreria scaricabile dagli iscritti in fondo all’articolo, abbondantemente commentata, dovrebbe farvi capire come è semplice implementare queste funzioni via software. Teniamo conto che, allo stato attuale, i picmicro non hanno una periferica 1wire hardware e francamente non la trovo una cosa necessaria.

Per ottenere un corretto funzionamento, inoltre, è necessario fare uso di librerie Delay molto precise. Per questa libreria ho utilizzato le librerie “Enanched Precision” che si trovano sul sito microchipc.com

Il ROM code

I dispositivi Slave sono identificati da un indirizzo a 64bit (8 bytes). Il primo byte dell’indirizzo (il byte più significativo) contiene il CRC (controllo di errore), i successivi 6 bytes (dal più significativo al meno significativo) contengono il numero seriale del dispositivo e l’ultimo byte contiene l’identificativo della “famiglia” a cui appartiene il dispositivo (esempio: 0x28=DS18B20, 0x10=DS18S20).

In questa pagina: http://owfs.sourceforge.net/family.html sono contenuti gli identificativi delle famiglie di vari dispositivi 1Wire, con i loro comandi

Nel caso in cui sul bus sia presente più di un dispositivo il Master dovrà conoscere a priori l’indirizzo di ogni dispositivo sulla linea. Nel protocollo 1-Wire sono definiti alcuni comandi chiamati  ROM commands che servono appunto al riconoscimento/rilevazione degli indirizzi dei dispositivi presenti sul bus. Se invece sulla linea è presente un unico dispositivo, esiste un comando chiamato Skip Rom che serve appunto per evitare di inviare l’indirizzo della periferica e quindi è implicito che i comandi saranno diretti all’unico dispositivo presente.

Libreria

Per gli utenti di settorezero metto a disposizione una libreria che ci permetterà di interfacciarci con il bus 1wire (per la lettura della sonda DS18S20 dovrete aspettare ancora un altro po’!). La libreria è molto semplice e per ora prevede unicamente 4 funzioni di alto livello:

unsigned char OWReset(void); // esegue il reset della linea
unsigned char OWReadByte(void); // legge un byte dalla linea
void OWWriteByte(char val); // scrive un byte sulla linea
void OWReadRom(unsigned char *ID); // memorizza nell'array ID il ROM code del SINGOLO dispositivo sulla linea

Non dovrebbe essere necessario specificare più di quanto non sia già stato scritto nelle note.  La libreria va modificata per il proprio pic agendo sul file onewire.h cambiando unicamente le due definizioni:

16
17
#define    DQ      RC5      // Pin dati sul quale sono collegate le linee DQ dei dispositivi 1-wire
#define    TRIS_DQ    TRISC5     // Registro TRIStato relativo alla porta usata per DQ

Nel main dovremo includere le routine di Delay, necessarie per il funzionamento corretto della libreria e unicamente “onewire.h”.

Avendo a disposizione un dispositivo 1Wire possiamo incominciare a determinarne il rom code, operazione che sarà comunque necessaria nel caso in cui successivamente vorremo collegare su un solo bus 1wire più dispositivi.

Ricaviamo il ROM code

In allegato, in fondo all’articolo, c’è un codice sorgente utilizzante la libreria 1Wire e che permette di rilevare il ROM code di un dispositivo 1Wire. Il codice è compilato per pic16F877A montato su scheda FreedomII ma lo potete semplicemente adattare ad un qualsiasi pic munito di UART in quanto il ROM code verrà appunto inviato sulla UART e letto da un qualsiasi programma terminale.

Supponendo di avere una sonda di temperatura (DS18S20 o DS18B20) procederemo a collegarla in questo modo (modalità alimentazione parassita):

In pratica, il pin DQ della sonda andrà direttamente al pin RC5 del picmicro e gli arriverà Vdd tramite la resistenza di pullup da 4.7KΩ. Utilizzando la FreedomII andremo a sfruttare anche il pulsante BT1, collegato al pin RB4: premendo il pulsante si avvierà la funzione di lettura del ROM code.

Preparato il circuito e caricato sul pic il programma, andremo ad aprire HyperTerminal, scegliendo la giusta porta COM alla quale abbiamo collegato la FreedomII ed impostando i seguenti parametri di comunicazione:

Di default la porta COM verrà aperta. Dando alimentazione alla Freedom apparirà la seguente schermata:

Premendo il pulsante BT1 viene richiamata la funzione per la lettura del ROM code: come specificato funziona solo se sul dispositivo è presente un unico dispositivo 1wire.

La funzione OWReadRom memorizza gli 8 bytes del rom code nell’array ID, dichiarato all’inizio del Main. Successivamente l’array viene scansionato e stampato a video utilizzando la funzione printf:

printf("0x0%X",ID[a]);

come vedete ho utilizzato lo specificatore di formato %X che serve a riportare il byte in formato esadecimale con le lettere maiuscole (%x, invece, lo riporta in esadecimale con le lettere minuscole).

Nella funzione printf ho anteposto manualmente lo 0x (o lo 0x0 se il numero è minore di 16 in modo da anteporre uno zero all’unica cifra esadecimale restituita) : in questo modo otteniamo una stringa che poi possiamo facilmente copiare ed incollare nel nostro programma che successivamente andrà a sfruttare il dispositivo:

Il programma legge il primo byte (0x10 nel mio esempio) e da qui capisce di che tipo di dispositivo si tratta. Ovviamente non potevo elencare tutti i dispositivi 1wire e mi sono limitato alle due sonde di temperatura e agli ibuttons, le altre famiglie le potete trovare nel link che ho postato più in alto.

Links

Application Note 1199 della Microchip sul bus 1-wire

Downloads

Rileva ROM Code dispositivi 1Wire (857 download)

Librerie 1Wire (830 download)

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)