Programmeren in TI-83+ Assembly/Input en output/Invoer door de gebruiker

Uit Wikibooks
Naar navigatie springen Naar zoeken springen

Programmeren in TI-83+ Assembly


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 e.d. 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:

  1. Zorg ervoor dat er een plaats in het geheugen is (wij gebruiken AppBackUpScreen) om de ingevoerde tekst op te slaan.
  2. Zet één van de registers (wij gebruiken b) op 0; dit gaan we gebruiken om het aantal tekens op te slaan.
  3. Verhoog b met 1.
  4. Kijk welke toets er is ingedrukt (_getCSC).
  5. Als er helemaal geen toets ingedrukt is: ga terug naar 4.
  6. Als de toets Enter is: stop het invoervak.
  7. Zoek de letter op die bij de ingedrukte toets hoort.
  8. Voeg de letter toe aan de opgeslagen reeks letters, door hem op te slaan in AppBackUpScreen + het aantal tekens in het invoervak (b).
  9. Schrijf de huidige string op het scherm. Hiervoor moet je er eerst in het geheugen een 0 achter zetten (voor _PutS).
  10. Als het aantal tekens (b dus) groter is dan een bepaald maximum, dan stop het invoervak.
  11. 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.

Fig10 skcodes.png


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.

Fig11 skcodes geheugen.png

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"
ArrowLeftNavbox.svg ← getKey Invoer door de gebruiker Toets → ArrowRightNavbox.svg
Informatie afkomstig van http://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.