Tutorial · Principiante · 30 min

Architettura dell'8051: pin, mappa della memoria e registri

Cosa contiene davvero l'8051: un core Harvard, quattro porte con caratteri diversi, 256 byte di RAM e un ciclo macchina che puoi contare.

Introduzione

La maggior parte dei corsi su microcontrollori si apre con l’8051, e la maggior parte degli studenti lo incontra come un elenco di fatti da memorizzare: quattro porte, 128 byte di RAM, due timer, sei interrupt. Memorizzato così è destinato a essere dimenticato. Inteso come un insieme di compromessi deliberati presi nel 1980—quando la RAM costava cara e un chip doveva stare in 40 pin—spiega quasi tutto il modo in cui funzionano ancora oggi i microcontrollori di piccole dimensioni.

Questo è il percorso nell’architettura: cosa c’è dentro il package, come è suddivisa la memoria e perché il calcolo dei tempi è insolitamente semplice. I due approfondimenti riguardano il controllo dei pin e la generazione di PWM da un timer.

“8051” è una famiglia, non un chip

Intel ha introdotto MCS-51 nel 1980 e poi ha concesso in licenza il core a molti produttori, quindi oggi nessuno compra un Intel 8051. Quello che compri è un componente compatibile—nella stragrande maggioranza un AT89S52 di Atmel (ora Microchip)—che aggiunge memoria flash riprogrammabile tramite quattro pin invece della ROM cancellabile con UV del chip originale.

Le differenze che vale la pena conoscere sono queste:

8051 (originale) AT89S52 (il tuo)
Memoria di programma 4 KB ROM 8 KB flash
RAM interna 128 byte 256 byte
Timer 2 3
Sorgenti di interrupt 5 6
Programmazione ROM con mask in fabbrica Nel sistema, tramite pin SPI

Tutto il resto—il set di istruzioni, le porte, la disposizione dei registri, la temporizzazione—è identico. Il materiale didattico scritto per l’8051 si applica senza modifiche al chip sulla tua scrivania.

Cosa c’è dentro il package

Un DIP a 40 pin contiene un computer completo: una CPU a 8 bit, memoria flash di programma, RAM dati, tre timer/contatori, una porta seriale full-duplex, un controllore di interrupt e quattro porte I/O a 8 bit. Non c’è un sistema operativo e non c’è nulla in esecuzione tranne il tuo codice.

Disposizione dei pin dell'8051 nel package DIP a 40 pin, disegnata verticalmente con la tacca del pin 1 in alto. La colonna sinistra, dall'alto verso il basso, va dal pin 1 al pin 20: pin della porta 1 da P1.0 a P1.7 con le funzioni alternative T2, T2EX, MOSI, MISO e SCK, poi RST, poi i pin della porta 3 da P3.0 a P3.7 etichettati RXD, TXD, INT0, INT1, T0, T1, WR e RD, poi XTAL2, XTAL1 e GND. La colonna destra, sempre dall'alto verso il basso, va dal pin 40 al pin 21: VCC, pin della porta 0 da P0.0 a P0.7 che svolgono anche le funzioni di AD0-AD7, poi EA, ALE e PSEN, poi i pin della porta 2 da P2.7 a P2.0 che svolgono anche la funzione di linee di indirizzo A15-A8. La codifica a colori separa le porte I/O, le funzioni alternative della porta 3, i pin di clock e controllo e quelli di alimentazione.
Trentadue dei quaranta pin sono I/O. La porta 0 è numerata al contrario rispetto alle altre e le etichette alternative della porta 3 indicano dove si trovano la porta seriale, gli interrupt esterni e gli ingressi dei timer. Scarica SVG

Quattro pin non sono affatto I/O e devono essere tutti corretti prima che qualcosa possa funzionare: XTAL1 e XTAL2 per il quarzo, RST per la rete di reset e EA per scegliere la memoria di programma interna o esterna. Se sbagli EA, il chip non fa nulla, in silenzio.

Il circuito minimo necessario perché un 8051 possa funzionare. Il blocco di un chip AT89S52 mostra sei pin: il pin VCC 40 collegato alla linea di alimentazione a cinque volt e il pin GND 20 collegato a terra; il pin EA 31 collegato in rosso alla linea di alimentazione a cinque volt, con l'annotazione «collega EA al livello alto, altrimenti il chip non funziona»; i pin XTAL2 18 e XTAL1 19 collegati ai due lati di un quarzo da 11.0592 MHz, con un condensatore da 33 picofarad da ciascun lato del quarzo a terra; e il pin RST 9 collegato a un condensatore da 10 microfarad che sale verso la linea di alimentazione a cinque volt e a una resistenza da 10 kiloohm che scende a terra, con l'annotazione «il reset è attivo HIGH».
Quattro collegamenti e una manciata di componenti passivi. Nota la rete di reset: il condensatore va all'alimentazione, non a terra, perché RST è attivo alto. Scarica SVG

