Voorbeelden van het gebruik van de seriële poort
Hieronder volgen enkele voorbeelden van de manier waarop de seriële poort
gebruikt zou kunnen worden.
Op de PC kan de seriële poort aangestuurd worden mbv het programma
'hyperterminal'. Ook in de programmeer software die u hier
kunt downloaden zit de mogelijkheid met de SIMPLEX te communiceren.
De Baudrate van de seriële poort in de micro-controller wordt ingesteld in het BAUD register. Twee bits hierin bepalen een deelfactor voor de klok van de processor (die op de SIMPLEX 2 MHz is) en drie andere bits bepalen een tweede deelfactor. De resulterende frequentie bepaalt de Baudrate.
De eerste deelfactor is:
|
SCP1 |
SCP0 |
deelfactor |
hoogste Baudrate |
|
|
|
0 |
0 |
1 |
125 kiloBaud |
|
0 |
1 |
3 |
41.666 kiloBaud |
|
1 |
0 |
4 |
31.250 kiloBaud |
|
1 |
1 |
13 |
9600 Baud |
De eerste deelfactor kan het beste ingesteld worden op een hoogste Baudrate van 9600 Baud. Met de tweede deelfactor kan deze Baudrate eventueel verder omlaag gebracht worden. Het programma voor de PC moet natuurlijk op dezelfde Baudrate ingesteld worden, het is
standaard ingesteld op 9600 Baud.
De tweede deelfactor is:
|
SCR2 |
SCR1 |
SCR0 |
Deelfactor |
Baudrate |
|
|
|
0 |
0 |
0 |
1 |
9600 Baud |
|
0 |
0 |
1 |
2 |
4800 Baud |
|
0 |
1 |
0 |
4 |
2400 Baud |
|
0 |
1 |
1 |
8 |
1200 Baud |
|
1 |
0 |
0 |
16 |
600 Baud |
|
1 |
0 |
1 |
32 |
300 Baud |
|
1 |
1 |
0 |
64 |
150 Baud |
|
1 |
1 |
1 |
128 |
75 Baud |
Heen- en weer typen
Het eerste voorbeeld programma voor de SIMPLEX zendt alle tekens zoals ze van de PC ontvangen werden, onmiddellijk weer terug naar de PC.
In het voorbeeld kunt U zien hoe de seriële poort geïnitialiseerd moet worden, zodat communicatie mogelijk wordt. Alles wat U op het toetsenbord van de PC typt, wordt naar de SIMPLEX gestuurd. Hier wordt het ontvangen, en
meteen weer teruggestuurd. Na ontvangst zet de PC het teken op het scherm.
Probeer in de hoofdlus, tussen het ophalen van een teken en het weer terugzenden daarvan, het teken eens te veranderen. Dit kan bijvoorbeeld eenvoudig door een 'decb' instructie in te voegen tussen de instructies 'bsr getchar' en 'bsr putchar'. Hierdoor wordt de ASCII waarde van het ontvangen teken met één verlaagd voordat het weer wordt teruggestuurd naar de PC. Een 'B' wordt dan een 'A', een 'C' wordt een 'B', etc. *************************************************
* definiëren van de geheugen map
*************************************************
incl "map512.asm"
*************************************************
* start van het programma
*************************************************
PROGRAM space |kies het programma gebied
reset equ $ |na reset begint de micro op deze plaats
lds #stackend |begin met de stackpointer te laden
ldx #databeg |en zet dan het volledige datagebied op 00
clearram clr 0,x
inx
cpx #dataend
bls clearram
ldx #regsbeg |laat IX op de bank met I/O registers wijzen
*************************************************
* seriële poort
*************************************************
PROGRAM space
clistart equ $ |het beginadres van deze module
* initialisatie
* initialiseer de seriële poort
ldab #(scp1+scp0)
stab baud |kies 9600 BAUD ( 8MHz kristal)
ldab #(te or re)
stab sccr2 |en zet zender en ontvanger aan
bra cliend |einde van de initialisatie
* subroutines voor de seriële poort
PROGRAM space
* kijk of er een karakter ontvangen is
* zoja, zet dan de zerovlag op '0'
serincheck equ $
pshb
ldab scsr |lees de status vlaggen
andb #rdrf |en test op het 'receiver full' bit
pulb
rts
* kijk of de seriele poort gereed is om een teken te versturen
* zoja, zet dan de zerovlag op '0'
seroutcheck equ $
pshb
ldab scsr |lees de staus vlaggen
andb #tc |en test op het 'transmitter empty' bit
pulb
rts
* haal een teken op uit de ontvanger, en zet het in accumulator B
getchar equ $
bsr serincheck |wacht totdat er een teken ontvangen is
beq getchar
ldab scdr |en lees het teken uit het ontvanger register
rts
* verstuur een teken via de seriële poort
putchar equ $
bsr seroutcheck |wacht totdat de zender gereed is
beq putchar
stab scdr |en zet dan het teken in het verzendregister
rts
cliend equ $ |einde van de cli module
*************************************************
* het hoofdprogramma
*************************************************
PROGRAM space
main0 bsr getchar |wacht totdat er iets ontvangen is
bsr putchar |en verstuur dat daarna ook weer
bra main0
end
Besturing via de seriële poort
In dit voorbeeld wordt de seriële poort gebruikt om de LED uitgangen van de SIMPLEX te besturen vanuit de PC, en
enkele ingangen van de SIMPLEX op te sturen naar de PC, waar ze op het scherm getoond worden. Het
programma reageert als volgt op de opdrachten vanaf de PC:
| Toets |
LED 1 |
LED 2 |
| '0' |
aan |
aan |
| '1' |
aan |
uit |
| '2' |
uit |
aan |
| '3' |
uit |
uit |
De digitale ingangen van poort E worden naar de PC gestuurd, na te zijn omgezet in 8 ASCII nullen en enen. Een open ingang van poort
E wordt gezien als een '1'. Om hiervan een '0' te maken, moet U de betreffende ingang kortsluiten met massa. De
massa (GND) is ook uitgevoerd op de connector. *************************************************
* definiëren van de geheugen map
*************************************************
incl "map512.asm"
*************************************************
* start van het programma
*************************************************
PROGRAM space |kies het programma gebied
reset equ $ |na reset begint de micro op deze plaats
lds #stackend |begin met de stackpointer te laden
ldx #databeg |en zet dan het volledige datagebied op 00
clearram clr 0,x
inx
cpx #dataend
bls clearram
ldx #regsbeg |laat IX op de bank met I/O registers wijzen
*************************************************
* seriële poort
*************************************************
PROGRAM space
clistart equ $ |het beginadres van deze module
* initialisatie
* initialiseer de seriële poort
ldab #(scp1+scp0)
stab baud |kies 9600 BAUD ( 8MHz kristal)
ldab #(te or re)
stab sccr2 |en zet zender en ontvanger aan
bra cliend |einde van de initialisatie
* subroutines voor de seriële poort
PROGRAM space
* kijk of er een karakter ontvangen is
* zoja, zet dan de zerovlag op '0'
serincheck equ $
pshb
ldab scsr |lees de status vlaggen
andb #rdrf |en test op het 'receiver full' bit
pulb
rts
* kijk of de seriele poort gereed is om een teken te versturen
* zoja, zet dan de zerovlag op '0'
seroutcheck equ $
pshb
ldab scsr |lees de staus vlaggen
andb #tc |en test op het 'transmitter empty' bit
pulb
rts
* haal een teken op uit de ontvanger, en zet het in accumulator B
getchar equ $
bsr serincheck |wacht totdat er een teken ontvangen is
beq getchar
ldab scdr |en lees het teken uit het ontvanger register
rts
* verstuur een teken via de seriële poort
putchar equ $
bsr seroutcheck |wacht totdat de zender gereed is
beq putchar
stab scdr |en zet dan het teken in het verzendregister
rts
cliend equ $ |einde van de cli module
*************************************************
* real-time interrupt
*************************************************
PROGRAM space
rtistart equ $ |het beginadres van deze module
rtirate equ 33 |het aantal interrupts dat geteld wordt
DATA space
rticount rmb 1 |deze teller wordt bij elke interrupt verhoogd
* initialisatie van de real-time interrupt
PROGRAM space
ldx #regsbeg |IX wijst naar de I/O registers
ldab #$7E |vul de entry in de interrupttabel in
stab rtiint |met een sprong instructie naar de routine
ldd #rtiintentry
std rtiint+1 |die de interrupt afhandelt
bset pactl+regsbeg,x,(rtr1 or rtr0)
|zet de real-time interrupt tijd op 32.768ms
|met 8MHz Kristal (E / 2^16)
bset tmsk2+regsbeg,x,rtii
|laat de interrupts door
bra rtiend |einde van de initialisatie
* subroutine voor de afhandeling van de real-time interrupt
PROGRAM space
rtiintentry equ $
ldab #rtif
stab tflg2 |reset de interrupt-vlag
inc rticount |en tel de interrupt
rti
***** real-time interrupt interface routines
PROGRAM space
* test op time-out. zet de zero-vlag indien er een time-out is.
checktimeout equ $
pshb
sei |houd interrupts tijdelijk tegen
ldab rticount |kijk hoe vaak er een interrupt was
subb #rtirate |indien er minimaal 'rtirate' interrupts
blo checkrti9 |zijn geweest, dan is er een timeout en moet
stab rticount |'rtirate' van de teller worden afgetrokken
clrb |daarnaast moet de zerovlag gezet worden
checkrti9 cli |daarna kunnen de interrupts weer worden
pulb |doorgelaten
rts
rtiend equ $ |einde van de real-time interrupt module
*************************************************
* het hoofdprogramma
*************************************************
PROGRAM space
bra main0
* subroutine om een byte (in B) te verzenden in 8 enen of nullen
sendbyte equ $
psha
tba
pshx
pshb
ldab #$0D |verstuur eerst een carriage-return
jsr putchar
ldx #8 |er zijn 8 bits te versturen
sendbyte0 ldab #'0' |neem aan dat er een '0' verstuurd moet
tsta |verstuur het meest linkse bit van A
bpl sendbyte1 |dit is een '1' als A negatief is, en anders
ldab #'1' |een '0'
sendbyte1 jsr putchar
lsla |schuif het volgende bit naar links
dex |er is een bit gedaan
bne sendbyte0 |ga door met zenden totdat alle 8 bits gedaan
pulb
pulx
pula
rts
main0 jsr serincheck |kijk of er iets ontvangen is
beq main1 |ga door als er niets is ontvangen
jsr getchar |haal anders het teken op
aslb |schuif de twee laatste bits 5 plaatsen naar links
aslb
aslb
aslb
aslb
stab porta |en zet het op de outputs (LED1 en LED2)
main1 jsr checktimeout
bne main2 |kijk of de inputs al verstuurd moeten worden
ldab porte |zoja, haal dan de inputs op
jsr sendbyte |en verstuur ze naar de PC
main2 bra main0 |blijf dit herhalen
end
Debuggen met de seriële poort.
Debuggen is het vinden en corrigeren van fouten in het programma. Wanneer er fouten gevonden moeten worden, betekent dit dat het programma grondig getest moet worden. Het is meestal erg lastig een compleet programma in één keer te testen. Daarom is het verstandig het programma op te bouwen uit verschillende afgeronde stukken (modulen.) Deze stukken kunnen dan stuk- voor stuk getest en bewezen worden.
Om een module te testen moet U er meestal wat code 'omheen' schrijven. Dit testprogramma moet de module gebruiken zoals het uiteindelijke programma de module zou gebruiken, en de resultaten op de één of andere manier controleren of zichtbaar maken zodat U de resultaten zelf kunt controleren.
Met behulp van de seriële poort en de PC, kunt U tussenresultaten in het programma zichtbaar maken op het scherm van de PC. Door op strategische plaatsen in het programma enkele tussenresultaten naar de PC op te sturen, kunt U op het scherm van de PC redelijk volgen wat het programma aan het doen is.
Om tussenresultaten zichtbaar te kunnen maken, moeten deze in 'leesbare' vorm naar de PC gestuurd worden. Hiertoe dienen de volgende routines. De routines stellen U in staat getallen naar hexadecimale of decimale ASCII te converteren, en vervolgens op te sturen via de seriële poort. *************************************************
* Strings en getal conversies
*************************************************
*
* Strings bestaan uit reeksen bytes in het geheugen, met aan het eind
* een NULL teken ($00). Deze $00 behoort niet tot de string, maar geeft
* het einde van de string aan.
* De string I/O vereist een routine 'putchar', die het teken in (B) naar
* een seriële poort stuurt.
*
PROGRAM space
stringstart equ $ |het beginadres van deze module
jmp stringend
* verstuur een string, die door IX aangewezen wordt, en afgeloten is met 00
* laat IX na aanroep op het eind van de string wijzen
pstring equ $
pshb
pstring1 ldab 0,x |haal een karakter van de string op
beq pstring2 |en stop als het een NULL is
jsr putchar |anders wordt het karakter verzonden
inx |en wordt het volgende karakter bekeken
bra pstring1
pstring2 pulb
rts
* verstuur een carriage-return en een line-feed
crlfstring fcb $0D, $0A, 00
newline equ $
pshx
ldx #crlfstring
bsr pstring
pulx
rts
* subroutine om een word (in D) te verzenden als 4 hexadecimale cijfers
sendword equ $
pshb |bewaar het minst significante byte
tab |en verstuur het meest significante eerst
bsr sendbyte
pulb |verstuur dan het minst significante byte
* subroutine om een byte (in B) te verzenden als twee hexadecimale cijfers
sendbyte equ $
pshb
lsrb |verstuur eerst de vier meest sign. bits
lsrb
lsrb
lsrb
bsr sendnibble |en dan de andere vier bits
pulb
* subroutine om een nibble (4 bits) in B te verzenden als een hex. cijfer
sendnibble equ $
andb #$0F |zorg ervoor dat het echt een nibble is
addb #'0' |maak er een cijfer van
cmpb #'9' |en als het groter is dan een '9'
bls sendnibble0 |maak er dan een letter A..F van
addb #('A' '9' 1)
sendnibble0 jsr putchar
rts
* converteer een 16 bits waarde in D naar een decimaal getal
* en stuur het resultaat van 5 karakters naar de seriële poort
pdecimal equ $
DATA space
binvalue rmb 2 |buffer voor de binaire versie van het getal
bcdvalue rmb 3 |buffer voor de BCD versie van het getal
PROGRAM space
pshb |bewaar de registers op de stack
psha
std binvalue |bewaar het te converteren getal
ldd #0 |maak de BCD representatie van het getal 0
std bcdvalue
staa bcdvalue+2
ldab #16 |nu moeten er 16 bits naar BCD omgezet worden
pdecimal2 lsl binvalue+1 |schuif de te converteren waarde een bit links
rol binvalue |dit komt overeen met vermenigvuldigen met 2
ldaa bcdvalue+2 |de carry wordt by het BCD getal opgeteld
adca #0
staa bcdvalue+2
decb |kijk of alle 16 bits reeds gedaan zijn
beq pdecimal3 |zo niet, vermenigvuldig het BCD getal dan ook
adda bcdvalue+2 |met twee, door het bij zichzelf op te tellen
daa |in BCD natuurlijk
staa bcdvalue+2
ldaa bcdvalue+1
adca bcdvalue+1
daa
staa bcdvalue+1
ldaa bcdvalue
adca bcdvalue
daa
staa bcdvalue
bra pdecimal2 |en ga terug om de rest van het getal te doen
pdecimal3 ldab bcdvalue |het getal is nu in BCD beschikbaar
jsr sendbyte |BCD is eenvoudig om te zetten naar ASCII
ldd bcdvalue+1 |converteer alle BCD digits
jsr sendword |en verstuur ze via de seriele poort
pula |haal de registers terug van de stack
pulb
rts
stringend equ $
|