Il codice per PIC 16F84A – Routines di supporto

Come anticipato, il codice assembly riportato nel seguito di questo articolo fa riferimento all’uso di un microcontrollore Microchip della famiglia PIC16F e in particolare suppone di usare l’hardware di un PIC16F84A ma può essere facilmente adattato senza troppe modifiche a quasi tutti i PIC della stessa famiglia.

Questo codice non è interamente farina del mio sacco ma è copiato da un programma che ho trovato in internet da una tesina universitaria. Purtroppo non ricordo chi fossero gli autori ma li ringrazio sentitamente per avermi risparmiato un bel po’ di lavoro.

Visto che lo scopo di questo articolo è essenzialmente didattico, commenterò passo passo le istruzioni del programma, ma darò comunque per scontata una certa conoscenza dei PIC, come si programmano e i fondamenti del loro linguaggio assembly.

Visto che nel paragrafo precedente abbiamo accennato alla necessità di effettuare le diverse operazioni sulla linea di trasmissione entro intervalli di tempo ben definiti, la prima cosa da fare è preparare una serie di routines di ritardo da chiamare opportunamente durante l’esecuzione del codice. In questo modo le routines che si occupano di alzare e/o abbassare la linea di comunicazione in funzione di quello che si vuole leggere o scrivere sulla sonda possono usufruire tante piccole routines che eseguono un numero di cicli a vuoto per il tempo necessario.

In questo caso abbiamo cicli di ritardo calcolati per un quarzo a 4MHz e vi sono diverse routines che realizzano ritardi da un minimo di 15µs a 1s.
Tralascerò la descrizione delle varie routines di ritardo dal momento che si tratta di semplici cicli a vuoto, calibrati per durare il tempo richiesto. Ricordo solo che con un quarzo da 4MHz ogni istruzione del PIC dura un microsecondo.

La routine principale, chiamata “Acquisition” che si occupa di eseguire tutti i passaggi necessari per acquisire il valore di temperatura letto dalla sonda è oggetto del prossimo paragrafo. Qui ci occuperemo di altre routines di supporto che vengono chiamate all’interno della Acquisition. La prima routine che analizziamo è anche la prima ad essere chiamata ed è denominata “inizializza_ds1820”:

Questa routine serve ad eseguire la sequenza di reset descritta al paragrafo precedente e a leggere l’eventuale impulso di presence. Quindi si occupa di abbassare la linea a 0, aspettare 600µs rilasciare la linea, aspettare 80µs e controllare se la linea è andata a 0 perchè una sonda ha risposto all’impulso di reset. Le operazioni di alzare e abbassare la linea coincidono rispettivamente con le istruzioni bsf e bcf applicate al bit 4 del registro PORTA.
Per tenere traccia di questa risposta e eventualmente usarla in altre parti del programma, si usa una variabile denominata errore di cui si usa il bit 0 come flag: bit 0 = 1 -> sonda non presente.

Ogni comunicazione con la sonda consiste sempre di 3 passi: inizializzazione, comando ROM, comando di funzione.
Dopo ogni comando si introduce un ritardo di 600µs per dare il tempo di esaurirsi allo slot di lettura, con un po’ di margine.

Abbiamo appena visto la routine di inizializzazione, che agisce direttamente sulla linea di trasmissione, ma, siccome le altre operazioni richiederanno di scrivere dei valori numerici, per facilitare la trasmissione dei valori 1 e 0 verso la sonda, ciascuno dei quali richiede dei movimenti ben temporizzati della linea, si utilizzano due routines di appoggio: “scrivi_uno” e “scrivi_zero”.

Per capire il funzionamento di queste due routines, dobbiamo tenere presente che la sonda legge il valore logico sul filo 15 microsecondi dopo che questo è stato tirato giù dal bus-master.
In altre parole se la sonda vede la linea, che è normalmente a 1, andare a 0, saprà che il bus-master le sta per comunicare un bit e quindi aspetterà 15μs e poi leggerà lo stato della linea interpretando il valore come un bit di dato.
Quello che deve fare il PIC è quindi, se vuole trasmettere uno 0, abbassare la linea e continuare a tenerla bassa fino a oltre i 15μs per almeno 75μs.
Questo perché la sonda potrà leggere il valore della linea in un intervallo compreso fra 15 e 75µs da quando il bus-master l’ha abbassata.
Viceversa, se il PIC vuole trasmettere un 1, deve rilasciare la linea entro i 15μs e lasciarla invariata per almeno 75μs.
Ovviamente anche nel caso della trasmissione di un 1 la linea deve essere dapprima abbassata dal PIC che, per dare il tempo alla sonda di accorgersi della variazione sulla linea, la deve mantenere a 0 per almeno 1μs prima di poterla rilasciare entro il limite dei 15μs.
Possiamo adesso dare un senso alle istruzioni sopra riportate. Come si può vedere per scrivere un 1 si mette a 0 la linea su cui è collegata la sonda (in questo caso il piedino RA4) e lo si mantiene per 7μs. Quindi siamo sicuri di averlo tenuto per 1µs e cadiamo a metà dell’intervallo da 15μs.
Successivamente si rimette la linea a 1 e si aspettano 80μs che è un po’ di più dei 75μs per avere un po’ di margine. Nel caso della scrittura di uno 0 è sufficiente mettere la linea a 0 per 80μs e poi rimetterla a 1.