Harvard: codice e dati sono mondi diversi

L’8051 mantiene la memoria di programma e la memoria dati in spazi di indirizzamento separati. Un indirizzo come 0x0030 significa una cosa durante il recupero di un’istruzione e qualcosa di completamente diverso durante un accesso ai dati: sono memorie diverse, raggiunte con istruzioni diverse.

Ecco perché i compilatori C per l’8051 ti costringono a fare attenzione alle classi di archiviazione che altre piattaforme nascondono. Un literal di stringa che non modifichi mai appartiene alla memoria code, dove ci sono kilobyte liberi. Mettilo per errore in data e consumi i 256 byte che ti servivano per tutto il resto:

// In code (flash) — costs nothing from your 256 bytes of RAM.
const char code banner[] = "Line follower v1";

// In RAM — 17 of your 256 bytes, gone, for a string that never changes.
const char banner_bad[] = "Line follower v1";

Su un Arduino questa distinzione è ciò per cui esiste PROGMEM. Sull’8051 non è un’ottimizzazione: è la differenza tra un programma che entra nello spazio disponibile e uno che non entra.

La mappa della RAM interna

I 256 byte di RAM interna non sono un piano di lavoro piatto. Sono divisi in regioni con capacità diverse e sapere quale sia quale costituisce gran parte della finalità della mappa della memoria.

Mappa della memoria dati interna dell'8051 disegnata come blocchi impilati dall'indirizzo 00h in basso a FFh in alto. Dal basso verso l'alto: quattro banchi di registri da 8 byte a 00h-07h, 08h-0Fh, 10h-17h e 18h-1Fh; una regione indirizzabile a bit di 16 byte da 20h a 2Fh che contiene 128 bit individualmente indirizzabili; 80 byte di RAM scratch e stack da 30h a 7Fh; e da 80h a FFh un blocco che contiene sia i registri a funzione speciale, raggiunti tramite indirizzamento diretto, sia i 128 byte superiori di RAM, raggiungibili solo tramite indirizzamento indiretto. Una freccia indica che il puntatore allo stack viene reimpostato a 07h, così lo stack inizia a 08h sopra il banco di registri 1; una seconda freccia indica che la regione 80h-FFh è formata da due memorie che condividono lo stesso intervallo di indirizzi.
Quattro regioni con quattro funzioni diverse. I due fatti annotati sono quelli che ti mordono: lo stack finisce sul banco di registri 1 e la metà superiore dell'intervallo di indirizzi è composta da due memorie separate. Scarica SVG

00h–1Fh — quattro banchi di registri. R0-R7 non sono posizioni fisse: sono una finestra su uno di quattro banchi da 8 byte, selezionati da due bit (RS0 e RS1) nella parola di stato del programmatore. Cambiare banco è una scrittura di due bit, un modo molto economico per assegnare a un interrupt registri propri invece di eseguire push e pop di otto registri.

20h–2Fh — indirizzabile a bit. Questi 16 byte sono anche indirizzabili come 128 singoli bit, da 00h a 7Fh. L’8051 ha vere istruzioni a singolo bit—SETB, CLR, JB, JNB—quindi un flag qui costa un bit e un’istruzione invece di un byte e una maschera. Ecco perché i compilatori C per l’8051 offrono un tipo bit che non esiste altrove.

30h–7Fh — scratch e stack. Ottanta byte per le tue variabili e per lo stack delle chiamate: è la risorsa che alla fine esaurisci davvero.

80h–FFh — due memorie, un intervallo di indirizzi. L’indirizzamento diretto qui raggiunge i registri a funzione speciale; l’indirizzamento indiretto (tramite R0 o R1) raggiunge i 128 byte superiori di RAM. Stessi numeri, memorie diverse, selezionate dalla forma dell’istruzione che usi. Sul 8051 originale da 128 byte la RAM superiore semplicemente non esiste.

I registri a funzione speciale sono solo memoria

Ogni periferica dell’8051 viene controllata scrivendo byte in indirizzi dell’intervallo diretto 80h–FFh. Non c’è un’API: c’è un registro e l’impostazione di un bit al suo interno cambia il comportamento del silicio.

