Progetto per l'autodirezionalità del robot n°5

Tesina

Stepper

Darlington

Visual C++

C Builder

Assembler

Alim. Switching

La Robotica

Il PIC 16F84, un microcontrollore integrato in un chip da 18 pin con ben 13 linee di I/O ed una memoria di tipo FLASH.

. E' un microcontrollore a 8 bit della Microchip che si presenta in un contenitore a 18 piedini. L'integrato richiede una tensione di alimentazione compresa tra 2V e 6V (valore tipico di 5V) da applicare ai terminali indicati con VDD (terminale positivo) e Vss (terminale di massa GND). I pin OSC1/CLKIN e OSC2/CLKOUT devono essere collegati ad un circuito oscillatore, ad esempio un quarzo o una rete RC, per generare il clock di sistema. La frequenza massima di tale segnale è di 10 MHz (20 MHz per il modello 16F84A). Nelle applicazioni che seguono si farà uso di un circuito oscillante che utilizza un quarzo di 4MHz

Modulo PIC

CPU

Registri

RISC

Piedinatura

Memoria

Microchip Assembler

   
 

 

L'unità centrale di elaborazione CPU è di tipo RISC (Reduced Instruction Set Computer) con un set di istruzioni ridotto a sole 35 istruzioni in grado di elaborare dati a 8 bit con già inclusi i metodi di indirizzamento immediato, diretto ed indiretto. II modo di operare sfrutta la tecnica denominata pipeline a 2 stati per cui mentre viene eseguita un'istruzione, contemporaneamente viene caricata l'istruzione successiva nel registro delle istruzioni per la decodifica. Ciò si traduce in una riduzione del tempo di esecuzione di ciascuna istruzione.
In particolare, se si escludono le istruzioni di salto che richiedono due cicli macchina, il tempo di esecuzione di una istruzione ha una durata pari ad un ciclo macchina che corrisponde a 4 impulsi di clock. Pertanto, se la frequenza di clock è fCK = 4MHz il tempo richiesto per eseguire un'istruzione vale 4TcK = 1 µs.
La CPU (Central Processing Unit) è in diretta connessione con l'unità aritmetica e logica ALU per svolgere tutte le operazioni imposte dal programma.
Il PIC si avvale di 15 registri speciali. In particolare il registro accumulatore W è un registro interno privilegiato ampiamente utilizzato dal microcontrollore per svolgere moltissime operazioni come somma, sottrazione, memorizzazione temporanea dei dati, ecc. Un registro fondamentale per il funzionamento del microcontrollore è il Program Counter PC. E' un registro contatore che si incrementa automaticamente durante l'esecuzione di un programma in modo da contenere l'indirizzo della successiva istruzione che deve essere eseguita. Solo nel caso di istruzioni di salto il suo valore viene modificato in modo da contenere l'indirizzo dell'istruzione relativa al salto. Dopo un comando di RESET il registro PC è azzerato e punta alla locazione OOOOH della memoria di programma che deve, pertanto, contenere la prima istruzione da eseguire. Il RESET del PIC si realizza ad hardware portando la linea MCLR (pin 4) al livello basso. Tale linea deve essere tenuta, normalmente, al livello alto VDD.
L'integrato dispone di 13 linee bidirezionali di UO; 5 indicate con RAO... RA4 costituiscono la PORTA A e 8 con RBO RB7 la PORTA B. Ciascuna linea può essere programmata come Input o come Output ed è in grado di assorbire (sink current) fino a 25mA ed erogarne (source current) fino a 2OmA.

 
   
Top

Schema a blocchi di funzionamento del dispositivo.

   
Top
  Architetture RISC

L'utilizzo efficiente della pipeline dipende molto dall'uniformità delle istruzioni. Se i tempi di esecuzione delle singole fasi fossero infatti diversi da istruzione ad istruzione, si correrebbe il rischio di sospendere uno stadio, in attesa che l'istruzione precedente termini lo stadio successivo. Una caratteristica importante in questo senso è data dalla lunghezza delle istruzioni. Se le istruzioni avessero lunghezze diverse (come nel caso dell'architettura Motorola 68K o CISC), la fase di fetch potrebbe richiedere degli accessi aggiuntivi alla memoria, e pertanto non sarebbe caratterizzata da un tempo di esecuzione costante, come invece avverrebbe se tutte le istruzioni avessero sempre la stessa lunghezza.
Istruzioni di uguale lunghezza sono caratteristiche delle architetture RISC, che sono in generale caratterizzate da un set semplificato di istruzioni rispetto alle architetture CISC (Complex Instruction Set Computer), ma che richiedono un tempo di esecuzione assai più breve.

