MICROCONTROLLORE PIC 16F877A


Può essere considerato un evoluzione del microprocessore perché ha nel suo interno tutte le parti per poter funzionare :



I microcontrollori vengono utilizzati per quelle applicazioni che prendono il nome di SISTEMI EMBEDDED. Con la definizione di sistema embedded si intende un'applicazione dedicata, mirata allo svolgimento di funzioni specifiche, quelle in cui i micro trovano ampio spazio. Noi ci concentreremo sui PIC (Peripheral Interface Controller) prodotti dalla microchip con architettura Harvard; produce micro a 8, 16, 32 bit e una famiglia denominata dsPIC. Ci sono chip da 6 a 144 pin per le varie esigenze. Come abbiamo detto sono realizzati con architettura Harvard e di tipo RISC (Reduced Instruction Set Computer). Questo tipo di struttura dispone di due bus interni , uno per l'accesso alla data memory (RAM) e uno per l'accesso alla program memory; la profonditĂ  dei due bus, nel microcontrollore che useremo, è rispettivamente di 7 e 14 bit. La presenza di due bus separati permette prestazioni migliori rispetto all'architettura piĂą classica di Von-Neumannn, in quanto il caricamento delle istruzioni avviene mediante un bus dedicato, quindi istruzioni e operandi vengono caricati entrambi con un solo accesso ai bus e con un solo ciclo macchina (col metodo Von-Neumann per caricare istruzioni e operandi sono necessari piĂą accessi all'unico bus)



Nel circuito integrato ci sono dei pin specifici per il suo funzionamento, per la programmazione e I/O (sono definiti in questo modo i piedini che possono funzionare come ingressi o come uscite). I primi servono per alimentare il dispositivo (un circuito integrato è a tutti gli effetti un circuito in miniatura, che per funzionare deve essere alimentato con la sua tensione nominale), gestire il reset hardware e il clock che gestisce i tempi di lavoro del chip interno. Come si vede nella Fig.1, il chip è posizionato all'interno di un package nero, con dei pin che collegano verso il mondo esterno e un incavo che permette di conoscere la numerazione dei pin (vedi Fig.2 - Con la tacchetta posta a sinistra il piedino numero uno corrisponde al primo piedino in basso a sinistra, quindi segue la numerazione in senso antitorario).







Fig. 1 – struttura interna e vista esterna

Fig. 2 – numerazione pin


I pin specifici per il suo funzionamento si vedono nello schema elettronico seguente (questo è lo schema classico di base, ma nel circuito di reset potrebbe avere delle varianti che impareremo sotto):



Fig. 3 – schema base dell'utilizzo di questo microcontrollore

PERIFERICHE : sono hardware interni messi a disposizione dal dispositivo :

per essere usate le periferiche devono essere configurate mediante dei registri specifici. Questi verranno presentati man mano che verranno utilizzate le varie periferiche.


ALIMENTAZIONE : questo microcontrollore richiede un'alimentazione di 5V in continua. I pin per alimentare il microcontrollore sono :

E' importante ricordare che per ogni integrato presente su un circuito elettronico, sul piedino positivo dell'alimentazione va collegato un condensatore poliestere da 100 nF, l'altro piedino va collegato a massa. La funzione di questo componente e di filtrare le alte frequenze evitando auto oscillazioni del componente a causa dei disturbi elettromagnetici. Il piedino del condensatore collegato al pin positivo (in questo caso VDD) va collegato il più vicino possibile a pin dell'integrato per accorciare il più possibile la pista (o il filo) tra condensatore e pin, perché più è lungo e più capta disturbi elettromagnetici (si comporta da antenna).


RESET : resettare un microcontrollore vuol dire riportare la lettura del programma alla prima riga (prima cella del program memory) rifacendo rileggere dall'inizio il firmware. Il piedino che permette questo effetto a livello hardware è il pin 1 chiamato MCLR (negato, quindi funzionante in logica negativa) serve a resettare il microcontrollore a livello hardware. Posso avere combinazioni ed effetti diversi in base alle richieste o alle esigenze.





Fig. 4

Fig. 5

Fig. 6

Fig. 7



Nessun ritardo alla partenza - Caso Fig. 4 : questo è il caso più semplice. Essendo MCLR un ingresso negato, per non fare il suo effetto (cioè resettare il microcontrollore) deve essere a “1” logico. La resistenza R da 10 K (valore consigliato dalla casa madre) assolve proprio al compito di mantenere a livello alto questo pin. In questo caso, appena si alimenta il microcontrollore il programma parte immediatamente perché questa resistenza mantiene disattivato il reset. Attenzione : senza questa resistenza il microcontrollore funzionerà male, perché come qualsiasi piedino digitale, la mancanza di un riferimento provoca instabilità, cioè passaggi del pin alternativamente a “0” e a “1” ottenendo reset continui del dispositivo in modo imprevedibile.


Ritardo alla partenza - Caso Fig. 5 : Con l'aggiunta del condensatore C2 da 100nF (valore consigliato, ma non obbligatorio, dalla casa madre) si ottiene un reset di un certo tempo ogni volta che si alimenta il dispositivo. L'effetto che si ottiene è il seguente :

  1. appena si alimenta il condensatore è scarico, quindi il pin 1 a “0” logico mantiene il microcontrollore in reset;

  2. il condensatore si carica (secondo la legge di carica del condensatore) e dopo un certo tempo T raggiunge un potenziale che viene letto come “1” logico e quindi smette di resettare il microcontrollore;

  3. dopo il p.to 2) , appena termina l'effetto di reset, il programma comincia ad essere eseguito.

