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.
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.
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.
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