Le due routines “scrivi_zero” e “scrivi_uno” si occupano di controllare a basso livello lo stato della linea, ma abbiamo bisogno ancora di una routine di supporto che si occupi di scrivere un intero valore numerico. Eccola di seguito riportata, la scrivi_ds1820.

Per l’utilizzo di questa routine, si suppone che sia stato inserito il valore che si vuole trasmettere nella variabile chiamata ds1820 e ricordiamo che tutte le comunicazioni con la sonda avvengono trasmettendo per primo il bit MENO significativo.
In questa routine si usa l’istruzione rrf per far ruotare verso destra i bit della variabile ds1820 passando per il bit di carry dello STATUS register. Ad ogni ciclo si utilizzano le routines scrivi_uno e scrivi_zero, viste precedentemente, in funzione del fatto che il bit di carry sia zero o uno.

Sapendo questo esaminiamo le righe una per una:

  • metti nell’accumulatore il valore decimale 8
  • metti il valore dell’accumulatore nel registro KEY

questo serve per avere un contatore per gli 8 bit di trasmissione;

  • rrf ds1820,F

come anticipato questa è l’istruzione che effettua una rotazione verso destra del registro specificato e ne salva il contenuto nel registro stesso.
La particolarità consiste nel fatto che la rotazione avviene attraverso il bit di Carry dello STATUS register.
Questo significa che dopo aver eseguito la rrf ci ritroveremo al posto del bit 7 il valore che era nel bit di carry prima della rrf, al posto del bit di carry troveremo il valore del bit 0 (il bit meno significativo) e tutti gli altri bit saranno scalati di una posizione verso il meno significativo.
Questa procedura ci permette di avere ad ogni ciclo, nel bit di carry, proprio il valore da trasmettere partendo dal meno significativo.
Non rimane altro che:

  • controllare il valore del bit di carry e saltare se vale 1
  • andare avanti di 3 istruzioni
  • chiamare la “scrivi_uno” esaminata precedentemente
  • andare avanti di 2 istruzioni
  • chiamare la “scrivi_zero” esaminata precedentemente
  • decrementare il contatore “KEY” saltando se vale 0
  • ritornare all’inizio della routine
  • ritornare alla chiamante

C’è poco altro da aggiungere a queste righe, si tratta di alcuni salti condizionati organizzati in modo da chiamare la “scrivi_uno” o la “scrivi_zero” in base al valore del bit di carry.

Dobbiamo ora affrontare il problema di “leggere” questo dato che ci viene inviato ancora una volta a partire dal bit meno significativo.
Anche in questo caso è il bus-master che comanda la comunicazione abbassando la linea.
La sonda, se vuole trasmettere uno 0 manterrà la linea a 0 per un massimo di 15μs da quando il bus-master l’ha abbassata. Per il diagramma temporale si faccia riferimento al paragrafo precedente.
Quindi il PIC dovrà smettere di pilotare la linea entro i 15μs e leggere il valore.
Ogni slot di lettura deve durare almeno 60μs e fra uno slot e l’altro deve intercorrere almeno 1 μs.
Alla luce di quanto sopra possiamo interpretare la seguente routine:

Come prima operazione si pulisce il contenuto del registro ds1820 perchè vi andremo a inserire il dato letto.
Poi si imposta a 8 il contatore dei bit, in questo caso, ricevuti.
Si abbassa la linea di comunicazione.
Si eseguono due nop, cioè due operazioni a vuoto che permettono di far trascorrere 2 microsecondi per far assestare la linea e permettere alla sonda di vedere la variazione.
Si rilascia la linea.
Si effettuano una serie di nop per portarsi a ridosso dei 15μs che è il limite massimo entro cui fare la lettura.
Si preimposta alto il bit di carry.
Finalmente si effettua la lettura del valore.
Se tale valore è 0 si imposta a 0 il bit di carry altrimenti si salta alla istruzione successiva.
Si effettua la rrf per riportare nel registro ds1820 il bit di carry infilandolo da sinistra.
In questo modo dopo le 8 iterazioni il primo bit letto sarà arrivato in posizione 0 che è appunto la meno significativa.