| OUT (n), A | Sends a byte to port n via the accumulator. |
| OUT (C), reg | Sends a byte to port C via register reg. |
| IN A, (n) | Receives a byte from port n via the accumulator. Does not affect flags. | ||||||||
| IN reg, (C) | Receives a byte from port C via register reg. | ||||||||
|
|||||||||
A port is a device that lets the CPU transfer bytes between other pieces of otherwise unconnected hardware. What's that? You want an analogy? Okay, imagine you wanted to get a car from Yokohama to San Francisco; you couldn't just drive it over because they're separated by thousands of miles of open ocean. Instead, you'd take the car to the port of Yokohama, have a boat take it to the port in San Francisco, and drive off. Similarly, the CPU and the keypad have no real connection, so the port is used to interact.
The keyport on the TI-83 Plus is port #1, so we replace n in the two instructions with 1.
The first thing to do is enable the key group we want to read from. This is done by sending the value of that group to the key port. We then read from the key port and check the value returned. You can get the values from this table.
| Key Code | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| FE | FD | FB | F7 | EF | DF | BF | 7F | ||
| G r o u p |
BF | GRAPH | TRACE | ZOOM | WINDOW | Y= | 2nd | MODE | DEL |
| DF | STO | LN | LOG | x2 | x-1 | MATH | ALPHA | ||
| EF | 0 | 1 | 4 | 7 | , | SIN | APPS | X, T, θ, n | |
| F7 | . | 2 | 5 | 8 | ) | COS | PRGM | STAT | |
| FB | (-) | 3 | 6 | 9 | ( | TAN | VARS | ||
| FD | ENTER | + | - | × | ÷ | ^ | CLEAR | ||
| FE | down | left | right | up | |||||
ReadKey: LD A, %11111101 ; Check for [-] OUT (1), A IN A, (1) CP %11111011 JP Z, Minus LD A, %11111110 ; Check for [up] OUT (1), A IN A, (1) CP %11110111 JP Z, Up JP ReadKey Minus: LD HL, zs_minus b_call(_PutS) RET Up: LD HL, zs_up b_call(_PutS) RET zs_up: .DB "You pressed UP !", 0 zs_minus: .DB "You pressed - !", 0
Loop: LD A, %11011111 ; Enable group OUT (1), A IN A, (1) ; Input a key CP %11110111 ; Check if it's [LOG] RET Z ; End if so JP Loop
In Program 22-2 then, the key port was sending the bitwise AND of [LOG] and [ALPHA] which is %01110111. CP didn't work because it was looking for the exact value %11110111. BIT, on the other hand, will work because bit 3 is still zero.
If you want the calcultor to do something when a key is pressed, regardless of whether any other keys in the group are pressed, you should use BIT (or a shift instruction if possible). However, if you wanted a different action to be taken when two or more keys are pressed down, then you'd have to either use CP, or have a kind of a BIT chain.
b_call(_RunIndicOff)
LD HL, $1C23
LD (x_pos), HL
DispText:
b_call(_ClrLCDFull)
LD HL, (x_pos)
LD (PenCol), HL
LD HL, string
b_call(_VPutS)
LD C, 1
InKey:
LD A, %10111111 ; Check for [DEL] to exit
OUT (C), A
IN A, (C)
BIT 7, A
JR NZ, InArrow
LD A, $FF ; Reset key port
OUT (C), A
RET
InArrow:
LD A, $FF ; Reset key port
OUT (C), A
LD A, %11111110
OUT (C), A
IN B, (C)
BIT 0, B
JP Z, Down
BIT 1, B
JP Z, Left
BIT 2, B
JP Z, Right
BIT 3, B
JP Z, Up
JP InKey
Down:
CALL MoveDown
BIT 1, B
CALL Z, MoveLeft
BIT 2, B
CALL Z, MoveRight
JP DispText
Left:
;There is no need to check for Down key anymore.
CALL MoveLeft
BIT 3, B
CALL Z, MoveUp
JP DispText
Right:
CALL MoveRight
BIT 3, B
CALL Z, MoveUp
JP DispText
Up:
CALL MoveUp
JP DispText
MoveDown:
LD A, (y_pos) ; Check if at bottom edge of screen
CP 57
RET Z
INC A ; Down one pixel
LD (y_pos), A
RET
MoveUp:
LD A, (y_pos) ; Check if at top edge of screen
OR A
RET Z
DEC A ; Up one pixel
LD (y_pos), A
RET
MoveLeft:
LD A, (x_pos) ; Check if at left edge of screen
OR A
RET Z
DEC A ; Left one pixel
LD (x_pos), A
RET
MoveRight:
LD A, (x_pos) ; Check if at right edge of screen
CP 96-28 ; 96 - number of pixels the string takes up
RET Z
INC A ; Right one pixel
LD (x_pos), A
RET
x_pos: .DB 0
y_pos: .DB 0
string: .DB "Let\'s Go!", 0