Tutorial · Beginner · 30 min lezen
8051-architectuur: pinnen, geheugenkaart en registers
Wat de 8051 werkelijk bevat: een Harvard-kern, vier poorten met elk een eigen karakter, 256 bytes RAM en een machinacyclus die je kunt meetellen.
Inleiding
De meeste microcontrollercursussen beginnen met de 8051, en de meeste studenten leren hem kennen als een lijst feiten om te onthouden: vier poorten, 128 bytes RAM, twee timers, zes interrupts. Zo onthouden is het snel vergeten. Begrepen als een reeks bewuste afwegingen uit 1980 — toen RAM echt geld kostte en een chip in 40 pinnen moest passen — verklaart hij bijna alles over hoe kleine microcontrollers vandaag nog werken.
Dit is een rondleiding door de architectuur: wat er in de behuizing zit, hoe het geheugen is opgedeeld en waarom de tijdberekening opvallend eenvoudig is. De twee vervolgstukken behandelen het aansturen van de pinnen en PWM opwekken vanuit een timer.
“8051” is een familie, geen chip
Intel introduceerde de MCS-51 in 1980 en licentieerde de kern daarna breed uit, dus niemand koopt vandaag nog een Intel 8051. Wat je koopt is een compatibel onderdeel — vrijwel altijd de AT89S52 van Atmel (nu Microchip), die flash toevoegt die je via vier pinnen opnieuw kunt programmeren, in plaats van de UV-wisbare ROM van het origineel.
De verschillen die je moet kennen:
| 8051 (origineel) | AT89S52 (wat jij hebt) | |
|---|---|---|
| Programmageheugen | 4 KB ROM | 8 KB flash |
| Intern RAM | 128 bytes | 256 bytes |
| Timers | 2 | 3 |
| Interruptbronnen | 5 | 6 |
| Programmeren | Mask-ROM in de fabriek | In het systeem, via SPI-pinnen |
Al het andere — de instructieset, de poorten, de registerindeling, de timing — is identiek. Cursusmateriaal voor de 8051 geldt ongewijzigd voor de chip op je bureau.
Wat er in de behuizing zit
Eén 40-pins DIP-behuizing bevat een complete computer: een 8-bits CPU, programmaflash, data-RAM, drie timer/tellers, een volledig-duplex seriële poort, een interruptcontroller en vier 8-bits I/O-poorten. Er is geen besturingssysteem en er draait niets behalve jouw code.
Vier pinnen zijn helemaal geen I/O en alle vier moeten goed zitten voordat er iets draait: XTAL1 en XTAL2 voor het kristal, RST voor het resetnetwerk en EA om te kiezen tussen intern of extern programmageheugen. Kies je EA verkeerd, dan doet de chip niets — stilzwijgend.
Harvard: code en data zijn verschillende werelden
De 8051 houdt programmageheugen en datageheugen in gescheiden adresruimtes. Het adres 0x0030 betekent iets anders voor een instructie-ophaalactie dan voor een gegevenstoegang — het zijn verschillende geheugens, bereikbaar via verschillende instructies.
Daarom laten C-compilers voor de 8051 je nadenken over opslagklassen die andere platformen verbergen. Een string-literal dat je nooit wijzigt hoort in code-geheugen, waar kilobytes in overvloed zijn. Zet het per ongeluk in data en het eet de 256 bytes die je voor al het andere nodig had:
// 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";
Op een Arduino bestaat dit onderscheid omwille van PROGMEM. Op de 8051 is het geen optimalisatie, maar het verschil tussen een programma dat past en een dat niet past.
De kaart van het interne RAM
De 256 bytes intern RAM zijn geen vlak kladgebied. Ze zijn verdeeld in regio’s met verschillende eigenschappen, en weten welke regio welke is, is het meeste waar de geheugenkaart voor dient.
00h–1Fh — vier registerbanken. R0 tot en met R7 zijn geen vaste locaties; ze zijn een venster op een van vier 8-bytebanken, gekozen door twee bits (RS0 en RS1) in het program status word. Van bank wisselen is een schrijfactie van twee bits, wat het een bijzonder goedkope manier maakt om een interrupt zijn eigen registers te geven in plaats van er acht op de stack te zetten en er weer af te halen.
20h–2Fh — bit-adresseerbaar. Deze 16 bytes zijn ook adresseerbaar als 128 losse bits, 00h tot en met 7Fh. De 8051 heeft echte één-bitsinstructies — SETB, CLR, JB, JNB — dus een vlag kost hier één bit en één instructie in plaats van een byte en een masker. Daarom bieden 8051-C-compilers een bit-type dat nergens anders bestaat.
30h–7Fh — kladruimte en stack. Tachtig bytes voor je variabelen en je aanroepstack, en dit is de bron waar je daadwerkelijk doorheen raakt.
80h–FFh — twee geheugens, één adresbereik. Direct adresseren bereikt hier de speciale functieregisters; indirect adresseren (via R0 of R1) bereikt de bovenste 128 bytes RAM. Dezelfde getallen, verschillende geheugens, gekozen door de instructievorm die je gebruikt. Op de oorspronkelijke 8051 met 128 bytes bestaat het bovenste RAM simpelweg niet.
Speciale functieregisters zijn gewoon geheugen
Elke peripheral op de 8051 wordt bestuurd door bytes te schrijven naar adressen in het directe bereik 80h–FFh. Er is geen API — er is een register, en een bit daarin zetten verandert wat het silicium doet.
| Register | Adres | Wat het bestuurt |
|---|---|---|
P0 P1 P2 P3 |
80h, 90h, A0h, B0h | De vier I/O-poorten |
TMOD |
89h | Modusselectie voor timer 0 en 1 |
TCON |
88h | Runbits en overflowvlaggen van de timers |
TH0 TL0 TH1 TL1 |
8Ch, 8Ah, 8Dh, 8Bh | Telregisters van de timers |
SCON SBUF |
98h, 99h | Besturing en data van de seriële poort |
IE IP |
A8h, B8h | Interruptinschakeling en prioriteit |
PSW |
D0h | Vlaggen, en de registerbank-selectiebits |
SP |
81h | Stackpointer |
P1 = 0x0F; schrijven in C is een opslag naar adres 90h, en acht pinnen veranderen van toestand. Die directheid is de hele aantrekkingskracht van de chip als onderwijsapparaat.
Timing die je kunt meetellen
Eén machinacyclus is twaalf oscillatorperioden op een klassieke 8051-kern, en de meeste instructies duren één of twee machinacycli. Die vaste verhouding betekent dat je de uitvoeringstijd exact kunt berekenen in plaats van hem te meten:
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
Een lus van drie instructies met één cyclus duurt bij 11,0592 MHz elke keer 3,26 µs, zonder cache, zonder pipeline en zonder interruptjitter behalve wat je zelf aanzet. Heel weinig moderne processors laten je zo redeneren, en daarom overleeft de 8051 in tijdkritische peripherals.
Waarom het kristal 11,0592 MHz is
Dat getal lijkt willekeurig en is het niet. De seriële poort leidt zijn baudrate af door de machinacyclusklok te delen, en 11,0592 MHz deelt netjes op tot standaardbaudrates:
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
Een UART verdraagt een paar procent fout; 8,5% maakt elk frame onleesbaar. Print je 8051-bord rommel over de seriële lijn, kijk dan eerst naar het kristal en daarna naar je code.
Wat de 8051 niet heeft
Twee afwezigheden bepalen elk 8051-project, en geen van beide blijkt uit een functielijst:
- Geen analoog-naar-digitaal-omzetter. Een potentiometer, een thermistor of een analoge lijnsensor uitlezen vereist een externe ADC-chip zoals de ADC0804. Er is geen
analogRead()om naar te grijpen. - Geen PWM-hardware. Niets op de chip genereert een golfvorm met variabele duty cycle. Een LED dimmen of een motorsnelheid instellen betekent zelf PWM bouwen vanuit een timerinterrupt, en daar CPU-tijd voor betalen.
Een Arduino Uno heeft allebei ingebouwd. Dat is het eerlijke vergelijk: de 8051 is geen slechtere Arduino, hij is de laag eronder, met de gemakskenken eruit gehaald zodat je kunt zien wat ze deden.
Het gaat mis
- Het bord is dood en niets wordt warm. Controleer of EA (pin 31) op +5 V staat. Zwevend of geaard haalt de chip code uit extern geheugen dat er niet is en voert niets uit, zonder enig symptoom.
- Hij reset constant, of start nooit. Reset op de 8051 is actief hoog. Het inschakelcircuit is een condensator van 10 µF van +5 V naar RST en een weerstand van 10 kΩ van RST naar aarde. Zo bedraad als een actief-lage reset houdt je de chip permanent in reset.
- Seriële uitvoer is rommel. Vrijwel altijd het kristal. Een 12 MHz-onderdeel haalt geen standaardbaudrates.
- Variabelen vernietigen elkaar zonder reden. Je zit waarschijnlijk vast aan de 80 bytes op 30h–7Fh, of je stack is omlaag uitgegroeid tot in je variabelen. Bekijk de geheugenkaart-uitvoer van je compiler.
- Registers veranderen onverwacht binnen een interrupt. De stackpointer reset naar 07h, dus de stack begint op 08h — en dat ís registerbank 1. Verplaats SP in je opstartcode of laat bank 1 met rust.
Verken de graaf
Onderdeel van deze bouwprojecten
Projecten en leerroutes waarin deze tutorial voorkomt.
Verder lezen