1.3.11 Programmering MCS51
Mikrokontrollerens programkode skrives som assemblerinstruksjoner eller i et programmeringsspråk på et høyere nivå som eksempelvis PLM og C++. Kode skrevet i assembler gir et mer kompakt program og utnytter plassen i hukommelsen mer effektivt. Da hukommelsen i en mikrokontroller er ganske begrenset, kan det derfor være en fordel å skrive programmet i assemblerkode. Etter hvert som utviklingen har gått fremover er det fremkommet mikrokontrollere med stadig større minnekapasitet, og programmering i høynivåspråk er blitt mer aktuelt. Å programmere i høynivåspråk gjør også arbeidet enklere når man først har tilegnet seg kunnskapen.
I dette kapittelet i den videre presentasjonen av MCS51 vil vi kun konsentrere oss om assemblerkoding, da denne gir en god innsikt og forståelse av de mekanismer som foregår mellom mikrokontrollerens programvare (software) og hardvare (hardware). I kapittel 3.4 vil vi ved hjelp av utviklingsverktøyet Arduino ta for oss en mer moderne mikrokontroller for programmering i et høynivåspråk.
Da de første mikrokontrollerne så dagens lys, skrev man programmene i assemblerkode. Årsaken var først og fremst den begrensede ROM-kapasiteten i komponentene, siden program i assemblerkode krever langt mindre minnekapasitet enn tilsvarende program i høynivåspråk. Etter hvert fikk mikrokontrollerne stadig større minnekapasitet, og det ble vanlig å utarbeide programmer også i høynivåspråk.
I denne sammenheng vil vi kun ta for oss assemblerprogrammering, da denne formen for koding gjør det enkelt å forstå de grunnleggende mekanismene som foregår i selve mikrokontrolleren mellom hardwaredelen og softwaredelen.
Program for mikrokontrollere skrives som instruksjoner i assemblerkode eller i høynivåspråk (for eksempel C eller – mer vanlig – C++).
Instruksjonene kalles kildekode og lagres som en kildefil (eng. source-file)
Instruksjonene skrives som forståelig tekst, men må oversettes til maskinkode før de kan kjøres i mikrokontrolleren. Dette kalles assemblering.
Kildefilen kan skrives som en vanlig tekstfil, men må normalt lagres som DOS-tekst for å kunne behandles i en assembler.
Etter at kildefilen er kjørt i en assembler, genereres en listfil og en objektfil (nærmere forklaring kommer lenger bak i presentasjonen).
Assemblerinstruksjoner for MCS51
Instruksjonene grupperes etter funksjonstilhørighet:
aritmetiske instruksjoner (Arithmetic operations)
logiske instruksjoner (Logical operations)
instruksjoner for dataoverføring (Data transfer)
bitinstruksjoner (Boolean variable manipulation)
hoppinstruksjoner (Program branching)
Aritmetiske instruksjoner
Aritmetiske instruksjoner er instruksjoner som utfører rene regneoperasjoner.
Eksempel:
ADD A,#04 ;adderer innholdet i akkumulator med tallet 4
(# indikerer at verdien som følger, er en konstantverdi (tall) og ikke en adresse.)
ADD A,04 ; adderer innholdet i akkumulator med innholdet i adresse 4
Legg merke til kommentarene som er skrevet etter operasjonen.
Det er viktig at disse innledes med semikolon for at de skal bli oversett av assembleren når kildeprogrammet skal assembleres.
Logiske instruksjoner
Logiske instruksjoner er instruksjoner som utfører logiske operasjoner som OG (AND), ELLER (OR) osv.
Eksempel:
ANL A,#00110101B ;logisk OG mellom akkumulator og bitmønsteret 00110101
Samme instruksjon kan også skrives med heksadesimalte tall:
ANL A,#35H
Andre logiske instruksjoner:
ORL – logisk ELLER
XRL – eksklusiv ELLER
Instruksjoner for kontroll og setting av bit
Eksempel på instruksjoner som kontrollerer signaler eller bit, er JB og JNB:
JB P1.0,LOOP ;hopp til adresse LOOP dersom port P1.0 er høy
JNB SIGNAL, LOOP ;hopp til adresse LOOP dersom SIGNAL ikke er høy
Når enkle utgangssignaler eller bit i hukommelsen skal settes, kan vi benytte instruksjonen SETB. Ved nullstilling av tilsvarende benyttes CLR. Eksempel:
SETB P0.2 ;setter port P0.2 høy
SETB SIGNAL ;setter SIGNAL høy
CLR P2.4 ;setter port P2.4 lav
Hoppinstruksjoner
Hoppinstruksjoner kan deles i tre hovedtyper:
ubetingede hopp
betingede hopp
relative hopp
Noen instruksjoner er en kombinasjon av disse typene.
Ved ubetinget hopp utføres et direkte eller indirekte hopp til en annen adresse, eksempelvis:
AJMP START; hopp til programadresse START
Betingede hopp utføres når en bestemt betingelse er oppfylt, eksempelvis:
JZ START ; hopp til adresse START hvis akkumulator er lik 0
Den siste typen instruksjon er samtidig en relativ hoppinstruksjon. Det betyr at programtelleren hopper et visst antall adresser forover eller bakover i programmet relativt til der den i øyeblikket peker.
Programutvikling
Når det skal utvikles program for en mikrokontroller, er det viktig å ha oversikt over hele utviklingsprosessen samt hvilken funksjon mikrokontrolleren skal ha for den enheten den skal benyttes i.
Blokkskjema mikrokontroller
Før man setter i gang programmeringsarbeidet, kan det være lurt å skaffe seg oversikt over alle signaler som skal brukes til og fra mikrokontrolleren for tilkobling til portene.
Blokkskjema for mikrokontroller anvendt i en alarmenhet:
Flytdiagram
Eksempel på flytdiagram for alarmenheten:
Programkode
Instruksjoner og operasjonskoder skrives linje for linje.
Eventuelle kommentarer må innledes med et semikolon (;) for ikke å lage problemer for assembleren.
Hvis ikke noe annet er angitt, vil programmets startadresse ligge på adresse
0000H.
Dersom vi ønsker at programmet skal starte på en annen adresse, kan dette gjøres ved direktivet ORG. Eksempel:
ORG 0030H
Programkoden for de tre første boksene i flytdiagrammet:
START: JNB AKTIV,START ;hopp til START dersom signalet AKTIV ikke er på
SETB GR_LED ;tenn grønn lysdiode
Her indikerer START: en startadresse i programmet. START må avsluttes med kolon (:) for at assembleren skal oppfatte dette som en programadresse. Alle programadresser som navngis med etiketter på denne måten, må alltid avsluttes med kolon.
Assemblering
Programkoden (kildefilen) overføres til et assemblerverktøy (assembler) for assemblering.
I assembleren blir programkoden omgjort til maskinkode, det vil si 0-er og 1-ere.
Under assembleringen genereres en listfil (filnavn.lst) og en objektfil (filnavn.obj).
Listfilen gir en fullstendig oversikt over resultatet av assembleringen med eventuelle markeringer av feil (syntaksfeil).
Om listfilen er feilfri, betyr det ikke nødvendigvis at programmet er logisk riktig.
Dersom listfilen oppgir feil, må kildefilen rettes opp og assembleres på nytt til listfilen er helt feilfri.
Objektfilen benyttes i forbindelse med fremstilling av hexfil for programmering av PROM i mikrokontrolleren.
Simulering og debugging
De fleste programverktøy som benyttes til programmering og assemblering, har også mulighet for simulering og emulering av programmet. Dette kan være arbeidssparende under uttesting av den fysiske enheten som mikrokontrolleren skal plasseres i.
Med en simulator kan vi et godt stykke på vei analysere og kontrollere at programmet er logisk riktig og gjør den jobben det skal, før det brennes i selve mikrokontrolleren.
Ved å angi start- og stoppadresser kan man kontrollere (debugge) deler av programmet og skritt for skritt kontrollere om porter, registre og datahukommelse opererer riktig til riktig tidspunkt.
Brenning av mikrokontrollerens PROM
Denne delen av prosessen krever eget utstyr (programmeringsverktøy) tilsvarende det som benyttes for programmering/brenning av vanlige PROM-er. Disse er vanligvis beregnet for tilkobling til PC.
Ved hjelp av programmeringsverktøyet kan programmet overføres til mikrokontrolleren
Plasser mikrokontrolleren i sokkelen på programmeringsverktøyet og følg angitt prosedyre som eventuelt følger med eller kommer opp på PC-skjermen.
Det assemblerte programmet «brennes» inn i mikrokontrollerens PROM eller EPROM ved hjelp av egen prosedyre (avhengig av hvilket verktøy du benytter).
Under assembleringen ble det opprettet en objektfil som inneholder en sjekksum og de heksadesimale kodene som benyttes for programmering av mikrokontrollerens PROM-del.
Programmering, utviklingsverktøy
Det er i handelen forskjellige typer utviklingsverktøy for mikrokontrollere, både til utvikling av program og brenning av selve mikrokontrolleren.
Utviklingsverktøy for programmering av mikrokontroller for tilknytning til PC (Ceibo):
Emulering og fysisk testing
På en digital trainer kan mikrokontrolleren testes fysisk når den er ferdig programmert.
Programmet vil normalt starte når driftsspenning settes på, eller når mikrokontrollerens resetinngang aktiveres.
Ved å tilføre signal til inngangene kan vi kontrollere eller måle om utgangene reagerer slik de skal.
Det finnes også emulatorverktøy (In-circuit emulator) der vi ved hjelp av en plugget sokkel kan erstatte selve mikrokontrolleren i det utstyret den skal plasseres. Da kan vi kjøre en fullstendig fysisk kontroll av programmet før mikrokontrolleren brennes.
Utstyr for programmering
Her er en link til en emulator levert av Ceibo: http://www.ceibo.com/eng/pdf/ds51.pdf
Her er et annet utviklingsverktøy: http://www.pjrc.com/tech/8051/
Utstyr for brenning (programmering) av mikrokontrollere. Enheten tilkobles USB-porten på en PC:
Kretsskjema
Kretsskjema for alarmkretsen (tegnet i Proteus):
Eksempel på bruk av mikrokontroller i OG-funksjon
OG-port med logisk uttrykk og sannhetstabell:
Flytdiagram og assemblerkode for OG-port
Flytdiagram og assemblerkode for OG-port med to innganger:
Assemblerprogram
Programmet for OG-operasjonen:
INN_A EQU P0.0
INN_B EQU P0.1
X EQU P1.5
;dette er et program som benytter mikrokontrolleren som en OG-port
START: JNB INN_A,X_LIK_0 ; sjekker inngang A
JNB INN_B,X_LIK_0 ; sjekker inngang B
SETB X ; setter utgangen X lik 1
JMP START
X_LIK_0: CLR X ; setter utgangen X lik 0
JMP START
END
Program for OG-funksjonen
#######################################################################
# #
# Micro Series 8051 Assembler V2.03/DOS 22/May/08 11:13:04 #
# #
# Source = n:\iar\exe\ogport.txt #
# #
# List = ogport.lst #
# #
# Object = x.r03 #
# #
# Options = f #
# #
#######################################################################
;dette er et program som benytter mikrokontrolleren som en OG-port
1 0080 INN_A EQU P0.0
2 0081 INN_B EQU P0.1
3 0095 X EQU P1.5
4
5 0000 308007 START: JNB INN_A,X_LIK_0 ; sjekker inngang A
6 0003 308104 JNB INN_B,X_LIK_0 ; sjekker inngang B
7 0006 D295 SETB X ; setter utgangen X lik 1
8 0008 80F6 JMP START
9 000A C295 X_LIK_0: CLR X ; setter utgangen X lik 0
10 000C 80F2 JMP START
11 000E END
Errors: None ##########
Bytes: 14 # ogport #
CRC: 0F68 ##########
Tabell Programmet for OG-fuksjonen ferdig assemblert
Assembler
En assembler for gratis nedlasting kan du finne på denne linken: http://plit.de/asem-51/
NB! Les brukerbetingelsene før du tar i bruk programmet!
Tabell Assemblerinstruksjoner for MCS 51-serien:
Instruksjon | Engelsk beskrivelse | Norsk beskrivelse |
ACALL | Absolute subroutine call | Hopp til subrutine |
ADD | Add | Addisjon |
ADDC | Add with carry | Addisjon med mente |
AJMP | Absolute jump | Absolutt hopp |
ANL | Logical AND | Logisk OG |
CJNE | Compare and jump if not equal | Sammenlign og hopp hvis ikke lik |
CLR | Clear | Nullstill |
CPL | Complement | Komplementer (snu) |
DA | Decimal adjust | Sett til desimalverdi |
DEC | Decrement | Dekrementer (reduser med 1) |
DIV | Divide with | Divider med |
DJNZ | Decrement and jump if not zero | Reduser med 1 og hopp hvis ikke lik null |
INC | Increment | Inkrementer (øk med 1) |
JB | Jump if bit is set | Hopp hvis bit er satt |
JBC | Jump if bit is set & clear bit | Hopp hvis bit er satt & nullstill bit |
JC | Jump if carry is set | Hopp hvis menteflagg er satt |
JMP | JMP | Hopp |
JNB | Jump if bit not set | Hopp hvis bit ikke er satt |
JNC | Jump if carry not set | Hopp hvis ikke menteflagg er satt |
JNZ | Jump if accumulator is not zero | Hopp hvis ikke akkumulator er null |
JZ | Jump if accumulator is zero | Hopp hvis akkumulator er null |
LCALL | Long subroutine call | Langt subrutinehopp |
LJMP | Long jump | Langt hopp |
MOV | Move data | Flytt data |
MOVC | Move Code | Flytt kode |
MOVX | Move external | Flytt eksternt (ekstern hukommelse) |
MUL | Multiply | Multipliser |
NOP | No operation | Ingen operasjon (fyllinstruksjon) |
ORL | Logical OR | Logisk ELLER |
POP | Pop from stack | Hent fra stakk |
PUSH | Push on stack | Overfør til stakk |
RET | Return from subroutine | Returner fra subrutine |
RETI | Return from interrupt | Returner fra interupt |
RL | Rotate left | Roter til venstre |
RLC | Rotate left through carry | Roter til venstre via mente |
RR | Rotate right | Roter til høyre |
RRC | Rotate right through carry | Roter til høyre via mente |
SETB | Set bit | Sett bit lik \"1\" |
SJMP | Short jump | Kort hopp (relativt) |
SUBB | Subtract | Subtraksjon |
SWAP | Swap nibbles | Bytt om de fire MSB med de fire LSB |
XCH | Exhange | Kryssbytting |
XCHD | Exchange low order digit | Kryssbytt laveste siffer |
XRL | Exclusive OR | Eksklusiv ELLER |