Registro Indirizzo Cosa controlla
P0 P1 P2 P3 80h, 90h, A0h, B0h Le quattro porte I/O
TMOD 89h Selezione della modalità dei timer 0 e 1
TCON 88h Bit di avvio dei timer e flag di overflow
TH0 TL0 TH1 TL1 8Ch, 8Ah, 8Dh, 8Bh Registri di conteggio dei timer
SCON SBUF 98h, 99h Controllo e dati della porta seriale
IE IP A8h, B8h Abilitazione e priorità degli interrupt
PSW D0h Flag e bit di selezione del banco di registri
SP 81h Puntatore allo stack

Scrivere P1 = 0x0F; in C equivale a memorizzare un valore all’indirizzo 90h, e otto pin cambiano stato. Questa immediatezza è tutto il fascino del chip come dispositivo didattico.

Una temporizzazione che puoi contare

Un ciclo macchina dura dodici periodi dell’oscillatore su un core 8051 classico e la maggior parte delle istruzioni richiede uno o due cicli macchina. Questo rapporto fisso significa che puoi calcolare esattamente il tempo di esecuzione invece di misurarlo:

machine cycle = 12 / f_osc

at 11.0592 MHz : 12 / 11 059 200 = 1.085 µs
at 12 MHz      : 12 / 12 000 000 = 1.000 µs

Un ciclo di tre istruzioni a singolo ciclo a 11.0592 MHz richiede 3.26 µs, ogni volta, senza cache, senza catena di elaborazione e senza jitter degli interrupt oltre a quello che abiliti tu. Pochissimi processori moderni permettono di ragionare in questo modo, ed è il motivo per cui l’8051 sopravvive dentro le periferiche critiche dal punto di vista temporale.

Perché il quarzo è da 11.0592 MHz

Il numero sembra arbitrario, ma non lo è. La porta seriale deriva la velocità in baud dividendo il clock dei cicli macchina, e 11.0592 MHz si divide in modo da ottenere velocità in baud standard esattamente:

baud = f_osc / (12 × 32 × (256 − TH1))

11.0592 MHz, TH1 = 253 :  11 059 200 / (12 × 32 × 3) = 9600.0   ✓ exact
12 MHz,      TH1 = 253 :  12 000 000 / (12 × 32 × 3) = 10416.7  ✗ 8.5% off

Una UART tollera qualche punto percentuale di errore; un errore dell’8.5% trasforma ogni frame in spazzatura. Se la tua scheda 8051 stampa caratteri spazzatura sulla seriale, guarda il quarzo prima di guardare il codice.

Cosa non ha l’8051

Due assenze danno forma a ogni progetto con 8051 e nessuna delle due è evidente da un elenco di funzionalità:

  • Nessun convertitore analogico-digitale. Per leggere un potenziometro, un termistore o un sensore di linea analogico serve un chip ADC esterno come ADC0804. Non c’è alcuna analogRead() da usare.
  • Nessun hardware PWM. Niente sul chip genera una forma d’onda con duty cycle variabile. Per attenuare un LED o impostare la velocità di un motore devi costruire tu il PWM con un interrupt del timer e pagarne il costo in tempo CPU.

Un Arduino Uno li ha entrambi integrati. Questo è il confronto onesto: l’8051 non è un Arduino peggiore, è lo strato sottostante a un Arduino, privato delle comodità così da farti vedere cosa facevano.

Quando qualcosa va storto

  • La scheda è morta e nulla si scalda. Controlla che EA (pin 31) sia a +5 V. Se è galleggiante o collegato a terra, il chip recupera il codice da una memoria esterna inesistente e non esegue nulla, senza alcun sintomo.
  • Si reimposta continuamente oppure non si avvia mai. Il reset sull’8051 è attivo alto. Il circuito di alimentazione è un condensatore da 10 µF da +5 V a RST e una resistenza da 10 kΩ da RST a terra. Collegarlo come un reset attivo basso tiene il chip in reset permanente.
  • L’uscita seriale è spazzatura. Quasi sempre è il quarzo. Un componente da 12 MHz non può raggiungere le velocità in baud standard.
  • Le variabili si corrompono senza motivo. Probabilmente hai esaurito gli 80 byte da 30h–7Fh oppure lo stack è cresciuto verso il basso fino alle variabili. Controlla l’uscita della mappa della memoria del compilatore.
  • I registri cambiano in modo inatteso dentro un interrupt. Il puntatore allo stack viene reimpostato a 07h, quindi lo stack inizia a 08h—che è il banco di registri 1. Sposta SP nel codice di avvio oppure lascia intatto il banco 1.

Esplora il grafo

Fa parte di queste costruzioni

Progetti e percorsi di apprendimento che includono questo tutorial.

Per approfondire

Fonti