La differenza filosofica tra le architetture RISC e CISC è che mentre in quest'ultima si cercava di fornire istruzioni potenti (tipicamente realizzate tramite la microprogrammazione), nelle architetture RISC vengono favorite le istruzioni semplici (realizzate direttamente in hardware), anche a costo di dover eseguire una sequenza di istruzioni semplici al posto di una singola istruzione più potente. Si è infatti osservato che nella maggioranza dei casi i programmi sono formati da istruzioni semplici, e pertanto il guadagno in performance velocizzando queste ultime risulta maggiore dell'eventuale perdita dovuta al fatto che più istruzioni sono richieste per operazioni più complesse, ma che avvengono con minore frequenza.

Oltre alla stessa lunghezza delle istruzioni, all'organizzazione hardwired ed alla minore dimensione del set di istruzioni, le istruzioni in un'architettura RISC sono caratterizzate da una notevole riduzione delle modalità di indirizzamento che fa si che il numero di cicli di clock necessario per l'esecuzione di un singolo stadio sia circa pari ad 1. Ciò significa che, in assenza di hazards, il tempo medio di esecuzione è di un periodo di clock per istruzione nelle architetture RISC. Se poi gli stadi vengono replicati nella CPU (architetture superscalari) consentendo quindi l'esecuzione parallela dello stesso stadio da parte di più di un'istruzione, il tempo medio di esecuzione risulta essere inferiore al periodo di clock.

Un'altra caratteristica dei processori RISC è data dall'elevato numero di registri (normalmente > 32) che consentono quindi di ridurre la necessità di accedere alla memoria esterna.

Va infine osservato che un programma in assembly per un processore RISC risulta più difficile da comprendere, ed è tipicamente più lungo di un programma equivalente per un processore CISC. Si deve tuttavia tener conto che tali programmi sono tipicamente prodotti da un compilatore, che potrà inoltre applicare una serie di ottimizzazioni per sfruttare al meglio le potenzialità della particolare architettura.

 
   
Top

Piedinatura dell' integrato

RA0-RA4 sono le linee della porta A configurabili separatamente come IN o OUT.
RB0-RB7 sono le linee della porta B configurabili separatamente come IN o OUT.
MCLR è il master reset utile per resettare il PIC a livello hardware (normalmente a livello +Vcc, si porta a livello 0 per il reset).
Vss alimentazione positiva da 2 a 5,5 volt.
Vdd massa.
RB0 è il pin che in programmazione può essere usato per gestire interrupt esterni.
OSC1 e OSC2 pin utilizzati per il clock tramite quarzo oppure con rete RC, CLKIN può essere usato per inviare un clock esterno.
RB6 e RB7 vengono usati in programmazione rispettivamente come DATA e come CLOCK.

Top

Il PIC 16F84A ha una configurazione in memoria come segue:

 

Concettualmente il principio di funzionamento di un PIC è molto semplice:
Lo stack (una locazione di memoria) mantiene l'indice dell'istruzione da eseguire, ogni ciclo di clock viene eseguita l'istruzione indicata dallo stack seguendo riga per riga il programma memorizzato nella EEPROM accedendo ad una memoria unica chiamata accumulatore. Nella RAM vengono salvati i dati temporanei e una volta spento il PIC vengono persi. Per memorizzare invece dei dati in modo permanente c'è a disposizione una EEPROM. Esistono alcune locazioni di memoria prefissate e chiamate Register che contengono tutti i dati di configurazione e permettono di definire ad esempio quali linee sono di ingresso e quali di uscita, se si usano interrupt, se si usa il timer ecc... Tutti i PIC hanno grosso modo la stessa configurazione di memoria ma cambia la quantità disponibile.

Top
listato dettagliato di un programma scitto in Microchip Assembly

PROCESSOR 16F84

RADIX DEC

INCLUDE

"P16F84.INC"

__CONFIG 3FF3H

ORG 0CH

Count RES 2

Direz RES 1

ORG 00H

bsf STATUS,RP0

movlw 00000000B

movwf TRISA

movlw 00000000B

movwf TRISB

bcf STATUS,RP0

movlw 00000001B

movwf PORTB

clrf PORTA

clrf Direz

clrf Count

clrf Count+1

bcf STATUS,C

MainLoop

call Delay

btfss Direz,0

goto Sali

Scendi

rrf PORTA,F

rrf PORTB,F

btfsc PORTB,0

bcf Direz,0

goto MainLoop Delay

movlw 40

movwf Count+1

DelayLoop

decfsz Count,F

goto DelayLoop

decfsz Count+1,

goto DelayLoop

return Sali

rlf PORTB,F

rlf PORTA,F

btfsc PORTA,3

bsf Direz,0

goto MainLoop

END

