Programmare il PIC
    Per tutti gli altri progetti vedi il mio blog principale www.gianlucaghettini.net



Fasi di sviluppo



Realizzare un progetto con il PIC 16F84 comporta quattro fasi principali:
  • Scrittura del programma
  • Debug e testing del codice
  • Compilazione
  • Inserimento del programma nel PIC
Nella prima fase si scrive il codice del programma, cioe' la sequenza di istruzioni assembly necessarie al corretto funzionamento del PIC; a tal fine si impiega un ambiente di programmazione che nel nostro caso sara' MPLAB. MPLAB e' un tool estremamente potente per realizzare velocemente programmi per una vasta gamma di processori, 16F84 e 16F84A compresi.
La seconda fase prevede il debug ed il testing del codice. In effetti, siccome le operazioni di scrittura nella memoria flash di programma del PIC non sono illimitate (nel caso della famiglia 16F8X possiamo programmare i PIC "solo" circa un migliaio di volte) non conviene affatto inserire subito il programma nella memoria flash e vedere se funziona ma conviene invece testare il programma con il simulatore del incluso in MPLAB: in questo modo possiamo verificare l'efficacia e la correttezza del programma senza necessariamente inserirlo nel chip, risparimiando molti cicli di scrittura inutili.
La terza fase (compilazione) prevede la creazione, tramite MPLAB, del file .HEX relativo al programma assembly appena realizzato. Questo file contiene la rappresentazione binaria del codice assembly appena realizzato ed e' l'unica forma del programma in grado di essere "compresa" dal microcontrollore. Il programmatore hardware non fa altro che prendere il file .HEX (il programmatore deve quindi essere collegato al computer) ed inserirlo bit a bit nella memoria flash del PIC, realizzando cosi' il processo di programmazione.
Una volta che il PIC e' stato programmato e' sufficiente collegare ad esso la circuiteria di base vista nelle sezioni precedenti (alimentazione, circuito per il piedino MCLR, oscillatore esterno) ed il chip iniziera' ad eseguire automaticamente il programma, istruzione dopo istruzione.
Quanto descritto completa il ciclo di sviluppo per il microcontrollore.
In figura si mostra graficamente la sequenza temporale delle varie fasi:



 



Costruzione del programmatore



In questa sezione viene descritta la costruzione di un programmatore per i PIC della famiglia 16F8X, perfettamente compatibile con i modelli 16F84 e 16F84A. Se si dispone gia' di un programmatore e' possibile saltare la sezione. In ogni caso le istruzioni per la configurazione di ICPROG saranno in funzione di questo specifico programmatore e quindi potrebbero non essere adatte per altri tipi di programmatori in commercio o autocostruiti.
Una piccola nota a riguardo: il programmatore e' un interfaccia da collegare fisicamente alla porta parallela del PC percio' occorre prestare ESTREMA attenzione nella realizzazione dei collegamenti, anche perche' entrano in gioco tensioni in grado di danneggiare irreparabilmente il PC stesso (una fra tutte la 220 di alimentazione!). Sebbene abbia provato e realizzato con successo questo programmatore, declino ogni responsabilita' per eventuali danni a persone e cose nella realizzazione dello stesso.


Funzionamento e schema elettrico


Il programmatore si rifa' al modello SCHAER2 di tipo parallelo, cioe' ad un programmatore che si interfaccia al PC tramite porta LPT (detta anche "porta della stampante"). Lo schema elettrico del programmatore e' abbastanza semplice: in effetti solo 5 dei 18 piedini vengono impegnati per la programmazione del pic e sono:
  • VCC +5Volt (piedino 14)
  • GND (piedino 5)
  • MCLR (piedino 4)
  • Linea dati (piedino 3)
  • Clock (piedino 2)