Questo è utile quando ci sono sensori collegati al sistema che richiedono un po' di tempo a stabilizzarsi nella fase di avviamento. Quindi per non avere effetti incontrollati si mantiene ferma la lettura del programma mantenendo il sistema in reset.


Nessun ritardo, ma possibilitĂ  di resettare in qualsiasi momento con un pulsante - Caso Fig. 6 : funziona come il circuito di Fig. 4, ma in questo caso il pulsante NO tra il pin 1 e massa permette, se viene premuto di effettuare un reset al sistema, che si mantiene per tutto il tempo in cui viene mantenuto premuto, dopo di che il programma ricomincia a essere letto dalla prima cella della program memory.


Ritardo alla partenza, possibilità di resettare in qualsiasi momento con un pulsante e al rilascio ripartire con ritardo - Caso Fig. 7 : l'effetto di questo schema è un mix tra i tre schemi precedenti. In pratica all'avvio si ha un ritardo (effetto condensatore) alla partenza del firmware, è possibile in qualsiasi momento resettare (effetto che si ottiene premendo il pulsante), e in questo caso, dopo aver rilasciato il pulsante il programma riparte dopo un certo tempo (effetto condensatore).


CLOCK : il funzionamento del microcontrollore viene scandito da un onda quadra. Questo segnale può essere ottenuto in vari modi, il più preciso e stabile è quello che utilizza il quarzo (Fig. 8).




Fig. 8 – il segnale di clock è un segnale ad onda quadra, in ogni periodo il microcontrollore compie un operazione.

Fig. 9 – C1 = C2 sempre, il valore si ottiene con le tabelle della Fig. 10.



Fig. 10 – tabelle prelevate dal datasheet per dimensionare i condensatori quando si usano i risonatori ceramici e i quarzi.


MEMORIA : Nel PIC16F877A ci sono tre aree di memoria : program memory, data memory e EEPROM.

