Programmeren in TI-83+ Assembly/Input en output/Invoer door de gebruiker
Soms moet de gebruiker tekst ingeven in het programma. Dit gaat in de meeste programmeertalen simpel. Het probleem bij Assembly is, dat een invoerveld volledig zelf moet worden geprogrammeerd door de programmeur.
Op deze pagina leer je hoe je een eenvoudig invoervakje maakt; dus zonder knipperende cursor en dergelijke. Een uitgebreidere variant kun je vinden bij de cursus Learn TI-83 Plus Assembly In 28 Days: Day 27.
Als je geen zin hebt om te kijken hoe het invoervak wordt gemaakt, kun je onderaan de pagina ook direct het resultaat bekijken.
Het begin: een opzet voor het invoervakje
[bewerken]We gaan proberen om het invoervakje van het TI-Basic-commando Input
na te maken. Hiervoor moeten we het volgende doen:
- Zorg ervoor dat er een plaats in het geheugen is (wij gebruiken
AppBackUpScreen
) om de ingevoerde tekst op te slaan. - Zet een van de registers (wij gebruiken
b
) op 0; dit gaan we gebruiken om het aantal tekens op te slaan. - Verhoog
b
met 1. - Kijk welke toets er is ingedrukt (
_getCSC
). - Als er helemaal geen toets ingedrukt is: ga terug naar 4.
- Als de toets Enter is: stop het invoervak.
- Zoek de letter op die bij de ingedrukte toets hoort.
- Voeg de letter toe aan de opgeslagen reeks letters, door hem op te slaan in
AppBackUpScreen
+ het aantal tekens in het invoervak (b
). - Schrijf de huidige string op het scherm. Hiervoor moet je er eerst in het geheugen een 0 achter zetten (voor
_PutS
). - Als het aantal tekens (
b
dus) groter is dan een bepaald maximum, dan stop het invoervak. - Ga naar 3.
Je ziet dat het in TI-Basic makkelijker gaat, maar er is nu eenmaal geen andere manier om een invoervak te maken in Assembly.
Schrijven van de code
[bewerken]Nu gaan we stap voor stap de code in elkaar zetten. Je kunt iedere stap zelf uitproberen op de emulator. (Denk aan de standaardcode!)
b
op 0 zetten
[bewerken]BeginInvoervak: ld b, 0 EindInvoervak: ret
We maken direct alvast twee labels aan aan het begin en einde van het invoervak.
Wachten op een toets
[bewerken]BeginInvoervak: ld b, 0 Toetsroutine: inc b Toetsvraag: push bc bcall(_getCSC) pop bc jp z, Toetsvraag EindInvoervak: ret
We maken ook alvast een label voor de _getCSC
, om naar terug te keren als er weer een toets wordt ingedrukt. Ook verhogen we direct b
(stap 3). We moeten de inhoud van register b
beschermen, dus zetten we die tijdelijk even op de stack.
Als Enter, dan stop
[bewerken]BeginInvoervak: ld b, 0 Toetsroutine: inc b Toetsvraag: push bc bcall(_getCSC) pop bc jp z, Toetsvraag cp skEnter jp z, EindInvoervak jp Toetsroutine EindInvoervak: ret
We vergelijken a
met de toetswaarde voor Enter (kEnter
). Als dat zo is, dus als er op Enter is gedrukt, ga dan naar EindInvoervak. Als er niet naar EindInvoervak is gesprongen, gaat het programma vanzelf naar Toetsroutine terug om op een nieuwe toets te wachten.
We hebben nu de hoofdstructuur van het vakje klaar.
Letter zoeken
[bewerken]Een eerste poging
[bewerken]Hoe kunnen we nu de letter zoeken die bij de toets hoort? Je kunt natuurlijk een serie cp
's maken, bijvoorbeeld iets als
cp skMath ; voeg een A toe cp skMatrix ; voeg een B toe cp skPrgm ; voeg een C toe
... maar je snapt wel dat dit te langzaam is.
Een LUT maken
[bewerken]Een betere manier is om een soort tabel aan te leggen, die de toetswaarden koppelt aan de bijbehorende letter. Maar hoe doen we dat? Laten we als eerste eens in ti83plus.inc kijken bij de Scan Code Equates. We zien hier dat de nummers van de toetscodes allemaal liggen tussen 01h en 38h (van 1 tot 56 dus). Zie de tabel van scancodes en de bijbehorende letters hieronder.
Als we nu een rij letters in het geheugen zetten, bijvoorbeeld achter in het programma (met .db
), in de volgorde van de nummers van deze toetscodes, dan kunnen we de bijbehorende letter uit het geheugen pikken door de toetscode als geheugenadres te gebruiken. Zie de afbeelding hieronder. Ieder vakje stelt daarin een byte in het geheugen voor.
Je ziet dat het op deze manier mogelijk is om de letters op een snellere manier te verkrijgen. Deze strategie van zoeken noemen we ook wel een LUT (lookup table = opzoektabel). Laten we als eerste eens de LUT gaan maken:
Lettertabel: .db "...........WRMH." .db "...VQLG...ZUPKFC" .db ". YTOJEB..XSNIDA"
Je ziet dat ik voor een toets waar geen letter op staat een punt (.
) heb gebruikt. Als je dus op zo'n toets drukt, verschijnt er een punt. Op deze punt kunnen we later filteren: als de letter een punt is, voeg dan niets toe.
Zoeken in de LUT
[bewerken]Nu moeten we een stukje code schrijven dat de juiste letter uit de LUT haalt. Om dat voor elkaar te krijgen, moeten we eerst het geheugenadres van de letter achterhalen door de scancode (in a
) op te tellen bij het geheugenadres van het label Lettertabel:
ld hl, Lettertabel ld e, a ld d, 0 add hl, de
Nu staat het geheugenadres van de letter in hl
. We kunnen dus met (hl)
de letter achterhalen. Deze letter zetten we tijdelijk in c
.
Onze totale code is dus tot nu toe:
BeginInvoervak: ld b, 0 Toetsroutine: inc b Toetsvraag: push bc bcall(_getCSC) pop bc jp z, Toetsvraag cp skEnter jp z, EindInvoervak ld hl, Lettertabel ld e, a ld d, 0 add hl, de ld c, (hl) jp Toetsroutine EindInvoervak: ret Lettertabel: .db "...........WRMH." .db "...VQLG...ZUPKFC" .db ". YTOJEB..XSNIDA"
Letter toevoegen aan de tekenreeks
[bewerken]We hebben nu de letter, maar nu gaan we die toevoegen aan de huidige tekst. Om te beginnen moeten we dus het geheugenadres bepalen van de plek waar de letter moet worden neergezet.
ld hl, AppBackUpScreen ld e, d ld d, 0 add hl, de
Het geheugenadres waar de letter moet worden neergezet staat nu in hl
.
Nu kopiëren we de letter:
ld (hl), c
En een 0 erachter:
inc hl ld (hl), 0
Tekenreeks schrijven
[bewerken]Nu schrijven we de getypte tekenreeks naar het scherm met de bcall _PutS
.
ld hl, 0 ld (CurCol), hl ld hl, AppBackUpScreen push bc bcall(_PutS) pop bc
Onze totale code tot nu toe is dus:
BeginInvoervak: ld b, 0 Toetsroutine: inc b Toetsvraag: push bc bcall(_getCSC) pop bc jp z, Toetsvraag cp skEnter jp z, EindInvoervak ld hl, Lettertabel ld e, a ld d, 0 add hl, de ld c, (hl) ld hl, AppBackUpScreen ld e, d ld d, 0 add hl, de ld (hl), c inc hl ld (hl), 0 ld hl, 0 ld (CurCol), hl ld hl, AppBackUpScreen push bc bcall(_PutS) pop bc jp Toetsroutine EindInvoervak: ret Lettertabel: .db "...........WRMH." .db "...VQLG...ZUPKFC" .db ". YTOJEB..XSNIDA"