Il pic viene messo in modalita' programmazione tramite l'applicazione di 13.8 Volt al piedno MCLR, anziche' il classico segnale +5 Volt descritto nelle sezioni precedenti.
In questa modalita' il microcontrollore assegna al piedino RB6 la funzione di linea dati seriale di tipo half-duplex e al piedino RB7 la funzione di linea di clock.
Il programmatore preleva il segnale dati in arrivo dalla porta parallela (cioe' i dati contenuti nel file .HEX) e lo replica sulla linea RB6 del pic; il pic a sua volta preleva il segnale sul piedino RB6 e lo trasmette alla memoria flash interna.
Il segnale di clock serve solo per la corretta decodifica dei bit trasmessi sulla linea dati; a titolo di esempio si riporta in figura la trasmissione della parola 10110:




I segnali dati e di clock trasmessi dal pc al microcontrollore sono semplici onde quadre in banda base (cioe' senza modulazione).
Questo e' lo schema elettrico del programmatore:


 
Per ingrandire cliccare qui

Lista dei componenti:
4 diodi 1N4004
1 condensatore elettrolitico da 330uF 16V
2 condensatori elettrolitici da 0.1uF 16V
1 regolatore di tensione 78L05
1 regolatore di tensione 70L09
4 resistenze da 10Kohm 1/4 watt
1 integrato 7407N o equivalente

I segnali DATAIN, DATAOUT, CLOCK e MCLR vengono convogliati rispettivamente ai pin 2,3,11 e 4 della porta parallela del pc come mostrato nello schema. Tali segnali vengono rigenerati dallo stadio buffer composto dall' integrato 7407 e dalle resistenze di pull-up da 10k ciascuna.
Le due tensioni necessarie al corretto funzionamento del programmatore (5 e 14 Volt) vengono invece fornite dallo stadio di alimentazione (in alto nello schema) realizzato con i regolatori di tensione 78L05 e 78L09 e dal solito ponte rettificatore.
Il circuito puo' essere costruito su una semplice basetta millefori ed utilizzato cosi' come e' ma personalmente ho preferito rinchiudere il tutto all'interno di un contenitore plastico utilizzando un classico scatolotto di derivazione 20x15 per impianti elettrici. Lo schema della figura e' la versione minimale del programmatore: c'e' solo il minimo indispensabile per programmare il PIC. Quello che ho realizzato io invece assolve anche alla funzione di tester per provare i programmi in situ: sul pannello frontale sono presenti 8 led rossi per il bus della porta B, 5 pulsanti per la porta A, un tasto di reset ed un selettore per dirottare i 13 segnali di I/O del pic sulla porta di espansione situata sul retro del programmatore. La porta di espansione e' stata realizzata con un connettore maschio da 26 pin e permette di interfacciarsi alle 13 linee di I/O del microcontrollore: in questo modo e' possibile collegare periferiche esterne al programmatore e provare i propri programmi con apparati reali e non solo con semplici led di segnalazione.
Ecco alcune foto del programmatore che ho realizzato:


Il programmatore appena ultimato
Retro del programmatore
(Pulsante di accensione, cavo di alimentazione e porta di espansione per I/O esterno)
Lato sinistro
(Porta di collegamento con il PC)
Stadio alimentazione
(fase di montaggio)
Circuito completo su bread-board
(fase di montaggio)
Inserimento del trasformatore nel case
(fase di montaggio)
Saldature sul retro del circuito stampato
Circuito stampato completato
(vista dall'alto)
Circuito stampato completato
(particolare della porta di I/O)
Collegamenti interni relativi al pannello superiore 
Il programmatore pronto per essere chiuso



Configurazione di  ICPROG


Come detto in precedenza il programmatore viene comandato da un apposito software di controllo. Nel nostro caso useremo l'ultima versione di ICPROG, scaricabile a questo indirizzo.
Oltre ad ICPROG e' necessario scaricare anche i driver NT/2000 per poter utilizzare la porta parallela sui Windows XP,NT e 2000. Il contenuto dei due archivi zip deve essere riversato in una stessa directory ad esempio in "C:\icprog".
Fatto cio' avviamo ICPROG ed andiamo in "settings->options", selezioniamo "misc" ed assicuriamoci che sia selezionata l'opzione "Enable NT/2000/XP Driver", come da figura:



Chiudiamo e riavviamo ICPROG per rendere effettive le modifiche (nel caso in cui le impostazioni non fossero state modificate il riavvio non e' necessario). A questo punto entriamo in "settings->Hardware" ed impostiamo le opzioni come in figura:



Adesso ICPROG e' pronto per essere usato con il programmatore. Prima pero' occorre verificare che i segnali da e verso il PC vengano inviati ed interpretati correttamente: a tal fine colleghiamo il programmatore al PC ed andiamo in "Settings->Hardware Check". Questa e' la finestra che otteniamo:



La finestra e' una sorta di banco di prova grazie alla quale possiamo attivare a piacimento i segnali sulla porta parallela e controllare facilmente con un tester se arrivano ai pin del microcontrollore. Le opzioni "Enable Data Out", "Enable Clock" e "Enable MCLR" portano rispettivamente al livello logico alto (+5 Volt) i pin 2,3 e 4 della porta parallela. L'opzione "Data In" non e' impostabile ma si setta se "Enable Data Out" e' settato e viceversa (questo solo se il programmatore funziona correttamente). "Enable VCC" non ci interessa perche' il nostro modello di programmatore non ne fa uso.
Detto questo selezioniamo "Enable Data Out": "Data In" dovrebbe selezionarsi automaticamente. Verifichiamo che quando "Enable Data Out" e' selezionato sia presente una tensione di circa +5 Volt sul pin RB7 del microcontrollore (possiamo prende il riferimento di massa dal pin GND dello pic stesso). Selezioniamo "Enable MCLR" e dovrebbe presentarsi una tensione di circa +13.8 Volt sul piedino MCLR del pic.
Se almeno uno di questi test e' fallito occorre controllare che i segnali imposti dal PC si presentino almeno sulla porta parallela: se e' cosi' allora ICPROG funziona correttamente mentre il problema e' nel programmatore, se no il problema e' almeno in ICPROG dato che non riesce a controllare correttamente la porta.
Per esperienza personale posso garantire che e' estremamente improbabile che tutto funzioni correttamente al primo tentativo (montaggio del programmatore, collegamento e configurazione di ICPROG) quindi occorre avere un po' di pazienza e sistemare gli errori commessi. Inoltre, prima di collegare per la prima volta il PC al programmatore e' bene verificare che sulla porta parallela vengano sempre presentate tensioni non superiori ai 5 Volt, per non arrecare danni al PC.



L'ambiente MPLAB



MPLAB e' la suite di sviluppo per la realizzazione dei programmi per i microcontrollori della Microchip. Consiste di un editor grafico per la stesura del programma, di un assembler per la generazione del codice macchina e di un debugger per la simulazione dei programmi. MPLAB e' completamente gratuito e puo' essere scaricato direttamente dal sito della Microchip a questo indirizzo.


Creazione del progetto e del programma


Una volta scaricato ed installato avviamo MPLAB.
Questa e' la schermata principale:



Per prima cosa occorre creare un nuovo progetto. Andiamo in "Project->Project Wizard"



Clicchiamo su "Avanti". Apparira' la seguente schermata:



Selezioniamo il modello di microcontrollore: nel nostro caso va bene sia "PIC16F84" che "PIC16F84A". Clicchiamo quindi su "Avanti".



Qui occorre selezionare il linguaggio di programmazione da utilizzare. Noi utilizzeremo direttamente l'assembly, quindi lasciamo le impostazioni cosi' come sono e clicchiamo su "Avanti"; otteniamo questa finestra:



In questo passo occorre specificare la directory di progetto. Possiamo inserire "C:\prova\prova.mcp" nel form ad indicare che vogliamo creare il progetto "prova.mcp" (mcp e' l'estensione standard per i progetti MPLAB) nella directory "C:\prova". Clicchiamo su "Avanti" due volte e poi, alla schermata di riepilogo, su "Fine". Otteniamo la seguente schermata:



Andiamo ora in "File->New"; apparira' una nuovo editor di testo vuoto (bianco). A questo punto clicchiamo su "File->Save as..." ed apparira' la seguente finestra:



Posizioniamoci all'interno della directory di progetto "C:\prova" appena creata dal programma e scriviamo "prova.asm" nell'apposito form come mostrato nella figura precedente. Chicchiamo quindi su  "Salva". La finestra si chiude, il file "prova.asm" viene immediatamente creato ed aperto in un nuovo editor (sempre vuoto ovviamente), come da figura:



Clicchiamo ora col tasto destro su "Source Files" all'interno della finestrella bianca in alto a sinistra e selezioniamo "Add Files..." come mostrato in figura:



A questo punto ci verra' chiesto di selezionare un percorso per il file di testo che conterra' il listato del nostro programma: selezioniamo "C:\prova\prova.asm" cioe' il file di testo che abbiamo creato al passo precedente.
Clicchiamo sulla nuova voce "prova.asm" che apparira' sotto "Source Files" per riaprire l'editor di testo.
Adesso siamo pronti per inserire, una dopo l'altra, tutte le istruzioni assembly necessarie per realizzare il nostro programma.
Un tipico programma e' composto essenzialmente da 5 parti principali:
  • Commento di intestazione
  • Direttive per il compilatore
  • Definizioni
  • Istruzioni di programma
  • Direttiva "END"
Ecco come si presenta un listato:

 

Il listato in figura e' scaricabile qui.
P.S. La routine di attesa da 100ms e' riferita ad un clock di 4MHz.

Questo programma non fa altro che alternare 1 e 0 sul primo bit della porta B ogni 100ms. Cioe', ogni 100ms il primo bit della porta B cambia stato.
In alto abbiamo il commento generale sul funzionamento del programma (i commenti possono essere sparsi ovunque, l'importante e' che inizino sempre con il punto e virgola).
Dopo il commento abbiamo le due direttive PROCESSOR e RADIX. La prima istruisce il compilatore a considerare uno specifico modello di microcontrollore (nel nostro caso il pic 16F84A). RADIX invece indica la base con la quale andremo a rappresentare i valori numerici nel listato del programma: HEX significa che utilizzeremo la notazione esadecimale, DEC quella decimale.
Abbiamo ora le definizioni: con la direttiva EQU possiamo associare a dei valori numerici una etichetta testuale: "PORTB  EQU  0x06" permette di utilizzare la scritta "PORTB" nel listato del programma al posto del suo indirizzo di memoria); in questo modo sara' piu' semplice accedere al registro. Notare comunque che, ad esempio, per accedere a PORTB o TRISB occorre sempre e comunque selezionare opportunamente il banco RAM.
Dopo le definizioni e' il listato del programma vero e proprio. La direttiva ORG indica la prima posizione in memoria di programma a partire dalla quale verranno inserite una dopo l'altra tutte le nostre istruzioni assembly: nel nostro caso con ORG 0x0000 imponiamo l'inserimento a partire dalla primissima locazione (locazione 0x0000)  anche perche' e' da qui che il pic comincia ad eseguire le istruzioni, ma nulla vieta di scegliere altre posizioni. Possono essere presenti piu' direttive ORG sparse lungo il codice di programma: ogni volta che se ne incontra una il compilatore iniziera' ad allocare le istruzioni assembly a partire dalla locazione specificata. La direttiva e' molto utile in caso si voglia lasciare un "buco" nella memoria di programma per far posto ad una routine di gestione delle interruzioni che, come visto in precedenza, deve necessariamente cominciare a partire dalla locazione di memoria 0x0004: in questo caso avremo una cosa del genere:

ORG    0x0000
goto    start
ORG    0x0004
;routine di gestione delle interruzioni

;fine routine
start:
;inizio programma vero e proprio

END

Il microcontrollore iniziera' l'esecuzione a partire da 0x0000 come di consueto, saltando pero' immediatamente al programma vero e proprio, tramite il goto. La routine di gestione delle interruzioni e' posizionata invece a partire dalla locazione 0x0004 e viene invocata solo quando necessario.
Ritornando al listato precedente, abbiamo poi le istruzioni di programma. Il programma principale si risolve in un singolo loop infinito che effettua queste operazioni:
  1. Imposta come linee di output i bit di PORTB
  2. Setta a 1 il primo bit di PORTB
  3. Chiama una routine di attesa
  4. Setta a 0 il primo bit di PORTB
  5. Chiama la routine di attesa
  6. Ritorna al passo 2
Infine abbiamo la direttiva "END" che decreta la fine del listato.
Il programma mostrato puo' essere copiato ed incollato sul nostro "prova.asm" cosi' come e' (cliccare qui per scaricare il listato in formato testo).


Compilazione del programma


In questa fase andiamo a "compilare" il codice, andando cosi' a creare il file .HEX da passare poi a ICPROG.
Andiamo in "Project->Build ALL" oppure premiamo "CTRL+F10"; se non abbiamo fatto alcun errore dovrebbe comparire una finestra di dialogo simile a questa:



La scritta "BUILD SUCCEEDED" in basso ci informa del successo dell'operazione. Nella directory di progetto (in questo caso "C:\prova") e' appena stato creato il file "prova.HEX", cioe' i dati che dovremo inserire nella memoria del pic tramite l'ausilio di ICPROG e del programmatore.
Nel caso siano presenti errori di sintassi otterremo la scritta "BUILD FAILED" e occorrera' correggere tali errori.



Debug del codice



Il debugger e' uno strumento molto potente fornito da MPLAB per poter verificare la correttezza logica del codice appena compilato (il compilatore rileva solo gli errori sintattici) senza necessariamente programmare fisicamente il PIC.
Andiamo in "Debugger->Select tool" e selezioniamo l'opzione 3 cioe' "MPLAB SIM". Abbiamo appena abilitato il debugger di MPLAB. Il debugger ci permette di controllare il funzionamento interno del microcontrollore istruzione dopo istruzione, come vengono modificati i registri SFR e GPR, la correttezza del flusso di programma, lo stato della EEPROM e molto altro.
Se non lo abbiamo gia' fatto premiamo "CTRL+F10" per ricompilare il programma.
Andiamo in "Debugger->Reset" e simuliamo un reset MCLR (come ad esempio l'accensione del pic) selezionando l'opzione "MCLR Reset". apparira' un puntatore verde alla prima istruzione del programma come in figura:  questo puntatore indica l'istruzione che sta per essere eseguita al prossimo colpo di clock. Premiamo una volta F8 ed otteniamo l'esecuzione dell'istruzione puntata, adesso e' il turno della prossima istruzione. Premendo di nuovo F8 avanziamo lungo tutto il programma. Con F7 avanziamo lo stesso ma possiamo entrare all'interno delle chiamate a funzione.
Se vogliamo controllare lo stato attuale dei registri SFR sara' sufficiente andare in "View->Special Function Registers": in questo modo possiamo controllare come si modificano tali registri parallelamente all'avanzamento del programma. Oltre ai registri SFR possiamo controllare:
  • La EEPROM con l'opzione "View->EEPROM"
  • La memoria di programma con "View->Program Memory"
  • Lo stack con "View->Hardware Stack"
  • Tutti i registri (SFR e GPR) con "View->File Registers"
Una volta attivate tutte queste opzioni ecco come si presenta MPLAB in modo debugger:






Programmazione del PIC



Possiamo ora inserire il file .HEX all'interno della memoria di programma del pic. Apriamo ICPROG ed andiamo in "File->Open File..". Selezioniamo il file "C:\prova\prova.HEX" creato da MPLAB all'atto della compilazione:
.



ICPROG visualizza i byte relativi al codice macchina del nostro programma nella finestra principale (evidenziata in blu). Nel pannello a lato (evidenziato in rosso) abbiamo invece alcune opzioni da settare opportunamente a seconda di come verra' impiegato effettivamente il pic nel sistema reale. Occorre innanzitutto selezionare il tipo di oscillatore (RC, XT, LP o HS) effettivamente impiegato nel circuito che ospitera' il pic.
Piu' in basso occorre decidere se attivare il Watch-Dog agendo sull'opzione WDT (normalmente lo si tiene disabilitato fintanto che non se ne fa espressamente uso all'interno del codice), se attivare il Power-Up Timer (opzione PWRT) che introduce un piccolo delay temporale all'accensione del pic per permettere di stabilizzare l'alimentazione e se attivare la protezione del codice (opzione CP). La protezione del codice e' utile nel caso in cui si voglia impedire la lettura a terzi del codice macchina inserito nel pic: ogni tentativo di lettura scatenera' automaticamente la cancellazione della memoria di programma del microcontrollore.
Fatto questo e' sufficiente accendere il programmatore ed effettuare la programmazione con il pulsante evidenziato in figura:



Il pulsante in questione fa parte dei quattro che permettono rispettivamene di leggere il pic, scrivere, cancellare e compararne il contenuto rispetto a quanto mostrato nella finestra principale.
Il pic e' ora pronto per essere montato nel circuito.