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.

Pinindeling van de 8051 in zijn 40-pins DIP-behuizing, verticaal getekend met de pin-1-inkeping bovenaan. De linker kolom loopt van pin 1 tot 20: poort 1 pinnen P1.0 tot P1.7 met hun alternatieve functies T2, T2EX, MOSI, MISO en SCK, dan RST, dan poort 3 pinnen P3.0 tot P3.7 met labels RXD, TXD, INT0, INT1, T0, T1, WR en RD, dan XTAL2, XTAL1 en GND. De rechter kolom loopt van pin 40 tot 21: VCC, poort 0 pinnen P0.0 tot P0.7 die tegelijk AD0 tot AD7 zijn, dan EA, ALE en PSEN, dan poort 2 pinnen P2.7 omlaag naar P2.0 die tegelijk adreslijnen A15 tot A8 zijn. Kleurcodering scheidt I/O-poorten, alternatieve functies van poort 3, klok- en besturingspinnen en voeding.
Van de veertig pinnen zijn er tweeëndertig I/O. Poort 0 is omgekeerd genummerd ten opzichte van de andere, en de alternatieve labels van poort 3 zijn waar de seriële poort, de externe interrupts en de timerinputs leven. SVG downloaden

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.

Het minimale circuit dat een 8051 nodig heeft om te draaien. Een AT89S52-chipblok toont zes pinnen: VCC pin 40 naar de vijfvoltsrail en GND pin 20 naar aarde; EA pin 31 in rood naar de vijfvoltsrail, met de aantekening
Vier verbindingen en een handvol passieve elementen. Let op het resetnetwerk: de condensator gaat naar de voeding, niet naar aarde, omdat RST actief hoog is. SVG downloaden

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.

Een kaart van het interne datageheugen van de 8051, getekend als gestapelde blokken van adres 00h onderaan tot FFh bovenaan. Van onderen: vier registerbanken van 8 bytes op 00h–07h, 08h–0Fh, 10h–17h en 18h–1Fh; een bit-adresseerbare regio van 16 bytes op 20h–2Fh met 128 afzonderlijk adresseerbare bits; 80 bytes klad-RAM en stack van 30h tot 7Fh; en op 80h–FFh een blok dat zowel de speciale functieregisters bevat, bereikbaar via directe adressering, als de bovenste 128 bytes RAM, alleen bereikbaar via indirecte adressering. Een pijl markeert dat de stackpointer reset naar 07h zodat de stack begint op 08h bovenop registerbank 1, en een tweede pijl markeert de regio 80h–FFh als twee geheugens die één adresbereik delen.
Vier regio's met vier verschillende taken. De twee aangetekende feiten zijn degene die je plagen: de stack belandt op registerbank 1, en de bovenste helft van het adresbereik is twee aparte geheugens. SVG downloaden

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

Bronnen