Nella program memory risiede il firmware che viene eseguito dal micro (tipo flash e quindi può essere scritta, cancellata e riscritta elettricamente un elevato numero di volte). La data memory (detta anche register file map – mappa dei registri) è una memoria RAM destinata ad essere usata per le variabili, costanti (general purpose register) e le risorse di sistema come i registri (special register che è un area di memoria RAM i cui bit sono fisicamente collegati all'architettura hardware, quindi con effetti specifici sul sistema). La EEPROM (Electrical Eresable Programmable Read Only Memory) serve per memorizzare informazioni che non vengono perse quando viene tolta alimentazione per spegnimento manuale del sistema o in caso di black-out.

Fig. 11 - rappresentazione della program memory, program counter e dello stack.

Vediamo la program memory : il programma inviato al microcontrollore viene memorizzato in queste 8192 celle, per essere eseguito c'è un registro specifico PC (program counter) che contiene i 13 bit (213 infatti corrisponde ai valori da 0 a 8191) che definiscono la riga che di codice che deve essere eseguita. Quando si sono istruzioni di salto in cui è previsto un ritorno al punto di partenza, il valore del PC viene memorizzato nel registro stack LIFO (acronimo di Last In First Out-Ultimo ad entrare, primo ad uscire) che permette 8 livelli di annidamento. In pratica per tornare indietro a ritroso vengono lette le righe da questo registro e caricate nel PC. La program memory ha delle celle di memoria da 14 bit, lunghezza rigida come richiesto dalla tecnologia RISC :

E' importante notare che la parte dell'istruzione che punta alla memoria RAM, e che fa riferimento ai registri specifici e ai general purpose register, è di 7 bit quindi .

RAM : la memoria RAM è divisa in 4 banchi a causa del fatto che ogni istruzione può puntare al massimo 128 celle di memoria (se notate è l'indirizzo dell'ultima cella di memoria del banco 0 nella RAM (vedi immagine sotto)). Riguardando la figura sotto, vediamo che le celle da indirizzare per raggiungere tutte le celle RAM sono locazioni e mi servono quindi 9 bit infatti . Per ottenere i due bit che mi mancano uso il così detto offset, cioè, in questo caso, due bit memorizzati in un registro specifico :

come posso vedere i bit0 … bit6 sono quelli specificati nella istruzione, mentre i due bit di peso maggiore sono contenuti in due bit nominati RP0 e RP1 del registro specifico STATUS (notate che il registro è contenuto in tutti i banchi, infatti questo deve essere sempre scrivibile per passare da un banco all'altro della memoria RAM).

Le celle con sfondo grigio non si possono usare perché usate dal sistema. Le celle bianche sono libere per le variabili o le costanti, mentre quelle con i nomi vanno usate conoscendo il registro specifico, perché ogni bit incide sulle impostazioni o il funzionamento del sistema.

I nomi di questi registri vanno specificati nelle istruzioni in cui il parametro è contraddistinto dalla lettera f

Quando uso locazioni con sfondo bianco (general purpose register) per comoditĂ  posso assegnargli un nome, piĂą comodo rispetto alla locazione di memoria. Per farlo uso la direttiva EQU.

Esempio

pippo EQU 0x21;

chiamo la locazione 0x21 (banco 0) col nome pippo.


Esempio che fa capire cosa succede se sbaglio banco di memoria :




CICLO MACCHINA : il microcontrollore, per eseguire una istruzione normale impiega 4 periodi di clock, mentre se l'istruzione salta ad un'altra riga (nel caso delle istruzioni che possono saltare o meno in base a dei criteri, seguono questa seconda opzione solo quando saltano) vengono eseguite in 8 periodi. I 4 periodi sono definiti ciclo macchina. Quando ho le istruzioni che saltano ho 2 cicli macchina. Il periodo di clock dipende dal quarzo. Sul quarzo viene scritta la frequenza di oscillazione del componente. Per ottenere il periodo :

quindi con un quarzo da 8 MHz si ha quindi ogni istruzione normale viene eseguita in . Sotto è possibile vedere un diagramma temporale delle fasi di Fetch che rappresentano la gestione dell'esecuzione delle istruzioni di un programma.

TCYn : sono indici che contano i cicli macchina (TCY1, TCY2, TCY3, etc.)

OSC1 : è il segnale di clock presente sull'omonimo pin

Q1, Q2, Q3, Q4 : sono i quattro impulsi di clock che si susseguono a ogni ciclo macchina

PC : valore del program counter che si incrementa di un unitĂ  ad ogni ciclo macchina

Per capire le ultime righe a gradini facciamo un esempio integrativo ai due riquadri. Ipotizziamo che il valore del program counter sia 10, quindi PC-1=10, questa è la riga di programma in esecuzione, ma in questa fase viene caricata anche la riga successiva che corrisponde alla 11 e quindi PC=11.





GLI ALTRI PIN : i pin che hanno piĂą nomi possono essere usati per funzionamenti diversi. Gli usi piĂą importanti sono i pin Rxn :

RA0, RA1, RA2, RA3, RA4, RA5 : sono i pin del porta A e sono di tipo I/O digitale, questi pin hanno la particolaritĂ  di accettare anche segnali analogici (0...5 V), ma in questo caso assumono l'altro nome : AN0, AN1, AN2, AN3 e AN4 (il pin RA4 non prevede di essere usato per leggere analogiche).

RB0, RB1, RB2, RB3, RB4, RB5, RB6, RB7 : sono i pin della porta B e sono di tipo I/O digitale, questi pin hanno la particolaritĂ  di poter attivare delle resistenze di pull-up interne che permettono di risparmiare spazio e soldi, ma possono essere usare solo per pulsanti o interruttori vicini al dispositivo.

RC0, RC1, RC2, RC3, RC4, RC5, RC6, RC7 sono i pin della porta C e sono di tipo I/O digitale.

RD0, RD1, RD2, RD3, RD4, RD5, RD6, RD7 sono i pin della porta C e sono di tipo I/O digitale.

RE0, RE1, RE2 sono i pin della porta E e sono di tipo I/O digitale, questi pin hanno la particolaritĂ  di accettare anche segnali analogici (0...5 V), ma in questo caso assumono l'altro nome : AN5, AN6 e AN7.


TRISA, TRISB, TRISC, TRISD e TRISE : quando questi pin sono usati come I/O digitali, bisogna informare il microcontrollore quali sono ingressi e quali sono uscite. Per fare ciò si usano i registri TRISx (x è il nome della porta di cui bisogna stabilire la direzione). Questo registro a 8 bit regola i vari pin della porta mediante il valore della cella corrispondente al pin stesso. Per definire che un pin funzioni come uscita (Output) si deve mettere “0” ( 0 assomiglia a O di Output)nel bit corrispondente. Per definire che un pin funzioni come ingresso (Input) si deve mettere “1” ( 1 assomiglia a I di Input) nel bit corrispondente. Per convenzione i pin non usati vengono battezzati come ingressi, perché un ingresso, durante il funzionamento della scheda, se per qualsiasi motivo va a contatto con uno stato logico, se è ingresso non fa nulla, se è un uscita ed ha uno stato diverso da quello che viene a contatto, provoca un danneggiamento della porta o del sistema.

Esempio

RB7

RB6

RB5

RB4

RB3

RB2

RB1

RB0

Output

Output

Output

Output

Input

Input

Input

Input

0

0

0

0

1

1

1

1

0

F

Nell'esempio vedo che per impostare il nibble alto della porta come uscita e viceversa quello basso devo impostare questo valore binario nel registro PORTB='00001111'b oppure in esadecimale PORTB=0x0F. Dopo aver caricato questo valore nel registro il microcontrollore attiva l'hardware interno per far funzionare la porta come da richiesta, quindi attenzione a non sbagliare perché come detto sopra un uscita usata in modo errato provoca dei guasti irreparabili.


PORTA, PORTB, PORTC, PORTD e PORTE : per leggere lo stato logico degli ingressi digitali o scrivere lo stato logico delle uscite digitali delle porte si usano i registri specifici che hanno il nome delle porte. Quindi, prendendo come esempio quello sopra del TRISB, con il registro PORTB posso scrivere nel nibble alto e leggere lo stato dei pin nel nibble basso. Per esempio :


RB7

RB6

RB5

RB4

RB3

RB2

RB1

RB0

Output

Output

Output

Output

Input

Input

Input

Input

1

0

0

1

0

0

1

1

Questi li scrivo da programma

Questi li leggo da programma


Da programma posso fissare singolarmente o in blocco, con le specifiche istruzioni, i bit di uscita. Invece, posso andare a leggere singolarmente i vari pin di ingresso (questo vale quando gli ingressi sono di tipo digitale, vedremo successivamente l'utilizzo degli ingressi analogici).


ISTRUZIONI :


legenda per capire la tabella delle istruzioni:



sotto è rappresentata una tavola riassuntiva delle istruzioni (presa dal datasheet), che suddivide le istruzioni per gruppi funzionali, con i codici operativi e l’influenza sui flag. Nella colonna 14-Bit Opcode :



fff ffff indicano i 7 bit specificati dall’indirizzo f

kkkk kkkk gli 8 bit di una costante di dato 0 â‰¤ k â‰¤ 255

kkk kkkk kkkk gli 11 bit di una costante d’indirizzo 0 â‰¤ k â‰¤ 2047.