Created: 7th December 1999
Last Modified: 15th December 1999
This page will explain another two ports, Port 1 (the keypad port) and Port 2 (the contrast port).
Rather than using the various ROM calls that access the keypad you can read it directly using ports. The port that controls the keypad is port 1. It can be written to and read from, and works as follows:
Writing to port 1 sends a mask to the keypad, enabling you to only read certain keys. Reading from the keypad tells you which group(s) of keys have at least one key pressed down. The values are described in the table below.
| Read (Bit Cleared) | Write (Binary) | ||||||
|---|---|---|---|---|---|---|---|
| 00111111 | 01011111 | 01101111 | 01110111 | 01111011 | 01111101 | 01111110 | |
| 7 | More | Alpha | x-Var | Del | |||
| 6 | Exit | Graph | Table | Prgm | Custom | Clear | |
| 5 | 2nd | Log | Sin | Cos | Tan | ^ | |
| 4 | F1 | LN | EE | ( | ) | ÷ | |
| 3 | F2 | x2 | 7 | 8 | 9 | × | Up |
| 2 | F3 | , | 4 | 5 | 6 | - | Right |
| 1 | F4 | STO> | 1 | 2 | 3 | + | Left |
| 0 | F5 | 0 | . | (-) | Enter | Down | |
So, for example, to pause the calculator until enter is pressed you could do the following (the bit read in is reset, or 0 if the key has been pressed):
ld a,%01111101 ;bitmask for Enter key out (1),a ;send it to keypad KeyLoop: in a,(1) ;get value from keypad rrca ;rotate it right, placing the ;least significant bit in the ;carry flag... jr c,KeyLoop ;...and if there is no carry ;enter has not been pressed
Notice that there are lots of comments for this piece of code. This is because it's optimised for code size, which makes it a bit cryptic at first. A more mundane way of doing the same thing (but taking up one more byte) is:
ld a,%01111101 ;bitmask for Enter key out (1),a ;send it to keypad KeyLoop: in a,(1) ;get value from keypad and %00000001 ;and it with bit for Enter key jr nz,KeyLoop ;and if the bit is not zero ;enter has not been pressed
The third way of doing it involves the bit instruction. This method
differs from the previous two ways in that the value read in is not destroyed. In
this case it's not important (and a waste of time) but sometimes it is, for example
when testing for multiple keys (often the arrow or F keys). The bit
instruction isn't that useful usually - it tests a specific bit of an argument.
ld a,%01111101 ;bitmask for Enter key out (1),a ;send it to keypad KeyLoop: in a,(1) ;get value from keypad bit 0,a ;and test bit 0 jr nz,KeyLoop ;if it is set enter has not ;been pressed, so loop
In most circumstances I use the second method, but I use the first when it will work (only certain keys are worth doing this for). As you can see, in assembly there are many ways of doing the same thing...
The contrast on the ti86 is also controlled from a port - Port 2. Writing
a value (between $0 and $1f) to it adjusts the contrast. Unfortunately it is
write-only. To get the current value of the contrast you must read memory
location $c008 (equate _contrast). Similarly, if you exit a
program with the contrast changed you should write the new value to $c008.
Here's a simple program that flickers the screen from being black to clear by
setting the contrast to $0 then $1f, then $0 and so on. The halt
instruction pauses the calculator until an interrupt occurs - 1/200th of a
second.
#include "ti86asm.inc" .org _asm_exec_ram nop jp ProgStart .dw 0,ShellTitle ShellTitle: .db "Flicker Screen",0 ProgStart: xor a ;a = 0 ld bc,$2002 ;b = 20 (loop counter) ;c = 2 (contrast port) FlickerLoop: out (c),a ;set contrast to a cpl ;a = not a and $1f ;a = a and $1f ld d,12 ;d = 12 (delay loop) DelayLoop: halt ;pause for 1/200 sec dec d ;d = d - 1 jr nz,DelayLoop ;if d > 0 goto DelayLoop djnz FlickerLoop ;b = b - 1; if > 0 goto FlickerLoop ld a,(_contrast) ;get real value for contrast out (c),a ;set contrast back to normal ret ;exit .end