Come lavorano i microprocessori
Nota: Per semplificare la descrizione non faccio per ora nessuna distinzione tra
microprocessore e microcontrollore, ne tratto i vari tipi.
Invece penso a chi vuole sapere qualche cosa di più sui modi e principi di
come queste macchine elettroniche riescono a funzionare con i programmi a
livello macchina, per capire la cosidetta intelligenza artificiale.
Naturalmente il linguaggio assembler ha delle abbreviazioni legate al tipo
di microprocessore usato, e poi in pratica, si deve sucessivamente
assemblare o trasformare le istruzioni e i dati in modo che diventi un
codice binario eseguibile.
NOTA(*): Per avere una descrizione completa degli argomenti si deve naturalmemte
consultare dei manuali tecnici specifici.
Contenuto(*):
1) Introduzione
2) Il sistema binario
3) Le funzioni logiche
4) Le conversioni numeriche, (binario-decimale-esadecimale-ascii)
5) Le funzioni aritmetiche
6) I registri del microprocessore Zilog Z80 e del microcontrollore Atmel AT89C2051 (8051)
7) Gli indirizzi e i dati in binario
8) La lettura e scrittura in memoria
9) L'uso delle porte esterne, (ingresso e uscita I/O)
10) Il salvataggio temporaneo dei registri nello stack
11) La trasformazione di una Word in due byte
12) Lo scambio tra i registri
13) Le istruzioni dirette al singolo bit
14) Le istruzione di chiamata ai sottoprogrammi e del salto ai programmi
15) Le istruzioni NOP e HALT
16) Cosa sono le interruzioni
17) Il registro di guardia (WATCH DOG)
18) L'acquisizione dei dati analogici (A/D)
19) La conversione dei dati numerici in analogici (D/A)
20) Il sistema a multiprocessore
(1) Introduzione
Per capire il linguaggio assembler usato per programmare i microprocessori,
con tutte le funzioni di controllo in ingresso e uscita come pure le operazioni
logiche e aritmetiche, rappresentate di solito con abbreviazioni mnemoniche della
lingua inglese, è necessario avere una nozione di base possibilmente nel campo
della logica elettronica.
E' utile a questo scopo, comprendere cosa in pratica succede in un'operazione
binaria, tenendo a mente che i microprocessori e le macchine numeriche in
generale, essendo costruite con logica elettronica in effetti conoscono solo
due valori: lo zero (0) e l'uno (1), corrispondenti a mancanza o presenza di
tensione su un conduttore, rispetto alla massa comune che è sempre il
riferimento di zero volt.
(2) Il sistema binario
Le operazioni si fanno usando il parallelo di questi singoli conduttori,
il cui valore unitario ha il nome di bit (dall' Inglese).
Più conduttori in parallelo possono contenere in totale dei numeri più
grandi di 0 e 1, in quanto ponendo la base 2 per ogni singolo bit,
come in decimale usiamo la base 10, vi è il seguente parallelo:
Numero DECIMALE Corrispondente a numero BINARIO (4 bit)
Esempio: 15 1 1 1 1
(Decina=1 Unità=5) Scomposizione (8)+(4)+(2)+(1)
12 " " " 1 1 0 0
(Decina=1 Unità=2) (8)+(4)+(0)+(0)
Come si vede allo stesso modo del decimale il peso (valore) del singolo
bit cresce secondo la comune direzione da destra verso sinistra.
I termini usati per raggruppare più bit insieme sono i seguenti:
4 bit = Nibble, 8 bit (2 x 4) = Byte, 16 bit (8 x 4) = Word
Peso (valore numerico) dei singoli bit di una Word
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
(32768)(16384)(8192)(4096)(2048)(1024)(512)(256)(128)(64)(32)(16)(8)(4)(2)(1)
Con 4 bit il numero massimo in decimale che si può usare è 15, ossia 16
conbinazioni tenendo conto anche dello zero.
Con 8 bit le combinazioni passano a 16 x 16 ossia 256, per cui il numero
massimo è 255, e se lo usiamo come contatore diventa naturalmente 256.
Così con 16 bit passiamo a numeri più grandi 256 x 256 ossia 65536
combinazioni, il numero massimo sarà 65535 e il contatore 65536.
Si usa anche il bit più alto per identificare i numeri negativi, esempio con 8 bit:
127 = 01111111B, -127 = 11111111B, -128 = 10000000B, -32 = 10100000B
con 16 bit: 32767 = 0111111111111111B, -32767 = 1111111111111111B
Naturalmente come capita per noi ogni giorno, più trattiamo con numeri di
piccole dimensioni e più troviamo facile fare anche mentalmente le comuni
quattro operazioni, ugualmente possiamo seguire meglio gli esempi con
numeri piccoli.
Nei microprocessori le quattro operazioni sono spesso semplificate con
le due operazioni base, la somma e la sottrazione (mentre moltiplicazione
e divisione si ricavano dalla combinazione delle prime due) ; in più ci
sono poi le operazioni logiche legate ai circuiti elettronici da cui derivano.
Oltre al risultato, in tali operazioni si controlla anche un particolare
valore o condizione (Flag), che dopo l'operazione può avere i due classici
valori di 0 o 1.
Di solito il valore uno ha il significato di conferma (Sì) e naturalmente
lo zero l'opposto (Nò), e da queste due condizioni si possono poi eseguire
delle sucessive scelte dal programma.
(3) Le operazioni o funzioni logiche
Se comprendiamo per prima queste operazioni logiche, siamo già a buon punto
nella comprensione del linguaggio macchina dei microprocessori.
Allora proviamo prima a fare qualche operazione logica con soli 4 bit.
La funzione logica (AND)
E' quella dove in pratica comanda lo zero, ossia se prendiamo due fili,
uno a livello (1) e l'altro a livello (0) e li colleghiamo insieme, se
il circuito elettronico esegue un'operazione AND significa che entrambi
i conduttori andranno a livello logico zero (0).
Esempio con numeri a 4 bit e il flag Z (zero):
1111 AND 0000 = 0000 (Z = 1), 1010 AND 1111 = 1010 (Z = 0)
1111 AND 1100 = 1100 (Z = 0), 1001 AND 0111 = 0001 (Z = 0)
La funzione AND si usa anche per testare il valore di un singolo bit,
servendosi del flag Z.
Esempio: si vuole controllare la condizione variabile del bit 3 (8 decimale),
di un ingresso binario (X) a 4 bit per poi eseguire una scelta con il
programma sucessivo.
(X = 1111) AND 1000 = 1000 (Z = 0), (X = 0111) AND 1000 = 0000 (Z = 1).
(8) (8)
Molti microprocessori o microcontrollori hanno anche istruzioni dirette
per testare singoli bit.
La funzione logica (OR)
In questo caso è l'uno che comanda, prendiamo i soliti due fili se uno
si trova a livello (0) e l'altro a livello (1), collegandoli insieme e
il circuito elettronico è predisposto per fare una funzione OR, il
risultato sarà che entrambi i conduttori si troveranno a uno (1).
Esempio con numeri a 4 bit e il flag Z (zero):
1111 OR 0000 = 1111 (Z = 0), 1010 OR 1000 = 1010 (Z = 0)
0000 OR 0000 = 0000 (Z = 1), 1100 OR 0011 = 1111 (Z = 0)
Come si vede negli esempi solo quando, entrambi i numeri sono a zero
il flag Z è uguale a uno; con l'OR si può così testare i numeri sconosciuti,
per fare una determinata scelta quando sono uguali a zero, (Z = 1).
La funzione OR può eseguire anche una somma esatta fra due numeri binari,
a patto che non ci siano due bit dello stesso peso a uno.
1000 OR 0100 = 1100, 0011 OR 0100 = 0111, 1010 OR 0011 = 1011 (11) Errore!
(8) + (4) = (12) (3) + (4) = (7) (10) + (3) = (13)
Questa funzione in elettronica si presta facilmente nel controllo degli
allarmi multipli; se abbiamo ad esempio 16 ingressi (16 bit) a livello zero,
e vogliamo far scattare un'allarme quando uno di questi va a uno, si usa
la funzione OR.
La funzione logica (NOT o CPL Complemento)
E' l'opposto del segnale in ingresso, se abbiamo un filo ad uno dopo il NOT
o CPL sarà a zero e viceversa se è a zero diverrà a uno.
Esempio con numeri a 4 bit:
1111 NOT/CPL = 0000, 0000 NOT/CPL = 1111, 0110 NOT/CPL = 1001, 1010 NOT/CPL = 0101
Eseguendo due volte il NOT o CPL su un certo numero o ingresso elettronico,
lo si riporta al valore iniziale.
Quando questa funzione (NOT) è usata in abbinamento alle precedenti funzioni,
AND e OR esse vengono chiamate NAND e NOR.
Il complemento di un numero binario è uguale al suo reciproco.
Per trovare il reciproco si deve sottrarre da (1111 per 4 bit) il numero da convertire.
Esempio: il complemento di 1001 (9) è uguale a 1111 (15) meno 1001 (9) ossia 0110 (6).
Lo stesso principio vale con numeri più grandi, il complemento di 11001111 (207) è
uguale a 11111111 (255) meno 11001111 (207) che da come risultato 00110000 (48).
La funzione logica (XOR) OR esclusivo
Questa funzione XOR (disgiunzione) è come l'OR, eccetto che quando i due nostri
conduttori hanno lo stesso valore (non zero) , ossia presenza entrambi di tensione,
invece di avere come risultato sempre i due fili a uno (1), questi passano immediatamente
a zero (0).
Esempio con numeri da 4 bit:
1111 XOR 1111 = 0000 (Z = 1), 1111 XOR 0001 = 1110 (Z = 0), 1110 XOR 0001 = 1111 (Z = 0)
La funzione logica XOR è molto usata nei circuiti a PLL, dove esiste un controllo
numerico di un dato oscillatore VCO la cui frequenza viene a sua volta controllata
con una tensione filtrata proveniente da un circuito XOR, dove entrano le frequenze
dell'oscillatore variabile VCO e quella di campionatura proveniente da un'oscillatore
al quarzo entrambi in precedenza opportunamente divisi di frequenza.
La funzione logica (CP) confronto o comparazione
Più che operazione logica si direbbe aritmetica, in quanto il confronto viene fatto
attraverso una sottrazione, solo che non si tiene conto del risultato e quindi i dati
rimangono in'alterati. Modificati, invece i flag di cui i principali sono lo Z (zero)
e il C (carry) bit di riporto, necessario per la corretta aritmetica.
Esempio con numeri a 4 bit:
1011 CP 1010 = (Z = 0) e (C = 0), 1011 CP 1011 = (Z = 1) e (C = 0)
(11) > (10) (11) = (11)
1011 CP 1100 = (Z = 0) e (C = 1)
(11) < (12)
Come si vede negli esempi, Z è uguale a uno solo quando i dati confrontati sono identici,
quindi questo sistema è usato per la ricerca rapida di uno o più dati conosciuti all'interno
di un particolare blocco di dati da esaminare.
Ugualmente quando per esempio facciamo la ricerca di una determinata parola dentro un testo
che stiamo esaminando con il nostro pc, attiviamo un programma di ricerca per comparazione
o confronto.
La funzione logica di scorrimento e rotazione dei bit
Queste funzioni usano anche il bit di riporto C (carry) delle operazioni aritmetiche.
Esempio se sommiamo due numeri a 4 bit, come 13 (1101) + 10 (1010), otteniamo
il totale di 23 (10111), dove il quinto bit il carry è a uno (1).
In questo esempio dove abbiamo come capacità di calcolo solo dati a 4 bit, vediamo che
si possono tranquillamente trattare cifre molto più grandi con l'uso del flag (C) carry,
e quando necessario si possono eseguire anche più operazioni consecutive e complesse.
Detto questo, le funzioni di scorrimento e rotazione dei bit sia verso sinistra che
verso destra servono a molteplici scopi.
Alcuni dispositivi hanno diversi comandi in tal senso, tratto però solamente le
principali di cui la prima è lo scorrimento (SHIFT).
Esempio con numeri da 4 Bit:
1101 SHIFT verso sinistra = (C) <-(1)1010 <-(0), Entra lo zero da destra e l'uno di
sinistra esce e va nel carry, se ripetiamo l'operazione, perdiamo il bit che era nel
carry (C). Questo è uno scorrimento chiamato (aperto), facendolo verso destra;
1101 SHIFT verso destra = (0)-> 0110(1)-> (C), avviene l'opposto.
Come si capisce dagli esempi si spostano i pesi dei bit per cui verso destra si divide
il numero binario per due, e viceversa lo si moltiplica per due verso sinistra.
Se lo scorrimento è ad anello (circolare) con l'attraversamento o meno del carry, allora
si tratta di una rotazione a destra o a sinistra.
Esempio di rotazione circolare attraverso il bit (C) carry:
1101 Ruota verso sinistra = (C)-------(X)-->---* Risultato (C=1) e dato = 101X
^ |
| |
*---<(1) 101X<----*
1101 Ruota verso destra = (C)<-----(1)-------* Risultato (C=1) e dato = X110
| |
| |
*--(X)->X110--->--*
Ad uso aritmetico decimale alcuni processori hanno delle istruzioni di shift, che
coinvolgono gruppi di 4 bit (nibble) in modo da trattare numeri in BCD.
Uno dei tanti scopi di queste operazioni logiche, oltre a quello matematico è
la trasformazione di dati paralleli in dati seriali e viceversa con l'uso del flag (C).
Malgrado si perda di velocità i dati seriali permettono una semplicità notevole
del circuito, e pure l'uso di componenti attivi con meno terminali. Un'esempio fra i
tanti; una memoria eprom parallela da 8 Kbyte usa uno zoccolo con 28 pin (terminali),
mentre una eeprom (cancellazione elettrica) seriale corrispondente, usa solo 8 pin.
(Naturalmente in certi casi la prima non può essere sostituita dall'altra).
Sovente queste semplificazioni permettono un notevole risparmio di lavoro e ingombro
con un evidente vantaggio pratico ed economico.
(4) Le conversioni numeriche
Come sappiamo i microprocessori vedono solo dei numeri nel loro linguaggio binario,
ma noi come essere umani usiamo i numeri decimali, e la comune tastiera del pc,
dove ci sono tutti i classici simboli alfanumerici, programmabili secondo la lingua
che usiamo.
Per questo, quando parliamo di operazioni su numeri binari a 4 bit, se vogliamo
usare questo nibble per calcoli con risultato decimale (BCD), abbiamo da fare una
conversione in quanto ogni nibble può contenere solo una cifra decimale.
Per cui 4 nibble (16 bit) in binario arrivano a 65535, ma in decimale solo a 9999.
E' necessario a questo punto trattare un'attimo il codice esadecimale (Hex), che
in pratica per racchiudere in un unico simbolo i numeri binari oltre la cifra 9,
si è dato ai numeri superiori le prime lettere dell'alfabeto, e quindi A = 1010 (10),
B = 1011 (11), C = 1100 (12), D = 1101 (13), E = 1110 (14), F = 1111 (15).
La conversione esadecimale in binario e viceversa è facile in quanto ogni cifra,
o lettera corrisponde come abbiamo visto sempre ad un nibble.
Esempio : 255(D) = 11111111(B) = FF(H), 100 = 01100100 = 64, 222 = 11011110 = DE
Per ultimo trattiamo il codice Ascii, usato da molto tempo per rappresentare i
caratteri alfabetici nei computer, stampanti, ecc. Di base è un codice a 7 bit, con
cui si rappresentano i numeri, le lettere e i principali segni di punteggiatura
(interpunzione).
In questo modo, avendo la possibilità di leggere nella nostra lingua un testo o un
messaggio con allegato il risultato di una certa operazione, rendiamo il colloquio
persona-macchina facilmente accessibile a tutti.
Anche quando si introducono dei dati che poi il processore dovrà elaborare, se usiamo
una tastiera alfanumerica, significa che utilizziamo già un processo di
conversione uomo-macchina; il più comune di questi sistemi è certamente l'uso
di programmi per il trattamento dei testi su foglio elettronico.
Ritornando al linguaggio binario le conversioni più usate, che naturalmente si possono
usare anche all'inverso, sono:
Binario -> Decimale (BCD), 1100(12) = 0001 0010 (BCD)
(1) (2)
Binario -> Esadecimale (Hex), 1100(12) = C(H)
Binario -> Ascii, 1100(12) = 00110001 00110010 (Ossia il numero decimale + 48)
(1) (2)
(5) Le funzioni aritmetiche
Queste funzioni molto importanti sono anche molto semplici, e naturalmente possono
far uso del bit di riporto C (carry) nello stato che è prima dell'operazione.
La somma o addizione che come mnemonico può avere ADD o ADC; la prima non tiene conto
del carry che comunque viene sempre modificato, mentre la seconda ne tiene conto.
Con i soliti numeri da 4 bit alcuni esempi:
(C=1) 1100 ADD 1100 = (1)1000, (C=1) 1100 ADC 1100 = (1)1001
(12) + (12) = (24) 1 + (12) + (12) = (25)
Allo stesso modo le sottrazioni sono con o senza carry; SBC e SUB.
Vediamo ancora alcuni esempi a 4 bit:
(C=1) 1100 SUB 1000 = 0100, (C=1) 1100 SBC 1000 = 0011
(12) - (8) = (4) (12) - (8)- 1 = (3)
Queste operazioni modificano alcuni Flag, il più importante è il riporto C.
Alcuni microprocessori hanno pure istruzioni più complesse come la moltiplicazione
e la divisione.
Nella famiglia dei microcontrollori a 8 bit (Intel) tipo 8051 vi è infatti MUL e DIV,
moltiplica e dividi, anche microc. più moderni come l'AVR AT90S8515 (Atmel) hanno
simili istruzioni, mentre per microcontrollori più piccoli spicca il tipo
AT89C2051 (derivato dall'8051) che possiede entrambi le istruzioni.
Avere a disposizione istruzioni potenti, significa poter scrivere programmi più
corti che allo stesso tempo diventano più veloci nell'esecuzione.
La moderna tecnologia però, ha anche ridotto i meccanismi dinamici all'interno
dei microprocessori portando questi ad elevate velocità e ad operare con istruzioni
più semplici (RISC istruzioni a codice ridotto) ; con il sacrificio di allungare
i programmi.
L'Incremento (INC) e il Decremento (DEC)
Si tratta della somma o della sottrazione di uno, molto usati come istruzioni
di conteggio nei cicli multipli di programmi più o meno complessi.
IL flag Z è quello interessato, per questo motivo è stata fatta pure l'istruzione
DJNZ N,X che significa decrementa di uno N e salta all'indirizzo X fino a che
Z è diverso da uno ossia N diventa zero.
Spesso i microp. che lavorano con numeri doppi da 8 bit, eseguono INC e DEC
direttamente a 16 bit, ma il controllo del valore di zero è sempre fatto su
numeri a 8 bit, a motivo della loro struttura aritmetica interna.
Il concetto dei salti condizionati lo riprenderemo poi quando parleremo dell'uso
nei programmi dei registri di memoria di un microprocessore.
(6) I registri del microprocessore Z80 e del microcontrollore AT89C2051
A questo punto è necessario parlare dei famosi registri, che sono delle memorie a
8 - 16 bit e per quelli più potenti anche 64 bit. Queste memorie chiamate (Registri),
perchè sono usate dal programma per eseguire tutte le funzioni e che poi trattengono
i dati necessari, per il corretto funzionamento.
Secondo il tipo di microP. o microC. e pure l'età di costruzione, abbiamo molteplici usi.
Per semplificare descrivo i più importanti:
L'Accumulatore (A), è il registro che esegue tutte le operazioni logiche e aritmetiche,
in alcuni microcontrollori, (esempio lo Zilog Z8) non è specificato, in quanto tutti i
registri di uso comune sono pure in grado di fare queste operazioni, mentre nell'8051
invece oltre all'accumulatore vi è il registro B usato in coppia con A per la
moltiplicazione e divisione.
Il registro di Flag, di solito a 8 bit che tiene conto di tutti i fattori implicati,
carry, mezzo carry (per 4 bit),zero, parità, segno, ecc.
I registri indice (IX) e (IY) di solito a 16 bit, possono contenere dati come invece
puntare insieme ad uno scarto fissato, a specifiche locazioni di memoria sia di programma
che di ram.
I registri di uso comune, da 8 o 16 bit che vengono utilizzati per contatori, puntatori,
locazioni temporanee di dati, ecc.
I registri specifici come (PC) puntatore di programma, (SP) puntatore di stack che serve
per ritenere gli indirizzi di rientro del registro (PC) dopo le chiamate ai sottoprogrammi.
Poi ci sono dei registri specifici per l'uso delle porte parallele, della porta seriale,
il timer, il controllo delle interruzioni con le priorità, il controllo di blocco, ecc.
A questo punto è bene fare una breve e semplice descrizione della differenza fra un
microprocessore e un microcontrollore.
Il primo di solito più potente nell'elaborare i dati, ma che a differenza del secondo,
è incompleto, ossia non possiede delle porte interne come seriali o parallele, come
pure la memoria del programma e dei dati volatili è esterna.
Viceversa il microcontrollore si può chiamare microcomputer, perchè possiede tutto
al suo interno, naturalmente a volte in misura ridotta per contenere il prezzo e
anche perché l'uso è limitato e specifico.
Fra i tanti descrivo la struttura del vecchio e famoso microprocessore della Zilog lo Z80.
Coppie di registri da 8 bit: (AF) Accumulatore con logica e aritmetica 8 bit, più i Flag
(BC) Uso comune o speciale, puntatore porte
(DE) uso comune o speciale con HL
(HL) Aritmetica a 16 bit senza le funzioni logiche
(AF') Ausiliario per uso alternato al principale
(BC') Blocco di tre coppie di registri per uso
(DE') alternato con i principali
(HL') " " "
Registri singoli 8 bit (I) Indice vettore delle interruzioni
" " " (R) Rinfresco memorie dinamiche (automatico)
Registri a 16 bit *(IX) Aritmetica parziale a 16 bit, puntatore dati
" " " *(IY) " " "
" " " (PC) Puntatore del programma
(SP) Puntatore dello Stack
(*) Con alcuni Z80 si può usare i registri indice (IX) e (IY), come se fossero due
da 8 bit. E' sufficente scrivere il codice di riferimento a X o Y e poi la specifica
istruzione diretta ai registri H o L.
Ora vediamo invece uno dei tanti microcontrollori l'AT89C2051, derivato dall'8051,
usa solo due porte delle quattro e 16 registri di uso comune, oltre ad avere due
ingressi del comparatore per i segnali analogici.
Registri principali da 8 bit: (A) Accumulatore con logica e aritmetica delle 4 operazioni
(B) Ausiliario dell'accumulatore e uso comune
(R0-R7) 8 registri in due banchi di cui (R0,R1) puntatori memoria
Coppia registri 8 bit (DPH-DPL) (DPTR) Registro puntatore dati programma
Porta bidirezionale (P1) P1.0-P1.7 (P1.0-P1.1) ingressi del comparatore
" " " (P3) P3.0-P3.7 (P3.6 lettura interna comparatore)
Altri registri a 8 bit (SP) Puntatore dello stack
(PSW) Registro dei flag e banco (R0-R7) in uso
(IP) Priorità interruzioni
(IE) Abilitazione interruzioni
(TMOD) Controllo modo dei due timer a 16 bit
(TCON) Controllo contatori timer
(TH0) Byte alto timer 0 (TR0)
(TL0) Byte basso " "
(TH1) Byte alto timer 1 (TR1)
(TL1) Byte basso " "
(SCON) Controllo porta seriale
(SBUF) Buffer dati porta seriale
(PCON) Controllo consumo alimentazione
I registri A,B,PSW,P1,P3,IP,IE,TCON,SCON, hanno i bit indirizzabili singolarmente
La memoria di programma è di 2048 Byte riscrivibili (4096 per AT89C4051).
La memoria dati (RAM) è di 128 Byte di cui i primi 16 occupati dai registri (R0-R7) per
i due banchi e il resto per uso comune.
Oggi microcontrollori più moderni come gli AVR e altri, hanno anche la ram Flash
riscrivibile, e registri con funzioni aggiunte sui timer (controllo di blocco ) e pure
il controllo di segnali in PWM ossia, la modulazione d'impulso a variazione di fase.
(7) Gli indirizzi e i dati in binario
Gli indirizzi contrassegnati con la lettera A e il numero del bit vicino, servono
come si capisce già dal nome, ad indirizzare un dispositivo da cui prelevare o scrivere
dei dati. Di solito per avere la massima velocità il microp. lavora con gli indirizzi
e i dati in parallelo, ma per memorizzare programmi e grandi quantità d'informazioni,
l'uso più comune è il seriale, a motivo della semplicità di funzionamento e quindi al
limitato costo (vedi i CD e i DVD).
Invece i dati in binario si scrivono con la lettera D e il numero del bit vicino.
(Indirizzo a 16 bit = A15 <---> A0 e dato a 8 bit = D7 <---> D0)
Esempio d'istruzione con l'uso di dati a 8 bit:
MOV 20,#10010000B ;Muovi nella locazione della memoria numero 20 (Dec.)
;il numero binario 10010000 ossia 128 + 16 = 144
I dati e gli indirizzi possono essere scritti anche in forma esadecimale, anzi di
solito gli assemblatori trasformano il listato in un file formato (.Hex) che poi
può essere scritto nella memoria contenente il programma del microp.
(8) La lettura e scrittura in memoria
Lo Z80 è stato il primo microprocessore ad avere delle istruzioni automatiche potenti,
nel trattamento e nella ricerca dei dati. Ad esempio per spostare un blocco di byte,
si carica in BC la lunghezza del blocco, in DE la destinazione ed in HL l'indirizzo
di partenza, con una solo comando (LDIR) il microp. trasferisce tutto in un'attimo.
Allo stesso modo il comando CPIR esegue una ricerca di un valore in un blocco di memoria
e quando lo ha trovato si ferma all'esatto indirizzo.
Ci sono struzioni automatiche anche con l'uso dei dispositivi (IN/OUT) d'ingresso e uscita.
Ecco alcuni esempi di trasferimento di dati.
LD A,(ADR16) ;Carica in accumulatore il dato dall'indirizzo ADR 16 bit (Assembler Z80)
MOV ACC,ADR8 ;Stessa istruzione per 8051 con indirizzo a 8 bit
LD (ADR16),A ;Carica il valore di A nella memoria all'indirizzo ADR (Z80)
MOV ADR8,ACC ;Stessa istruzione per 8051
LD A,(HL) ;Carica in accumulatore il dato dall'indirizzo a 16 bit di HL (Z80)
LD (BC),A ;Carica in memoria all'indirizzo di BC il dato dell'accumulatore
MOV ACC,@R0 ;Carica in accumulatore il dato dall'indirizzo a 8 bit di R0 (8051)
MOV @R1,ACC ;Carica nella memoria dell'indirizzo R1 il dato dell'accumulatore (8051)
MOVC A,@A+DPTR ;Carica in accumulatore il dato dell'indirizzo di A sommato a DPTR (8051)
IL movimento dei dati avviene anche tra gli stessi registri e fra la memoria e i registri.
(9) L'uso delle porte esterne, (ingressi ed uscite I/O)
Lo Z80 ha 256 indirizzi di I/O oltre ai 65536 indirizzi di memoria, altri microprocessori
vedono gli I/O come memoria. In effetti usare un'indirizzo di memoria per gli ingressi e
uscite ne aumenta la velocità notevolmente. Di solito i dispositivi esterni sono più
lenti della memoria e allora si è costruito un banco fisico proprio per questo uso.
I microp. dei personal computer hanno 65536 indirizzi di I/O.
IN A,(ADR8) ;Leggi la porta all'indirizzo ADR8 e metti in accumulatore
OUT (ADR8),A ;Scrivi il valore dell'accumulatore all'indirizzo ADR8 in uscita
MOV P1,ACC ;Scrivi nella porta P1, il valore dell'accumulatore (8051)
MOV ACC,P3 ;Leggi P3 e mettilo in A (8051)
(10) Il salvataggio temporaneo dei registri nello Stack
Questi comandi servono a salvare momentaneamente il contenuto dei registri d'uso
comune oltre all'accumulatore.
PUSH AF ;Salva nello stack il valore dei due registri
POP AF ;Riprendi dallo stack i valori salvati
PUSH DE ;Salva DE
POP BC ;Metti in BC il valore salvato di DE
PUSH PSW ;Salva il registro di stato nello stack (8051)
POP PSW ;Riprendi il registro di stato
PUSH 7 ;Salva il registro R7 (banco 1) nello stack (8051)
POP 10 ;Carica nel registro R2 (banco 2) il valore dello stack (8051)
(11) La trasformazione di una Word in due byte
Come abbiamo visto i registri anche se lavorano con dati a 8 bit, leggono indirizzi
a 16 bit, questo significa che in pratica la parola a 16 bit deve essere divisa in
due parti, quando viene memorizzata. Se vogliamo convertire un numero decimale in
due byte occorre fare la seguente trasformazione:
Convertire il numero NX in byte alto = INT (NX/256), ossia il risultato
intero della divisione, mentre per il byte basso = NX - (INT (NX/256)x 256),
ossia sottrarre la parte intera del byte alto moltiplicata 256 da NX e così ciò che
rimane è il byte basso.
Esempio pratico con 63333: INT (63333/256) = 247 che è il byte alto, per il resto
si fa 63333 - (247 x 256) = 101 che è il byte basso.
Se ora dovessimo caricare i due valori in un registro doppio come DPTR (8051), facciamo
MOV DPH,#247
MOV DPL,#101
Tuttavia questo caso è immaginario, perché l'istruzione corretta è: MOV DPTR,#63333
e ci pensa l'assemblatore poi, formando il listato esadecimale a scomporre in due byte
il numero a 16 bit.
Però è basilare saper fare queste semplici conversioni, quando ci si trova a lavorare
con i microp. a livello di codice macchina.
(12) Lo scambio dei registri
Queste istruzioni permettono di rendere un programma più flessibile e veloce, in
quanto eseguono uno spostamento multiplo tra il contenuto di due o più registri.
Nello Z80 l'istruzione EX AF,AF' scambia la coppia di registri a 16 bit, ugualmente
EX DE,HL mentre EX (SP),HL scambia il contenuto dello stack con HL.
L'istruzione EXX scambia addirittura 6 blocchi da 16 bit, ossia BC DE HL con BC' DE' HL'.
Per l'8051 XCH A,R5 scabio dati tra A e R5 poi XCH A,100 scambio di A con la locazione
di menoria numero 100, XCH A,@R1 scambio tra A e la memoria puntata da R1, XCHD A,@R0
scambio dei due nibble bassi tra l'accumulatore e l'indirizzo della memoria puntata da R0.
C'è anche SWAP A, che esegue lo spostamento del nibble basso al posto di quello alto e
viceversa; anche questa è un'istruzione molto comoda per trattare dati da scomporre.
(13) Le istruzioni dirette al singolo bit
Utili per testare una certa condizione o preparare un singlo bit come flag ausiliario,
per l'uso in programmi più o meno complessi. Con lo Z80 le istruzioni sono:
SET b,R ;Mette a uno il bit b (7-0) del registro R a 8 bit
RES b,R ;Mette a zero " " "
BIT b,R ;Testa il bit b del registro R e modifica di conseguenza il flag Z
Oppure con il registro A e le funzioni logiche già viste:
AND A,64 ;Test bit 6, Z = 0 se D6 di A = 1
OR A,64 ;Mette a uno il bit 6, ossia 01000000B
AND A,191 ;Mette a zero il bit 6, 191 = 10111111B
Ecco alcuni esempi dalle istruzioni dell'8051 che sono molto semplici e pratiche.
SETB P3.4 ;Mette a uno il bit 4 della porta P3
SETB P1.0 ;" " 0 " P1
CLR P3.4 ;Azzera il bit P3.4
CPL P3.4 ;Esegue il complemento del valore del bit P3.4
SETB TR0 ;Attiva il clock del timer 0
CLR TR1 ;Ferma il clock del timer 1
CLR EA ;Disabilita le interruzioni
SETB EA ;Abilita le interruzioni
JB P1.0,X ;Salta all'indirizzo di X se P1.0 è a uno
JNB P1.0,X ;Salta all'indirizzo di X se P1.0 è a zero
JB RI,X ;Salta all'indirizzo di X se la porta seriale ha ricevuto un byte
JNB TI,$ ;Ferma il programma, e prosegue solo quando un byte è stato interamente
;trasmesso dalla porta seriale
JBC ACC.7,X ;Salta all'indirizzo di X se il bit 7 di A è a uno e poi lo mette a zero
NOTA: Poichè l'8051 non ha dei registri di memoria in ingresso alle porte, i pin di queste
porte P1 e P3, se per qualche motivo sono cortocircuitati verso massa o comunque
con un valore resistivo basso, (rispetto alla resistenza interna che è di 27 K
verso VCC) quando si vanno a leggere anche se messi a uno in uscita, possono
dare valore zero in entrata.
(14) Le istruzioni delle chiamate a sottoprogrammi e dei salti di programma
Anche queste istruzioni sono essenziali per abbreviare e velocizzare la stesura e
l'esecuzione dei programmi. Possono essere immediate o condizionate dai flag.
Quando viene eseguita una chiamata (CALL) il microp. salva nello stack l'indirizzo di
rientro , per cui dopo ogni CALL si deve trovare alla fine della routine chiamata, il
comando RET che comanda di ritornare di nuovo al programma principale lasciato
temporaneamente, secondo l'indirizzo salvato nello stack.
Alcuni esempi dello Z80:
Otto chiamate restart (RST X)
RST 8 ;Chiamata indirizzo basso di memoria (8) con una istruzione da un byte
RST 32 ;" " " (32) " "
CALL 32500 ;Chiamata diretta all'indirizzo della memoria
CALL C,32500 ;Chiamata a condizione che il flag C è uguale a uno
CALL NC,32500 ;" " " " è uguale a zero
CALL Z,32500 ;" " " il flag Z è uguale a uno
CALL NZ,32500 ;" " " " è uguale a zero
JP (HL) ;Salta all'indirizzo a 16 bit della memoria, puntato dal registro HL
JP 32500 ;Salta all'indirizzo della memoria
JP C,32500 ;Salta all'indirizzo della memoria a condizione che C = 1
JP NZ,32500 ;Salta " " " " Z = 0
JR 32500 ;Salto relativo con spiazzamento, ossia la massima distanza è di 127 byte
;in avanti e 128 byte indietro, questo permette di avere l'indirizzo del
;salto in un unico byte. Inoltre se in un programma ci sono solo salti
;relativi, questo si può riallocare comodamente senza ricalcolare gli
;indirizzi; il microp. 8085 dell'M10 manca di questa versatile istruzione.
JR Z,32500 ;Salto relativo controllato dal flag Z = 1
DJNZ B,X ;Significa B-1 e salta a X fino a che B <> 0
Alcune istruzioni simili per l'8051:
ACALL XX ;Chiamata a sottoprogramma con istruzione abbreviata 2 Byte per XX a 11 bit
LCALL XX ;" " normale 3 byte per XX a 16 bit
AJMP XX ;Salto distante al massimo 11 bit (2KB)
LJMP XX ;Salto con distanza oltre i 2KB
JMP X ;Salto corto relativo + 127 o - 128 byte
JMP @A+DPTR ;Salto indicizzato dalla somma di A con DPTR
JC XX ;Salto relativo con C = 1
JNZ XX ;" " Z = 0
JNB P1.7,X ;" " con il bit P1.7 = 0
JBC ACC.5,X ;" " " il bit 5 di A = 1 e poi lo mette a zero
CJNE A,#N,X ;Confronta A con N, e se sono diversi salta a X
CJNE @R0,#N,X ;" " il contenuto della memoria puntata da R0 con N e salta a X se diverso
DJNZ 50,X ;Decrementa la locazione 50 e salta a X se non è uguale a zero
I ritorni da sottoprogrammi con l'uso dello stack
RET ;Dopo una CALL (Anche per 8051)
RETI ;Dopo una interruzione " " "
RETN ;Dopo " " " non mascherabile
RET C ;Con C = 1
RET NZ ;Con Z = 0
(15) Le istruzioni NOP e HALT
Per tutti i microp. NOP significa non fare niente e quindi lascia passare un determinato
tempo; per lo Z80 sono quattro cicli di clock della frequenza del microp. e per l'8051
un solo clock.
Halt per lo Z80, ferma il microp. in attesa di una interruzione, l'8051 non possiede
questa istruzione ma lo si può fermare controllando il registro PCON (controllo di potenza).
PCON.0 se uguale a uno limita il consumo del microc. e lascia attive le interruzioni, con
PCON.1 uguale a uno invece si ferma il microc. porta il consumo a circa 20 uA e riprende a
funzionare solo con un reset fisico.
(16) Cosa sono le interruzioni
Come dice la stessa parola, interrompono l'esecuzione del programma in corso, ogni qual
volta avviene una richiesta urgente, per cui il microp. da la priorità a questa, altrimenti
si potrebbero perdere dei dati o comunque generare un errore più o meno grave del sistema.
Appena il programma dell'interruzione è finito, il processore ritorna ad eseguire quello
che aveva temporaneamente interrotto. Data l'elevata velocità di esecuzione delle
interruzioni, sovente queste non rallentano visibilmente il programma principale.
Un'esempio di comune interruzione è la gestione dell'orologio interno, il microp. viene
interrotto ad esempio 20 volte al secondo per gestire i contatori del tempo, ma tutte queste
interruzioni possono rallentare il programma principale di circa 100-200 microsecondi,
davvero ben poca cosa.
Nota: Le singole istruzioni sono eseguite in nanosecondi; con un quarzo da 10 Mhz
uno Z80 vecchio tipo impiega da 0,4 uS a circa un microsecondo. Per l'8051 con un
quarzo da 24 Mhz, esegue le singole operazioni da 0,5 o un microsecondo.
Processori più recenti (AVR, PIC, ecc.) lavorano con una tecnica all'interno parallela
nelle funzioni e così possono raggiungere notevoli velocità con quarzi da pochi Mhz.
Personalmente sono riuscito a far lavorare l'AT89C2051 con una frequenza limite di
84 Mhz, corrispondente ad un massimo di 7 milioni d'istruzioni al secondo,
una ogni 140 nanosecondi.
Nello Z80 le interruzioni sono comandate con due ingressi fisici a priorità assoluta NMI
e secondario INT, secondo il programma le interruzioni secondarie possono far uso del
registro I che sommato ad un dato a 8 bit indica al programma un'indirizzo completo a 16 bit.
Questo sistema permette un veloce servizio, quando i dispositivi periferici collegati al
microp. fanno una chiamata di interruzione.
Con l'8051 si hanno cinque tipi di interruzione. Due sono generati dall'esterno e tre
interni (i due timer e la porta seriale). All'inizio del programma ci sono degli indirizzi
dedicati dove possono essere memorizzate poche istruzioni con i vettori d'interruzione,
dove in pratica poi viene eseguito il programma.
Gli indirizzi partono da 0003H fino a 0023H, e i primi quattro hanno 8 byte a disposizione,
mentre l'ultimo, (porta seriale) teoricamente non ha limite.
(17) Il registro di guardia (WATCH DOG)
Nei microc. moderni hanno aggiunto un registro di guardia, il quale serve ad evitare che
per qualche causa accidentale il programma e quindi il microcontrollore si blocchi.
In pratica il registro è un timer fisso, che deve essere ogni tanti millisecondi caricato
al numero massimo (255), perché altrimenti si azzera e genera quindi un reset.
Se il microc. durante il suo funzionamento ogni tanto rinfresca il registro di guardia,
tutto procede bene, ma se per cause accidentali si blocca l'esecuzione del programma,
quando il registro di guardia è a zero, il tutto si resetta e il microc. riprende a
lavorare come prima. A questo punto se la causa del blocco (interferenze radio, di
alimentazione, ecc.) scompare il sistema ha avuto solo un blocco temporaneo.
(18) L'acquisizione dei dati analogici (A/D)
I microp. e microc. lavorano con dati numerici in forma parallela, quando si deve leggere
un valore analogico presente ad esempio su un determinato ingresso, si fa uso della
conversione analogica-numerica e viceversa.
In inglese A/D (Analogico/Digitale) e D/A (Digitale/Analogico), questi convertitori un
tempo esterni ora si trovano montati direttamente nei microcontrollori di un certo livello.
In'altri più economici si fa uso del principio del comparatore interno o esterno, il microc.
della Zilog Z86E08 monta due comparatori all'interno mentre l'AT89C2051 ne monta uno.
Un esempio di come eseguire la lettura di un valore analogico con il comparatore è facile
da capire, basta pensare ad un contatore del tempo e ad una rampa di tensione, dalla minima
alla massima.
Principio di lettura con comparatore analogico
(+) 5 Volt
R1 o IC | Vr = Tensione rampa
/ *-----\/\/\/---------* Vx = Tensione da misurare
(Vr) / | Comparatore / R1 = 1 Mohm
/ | __________ \ R2 ____________ C1 = 10 nF
C1 | | \ / |Ingresso n.100 Costante di tempo R1xC1 = 10 mSec.
*---||-*--*----|(+) \ \ |Lettura uP R2 = 10 Kohm
| | | (Usc) )--*------>(D0) IC = Generatore corrente costante
///// |(Vx)<--|(-) / |____________ D0 = Uscita comparatore
| |__________/ D7 = Comando scarica C1
| |
| ///// ____________
| |Uscita n.110
| Diodo per scarica C1 |Scrittura uP
*-------------->|-------------->(D7)
|____________
Programma con lo Z80:
ORG 60000 ;Locazione di partenza
XOR A ;A = 0 (oppure OUT 110,0)
OUT 110,A ;Scarica C1 attraverso il diodo
LD BC,700 ;Carica in BC numero di base 700
CALL RIT ;Aspetta 22 msec.
LD A,128 ;A con D7 = 1 (oppure OUT 110,128)
OUT 110,A ;Inizia la rampa di Vr
LEGGE: IN A,100 ;Legge la porta
AND 1 ;Controlla D0
INC BC ;BC = BC + 1 se Vr < Vx
JR Z,LEGGE ;D0 = 0 (D0 = 1 con Vr = Vx)
RET ;Fine con il registro BC proporzionale a Vx
RIT: LD DE,1000 ;Ritardo di circa 22 ms, clock 4 Mhz
ASP: DEC DE
LD A,D
OR E
JR NZ,ASP
RET
In pratica la tensione Vx misurabile in questo caso (visto la semplicità del circuito)
non va da 0 a 5 volt ma da 1 a circa 4,2 volt, e al posto del diodo è meglio usare un
transistor che scarica meglio C1.
Senza il generatore (IC invece di R1) della corrente costante, la linearità della rampa
di Vr nel tempo è inferiore; tuttavia fra 2,5 e 3,5 volt va bene lo stesso.
Se usiamo ad esempio una sonda per la temperatura atmosferica come l'LM135, che dà una
tensione di 2,73 volt con 0 C° e che sale a 3,73 volt a 100 C°, la lettura è abbastanza
precisa anche con variazioni di un solo millivolt, corrispondente ad un decimo di grado.
19) La conversione dei dati numerici in analogici (D/A)
Permette di trasformare il valore (peso) dei bit, in un segnale analogico con cui poi si
può controllare attraverso sucessiva elaborazione, qualsiasi dispositivo elettronico.
Ci sono dispositivi interfacciabili con i microp. che eseguono ambedue le conversioni
(A/D D/A) con opportuna alimentazione duale.
Porta uscita 20 Kohm 20 Kohm
a 4 bit. D0)---\/\/\/------*------\/\/\/------/////
Indirizzo 110 /
\ 10 Kohm
20 K /
D1)---\/\/\/------*
/
\ 10 K
20 K /
D2)---\/\/\/------*
/
\ 10 K
20 K /
D3)---\/\/\/------*---> VX Uscita <---/////
Programma dimostrativo con lo Z80, per generare in VX, una tensione con andamento variabile
a gradini di forma triangolare.
ORG 60000 ;Inizio programma
LD C,15 ;Valore base 00001111B in C
LD A,C ;A = C
ESCE1: OUT 110,A ;Esce A da porta 110
DEC A ;A = A-1 (Rampa in discesa)
NOP ;Ritardo d'equilibrio rampa
JRNZ,ESCE1 ;Continua fino a che A = Zero
ESCE2: OUT 110,A ;Esce A da porta 110
INC A ;A = A+1 (Rampa in salita)
CP C ;Controllo se A = 15
JRNZ,ESCE2 ;Continua fino a che A < 15
JR,ESCE1 ;Ritorna inizio A = 15
+ ------------------------ + VCC
\ /\ /\ /\ /
Andamento nel \ / \ / \ / \ /
tempo di VX \/ \/ \/ \/
0 -----------------------> Tempo
Nota: Tutte le porte in uscita hanno in pratica un registro di memoria su cui il microp.
scrive il dato in binario e i valori vengono presentati in uscita sui terminali
corrispondenti ai singoli bit . (Vedi la differenza dell'8051 - Nota argomento n.13).
(20) Il sistema a multiprocessore
Sia per motivi di velocità, come pure per praticità di gestione e quindi di potenza, a volte
si richiede che più microp. o microc. debbano lavorare insieme.
Sia che i microprocessori siano due o di più, esiste sempre una gerarchia di configurazione
fisica, dove uno solamente è il controllore primario (Master) e gli altri sono i controllori
secondari (Slave); questa disposizione è necessaria in modo da evitare un conflitto di
comandi o ordini, in tal modo si è esenti da errore.
Come l'esempio del direttore d'orchestra, senza di lui, anche se tutti i componenti
dell'orchestra suonano alla perfezione il loro strumento, ci saranno ugualmente degli errori
durante l'esecuzione musicale, in quanto manca la coordinazione principale del direttore.
Le configurazioni base sono in modo parallelo o in modo seriale.
La più comune è la seriale, per cui questi microcontrollori hanno dei registri per il dialogo
e il controllo esterno seriale, ciò permette anche una dislocazione fisica diversa fra i vari
dispositivi intelligenti.
Di solito il sistema si chiama (SPI), abbreviazione dall'inglese che in italiano significa:
Interfaccia di Periferia Seriale; che viene usata sia per dialogare con altri microp. o
microcontrollori, come pure per lo scambio di dati con dispositivi di periferia più semplici
come porte di I/O, memorie Eeprom, ecc.
Esempio di sistema (SPI) minimo a due microcontrollori
Primario (Master) Secondario (Slave)
______________________ ________________________
| Sincronismo |
(Segnale di Clock)------------------>---(Ingresso Clock)
(Segnale di controllo)------------------>---(Ingresso segnale controllo)
(Uscita dati seriali)------------------>---(Ingresso dati seriali)
(Ingresso dati seriali)----<-----------------(Uscita dati seriali
______________________| |_______________________
I microcontrollori dell'Atmel del tipo AVR, usano il sistema SPI anche per la programmazione,
in quanto volendo si possono programmare non solo con il sistema tradizionale, ma anche senza
estrarli fisicamente dal circuito dove sono installati.
Nella famiglia derivante dall'8051, la porta seriale può comunicare con un bit in più il
nono, il quale volendo attraverso la configurazione del registro di comunicazione SCON, si
può usare nel programma in modo che controlli l'interruzione seriale.
Così facendo è possibile usare anche l'8051 in un sistema a multiprocessore.
Continua................
Saluti, Emilio ik1wjq
Vai a pagina1