Direttiva PROCESSOR: dice al programma che stiamo utilizzando il PIC 16F84

Direttiva RADIX: specifica che i numeri sono in formato decimale. Cioè se scrivo 10 significa il numero decimale 10, diverso da 0x10 (esadecimale del numero 16) e 00000010B (binario di 2)

Direttiva INCLUDE: specifica al compilatore di caricare quel file, che include le definizioni di alcuni parametri standard.

Direttiva CONFIG: setta i fuses del pic. 3FF3 significa NO,YES,NO,RS.

Direttiva ORG 0Ch: dice al compilatore che cio che segue fa parte della RAM.

Direttiva RES: riserva 'n' bytes di memoria per la variabile (2 bytes per Count e 1 per Direz)

Direttiva ORG 00H: dice al compilatore che da qui in poi inizia il programma vero e proprio. In caso di reset del pic, si riparte da qui.

Istruzione BSF: mette a 1 il bit specificato (RP0) nel registro specificato (STATUS). In realtà RP0 e STATUS sono dei numeri e sono definiti in quel file .inc che abbiamo incluso sopra. Ovviamente RP0 sarà un numero che va da 0 a 7 dato che ogni registro o cella di ram ha 8 bit. Ad esempio:
bsf PORTB,4 -> alza il 5° piedino (RB4) della porta B, ponendolo a livello alto.

Istruzione MOVLW: carica nell'accumulatore (indicato con 'W' nei PIC) una costante. Nel caso 0.

Istruzione MOVWF: mette l'accumulatore nel registro specificato (TRISA)

Istruzione BCF: contrario di BSF, mette a 0 il bit.
Significato di questo blocco: TRISA e TRISB sono i registri (8 cellette di memoria) che specificano se le porte A e B sono di ingresso o uscita. 0 significa uscita, 1 ingresso. Caricando 0 in a e in B, otteniamo la configurazione delle 2 porte come porte di uscita. Per andare a modificare questi 2 registri dobbiamo prima mettere a 1 RPO. Alla fine lo rimettiamo a 0. Una istruzione tipo:
bsf TRISB,3 -> non fà nulla se RP0 è basso, mentre se viene eseguita prima che venga abbassato RP0, setta la 4a linea della porta A come ingresso.

Istruzione CLRF: mette a 0 una variabile o registro.
Significato del blocco. PORTB è la porta B; scrivendo su questa si vanno a cambiare gli stati delle linee della porta B. In pratica; della porta B viene attivata solo la prima linea (bit 0) le altre tutte basse. Tutte basse anche quelle della porta A. Mettiamo a 0 la variabile Direzione (0 = salita 1 = discesa), la Count e la Count+1 (che non ha nome, ma per count avevamo riservato 2 bytes). Notare che Count+2 corrisponderebbe a Direz. Infine viene pulito il bit CARRY che si trova nel registro STATUS, dove avevamo incontrato anche RP0.
Ora arriva il programma principale:

Istruzione CALL: chiama una subroutine. In questo caso lancia la funzione 'delay'.

Istruzione BTFSS Direz,0: controlla il bit '0' della variabile 'Direz' e salta l'istruzione successiva se il bit è uno, mentre l'eseguirà se il bit è zero.
In questo blocco, dopo avere ritardato di un po' l'esecuzione con la funzione delay, si controlla se stiamo salendo o scendendo. Nel primo caso il bit 0 di direz è a 0, per cui salterà alla funzione 'Sali', mentre se fosse a 1 continuerebbe l'esecuzione saltando il 'goto Sali'. Ovviamente laddove salterà ci sarà la funzione scendi.

Istruzione RRF: ruota a destra una variabile, inserendo come nuovo bit il carry e ponendo quello che esce nel carry.
Come spiegato in precendenza, faccio scorrere verso giu il bit ruotando a destra dalla porta A alla porta B. Successivamente controllo se sono a fine discesa (cioè ho l'1 nel bit 0 della PORTB). Se no, continua daccapo, altrimenti si cambia direzione (da 1 a 0) e si riparte daccapo.

Istruzione DECFSZ: Decrementa una variabile e salta l'istruzione successiva se vale zero. Per fare un delay, l'istruzione successiva sarà un goto a questa istruzione, di modo che decrementi ciclicamente la variabile e quando vale 0, esca dal ciclo.

Istruzione RETURN: termina una call, tornando al programma principale dove era stata chiamata la funzione.
In questo blocco, settiamo a 40 il valore di Count+1. Poi c'è un ciclo interno che ripete 256 volte il decremento di Count e la goto, e un ciclo più esterno che ripeterà 40 volte il ciclo interno. Per ottenere un ritardo accettabile insomma, dobbiamo fare circa ventimila operazioni.

Alessandro del Gallo