Atypical code examples
8-bit binary-to-ASCII
include "p16f628.aty" Decimal: byte .buff[3] const .ones = 2 const .tens = 1 const .hundreds = 0 .Convert: // converts W to 3 ASCII digits in .buff .buff[.ones] = w w = '0', => .buff[.hundreds], => .buff[.tens] do w = 100 .buff[.ones] -=> w if !STATUS<C> then break .buff[.ones] = w ++.buff[.hundreds] loop do w = 10 .buff[.ones] -=> w if !STATUS<C> then break .buff[.ones] = w ++.buff[.tens] loop w = '0', +=> .buff[.ones] return
CRC16
Atypical version of this C code.
include "p16f628.aty" CRC: const lo = 0, hi = 1 byte .crc[2], .temp[2] .Init: clr .crc[hi] clr .crc[lo] return .Data: .temp = w w = .crc[hi], ^ .crc[lo], ^=> .crc[hi], ^=> .crc[lo] // swap hi and lo w = .temp, ^=> .crc[lo] w = swap .crc[lo], & 0x0f, ^=> .crc[lo] w = swap .crc[lo], & 0xf0, ^=> .crc[hi] w = swap .crc[lo], => .temp[lo], => .temp[hi] w = 0x0f, &=> .temp[hi] w = 0xf0, &=> .temp[lo] STATUS<C> = 0 rol .temp[lo] rol .temp[hi] w = .temp[lo], ^=> .crc[lo] w = .temp[hi], ^=> .crc[hi] return
PS/2 keyboard communications
include "..\p16f628.aty"
config _WDT_OFF & _INTRC_OSC_CLKOUT & _LVP_OFF & _MCLRE_OFF
varorg 0x20
byte temp
org 0
call Keyboard.Init
call Console.Init
byte .b
do
call Keyboard.Rx; w => .b
w = .b, ^ 0xaa
loop while !STATUS<Z>
w = 0xed; call Keyboard.Tx; call Keyboard.Rx
w = 0x02; call Keyboard.Tx; call Keyboard.Rx // Num Lock LED
w = '>'; call Console.Emit
call Console.Cr
do
call Keyboard.Read
call Console.Emit
loop
OutputWInHex:
byte .b
.b = w
w = swap .b, & 0x0f; call .toHex; call Console.Emit
w = .b, & 0x0f; call .toHex; call Console.Emit
return///
w = .b; goto Console.Emit
.toHex:
temp = w
w = ($+4>>8), => PCLATH
w = temp, +=> PCL
.table: retlw { "0123456789abcdef" }
assert ($-1>>8) == (#.table>>8)
Delay:
byte .i, .j
.i = w
clr .j
do
do
nop; nop; nop
loop while --.j
loop while --.i
return
//----- Keyboard stuff ----------------------------------------------------------------
// 2003-12-28 trying keyboard
// --------+ +--------
// Kbd CLOCK| <--> |RA0 16F628
// DATA| <--> |RA1
// --------+ +--------
//
// connector (bottom view)
// clock --o o
// o o o o -- +5
// / |
// gnd data
//
// 2003-12-28 can read scan codes
// 2003-12-30 use clock line to halt transmission while busy
// 2003-12-30 trying to implement bidirectional communication
// 2004-01-01 partial success; lots of resend messages from kbd
// 2004-01-02 trying change of timing: change bits immediately after clock goes low
// (instead of waiting for it to go high). Guess what? It works!
// Also discovered that the mapping between bits and kbd LEDS isn't
// what one might expect.
// to do:
// ASCII conversion
// interrupt-driven?
// Communicating with an AT keyboard.
// Keyboard.Init -- initialization stuff
// Keyboard.Rx -- low-level routine to read a byte from the keyboard
// Keyboard.Tx -- low-level routine to send a byte to the keyboard
// PORTA bits
const CLOCK = 0
const DATA = 1
const LED = 2
Keyboard:
// a few useful ASCII codes:
const .BS = 8, .CR = 13, .ESC = 27, .TAB = 9
// some made-up codes:
const .F1 = 0xF1, .F2 = 0xF2, .F3 = 0xF3, .F4 = 0xF4
const .F5 = 0xF5, .F6 = 0xF6, .F7 = 0xF7, .F8 = 0xF8
const .F9 = 0xF9, .F10 = 0xFA, .F11 = 0xFB, .F12 = 0xFC
// useful scan codes:
const scLSHIFT = 0x12, scRSHIFT = 0x59, scCAPSLOCK = 0x58
byte .shift // <1> = l.shift, <0> = r.shift
byte .capsLock // <1> = caps lock key pressed (for auto-repeat), <0> = caps lock on
.Init:
w = 7, => CMCON
clr PORTA
STATUS<RP0> = 1
bank 1
TRISA<LED> = 0, <CLOCK> = 0 // <DATA> = 1 on power-up
STATUS_1<RP0> = 0
bank 0
clr .shift
clr .capsLock
return
byte .i, .b
.Rx:
STATUS<RP0> = 1
bank 1
TRISA<CLOCK> = 1 // release clock line; keyboard can send now
STATUS_1<RP0> = 0
bank 0
call .waitForClockLowThenHigh // start bit
w = 8, => .i
do // 8 data bits
ror .b, <7> = 0
call .waitForClockLow
if PORTA<DATA> == 1 then .b<7> = 1
call .waitForClockHigh
loop while --.i
w = .b
call .waitForClockLowThenHigh // parity bit
call .waitForClockLowThenHigh // stop bit
STATUS<RP0> = 1
bank 1
TRISA<CLOCK> = 0 // tell keyboard to suspend transmission
STATUS_1<RP0> = 0
bank 0
return
.Tx: // enter with byte to send in W
.b = w
PORTA<DATA> = 0
STATUS<RP0> = 1
bank 1
TRISA<DATA> = 0 // bring data line low
STATUS_1<RP0> = 0
bank 0
STATUS<RP0> = 1
bank 1
TRISA<CLOCK> = 1 // release clock line; keyboard can send now
STATUS_1<RP0> = 0
bank 0
call .waitForClockLow // start bit
byte .parity
clr .parity
w = 8, => .i
do // 8 data bits
w = .b, & 1 // lsb
STATUS<RP0> = 1
bank 1
if STATUS_1<Z> then TRISA<DATA> = 0
if !STATUS_1<Z> then TRISA<DATA> = 1
STATUS_1<RP0> = 0
bank 0
w +=> .parity
ror .b
call .waitForClockHighThenLow
loop while --.i
w = .parity, & 1
STATUS<RP0> = 1
bank 1
if STATUS_1<Z> then TRISA<DATA> = 1
if !STATUS_1<Z> then TRISA<DATA> = 0
STATUS_1<RP0> = 0
bank 0
call .waitForClockHighThenLow // parity bit
STATUS<RP0> = 1
bank 1
TRISA<DATA> = 1 // release data line
STATUS_1<RP0> = 0
bank 0
call .waitForClockHighThenLow // stop bit
call .waitForClockHighThenLow // ack bit (really ought to test for valid ack)
STATUS<RP0> = 1
bank 1
TRISA<CLOCK> = 0 // tell keyboard to suspend transmission
STATUS_1<RP0> = 0
bank 0
return
.waitForClockLowThenHigh:
call .waitForClockLow
// and fall through
.waitForClockHigh:
do
loop while PORTA<CLOCK> != 1
return
.waitForClockLow:
do
loop while PORTA<CLOCK> != 0
return
.waitForClockHighThenLow:
call .waitForClockHigh
goto .waitForClockLow
.Read:
byte .ch, .j
do
call .Rx; w => .ch
w ^= 0xe0
if STATUS<Z> then // e0 prefix
call .Rx; w => .ch // get next byte
w ^= 0xf0
if STATUS<Z> then // key up
call .Rx // ..eat following byte
else // key down
w ^= (0xf0 ^ 0x4a) // ..keypad /
if STATUS<Z> then
w = '/'; return
endif
w ^= (0x4a ^ 0x5a) // ..keypad enter
if STATUS<Z> then
w = .CR; return
endif
endif
continue
endif
w ^= (0xe0 ^ 0xe1)
if STATUS<Z> then // e1 prefix: break key
w = 7, => .j
do
call .Rx // eat 7 following bytes: 1477E1F014F077
loop while --.j
continue
endif
w ^= (0xe1 ^ 0xf0)
if STATUS<Z> then // f0 prefix: key up
call .Rx; w => .ch
call .testShiftKeysUp
else // key down
w = .ch; call .testShiftKeysDown
w ^= 0
if !STATUS<Z> then continue
w = .ch
.shift = .shift
if STATUS<Z> then
call .scanCodeToAsciiUnshifted
else
call .scanCodeToAsciiShifted
endif
if .capsLock<0> then call .convertToUpperCase
return
endif
loop
.testShiftKeysDown:
w ^= scLSHIFT
if STATUS<Z> then
.shift<1> = 1
w = 1; return
endif
w ^= (scLSHIFT ^ scRSHIFT)
if STATUS<Z> then
.shift<0> = 1
w = 1; return
endif
w ^= (scRSHIFT ^ scCAPSLOCK)
if STATUS<Z> then
if .capsLock<1> then goto .1 // if caps lock is auto-repeating, ignore
w = 0xed; call Keyboard.Tx; call Keyboard.Rx // command to set LEDs
if .capsLock<0> == 0 then
.capsLock<0> = 1
w = 0x06 // Num Lock & Caps Lock LEDs on
else
.capsLock<0> = 0
w = 0x02 // Num Lock LED (Caps Lock off)
endif
call Keyboard.Tx; call Keyboard.Rx
.capsLock<1> = 1
.1: w = 1; return
endif
w = 0; return
.testShiftKeysUp:
w ^= scLSHIFT
if STATUS<Z> then .shift<1> = 0
w ^= (scLSHIFT ^ scRSHIFT)
if STATUS<Z> then .shift<0> = 0
w ^= (scRSHIFT ^ scCAPSLOCK)
if STATUS<Z> then .capsLock<1> = 0
return
org ($+0xff)&(~0xff)
.scanCodeToAsciiUnshifted:
w -= 0x84 // 0x84 items in table
if STATUS<C> then
w = 0xfd
return
endif
w += 0x84, => temp
w = ($+4>>8), => PCLATH
w = temp, +=> PCL
.table1:retlw { 0, .F9, 0, .F5, .F3, .F1, .F2, 0, 0, .F10, .F8, .F6, .F4, .TAB, '`', 0 }
retlw { 0, 0, 0, 0, 0, "q1", 0, 0, 0, "zsaw2", 0 } // 10-1f
retlw { 0, "cxde43", 0, 0, " vftr5", 0 } // 20-2f
retlw { 0, "nbhgy6", 0, 0, 0, "mju78", 0 } // 30-3f
retlw { 0, ",kio09", 0, 0, "./l;p-", 0 } // 40-4f
retlw { 0, 0, "'", 0, "[=", 0, 0, 0, 0, .CR, "]", 0, "\", 0, 0 } // 50-5f
retlw { 0, 0, 0, 0, 0, 0, .BS, 0, 0, "1", 0, "47", 0, 0, 0 } // 60-6f
retlw { "0.2568", .ESC, 0, .F11, "+3-*9~", .F12 } // 70-7f
retlw { 0, 0, 0, .F7 } // 80-83
assert ($-1>>8) == (#.table1>>8)
.convertToUpperCase:
w -= 'a'
if !STATUS<C> then
w += 'a'
return
endif
w -= ('z' + 1 - 'a')
if STATUS<C> then
w += ('z' + 1)
return
endif
w -= ('a' - 'A' - ('z' + 1))
return
org ($+0xff)&(~0xff)
.scanCodeToAsciiShifted:
w -= 0x84 // 0x84 items in table
if STATUS<C> then
w = 0xfc
return
endif
w += 0x84, => temp
w = ($+4>>8), => PCLATH
w = temp, +=> PCL
.table2:retlw { 0, .F9, 0, .F5, .F3, .F1, .F2, 0, 0, .F10, .F8, .F6, .F4, .TAB, '~', 0 }
retlw { 0, 0, 0, 0, 0, "Q!", 0, 0, 0, "ZSAW@", 0 } // 10-1f
retlw { 0, "CXDE$#", 0, 0, " VFTR%", 0 } // 20-2f
retlw { 0, "NBHGY^", 0, 0, 0, "MJU&*", 0 } // 30-3f
retlw { 0, "<KIO)(", 0, 0, ">?L:P_", 0 } // 40-4f
retlw { 0, 0, '"', 0, "{+", 0, 0, 0, 0, .CR, "}", 0, "|", 0, 0 } // 50-5f
retlw { 0, 0, 0, 0, 0, 0, .BS, 0, 0, "1", 0, "47", 0, 0, 0 } // 60-6f
retlw { "0.2568", .ESC, 0, .F11, "+3-*9", 0, .F12 } // 70-7f
retlw { 0, 0, 0, .F7 } // 80-83
assert ($-1>>8) == (#.table2>>8)