Programmare il PIC
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:
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:
- Imposta come linee di output i bit di PORTB
- Setta a 1 il primo bit di PORTB
- Chiama una routine di attesa
- Setta a 0 il primo bit di PORTB
- Chiama la routine di attesa
- 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.
|
|