' ' stopwtch.bas event stopwatch for 68hc11 and 2-line LCD ' include "regs11.lib" asmfunc _outch ' replace _OUTCH declare lcdtimer declare wait declare clock0(4) ' clock 0 declare clock1(4) ' clock 1 declare n declare stopped const DLY100s = 20000 ' delay for 1/100th sec ' ' ISR to handle the 4.1 msec tic counter. ' This ISR decrements WAIT and LCDTIMER ' until either reaches 0, then rearms ' itself. ' interrupt $fff0 ' RTI if wait <> 0 wait = wait - 1 endif if lcdtimer <> 0 lcdtimer = lcdtimer - 1 endif pokeb tflg2, %01000000 end ' ' ISR to count hundredths of a second. ' This ISR automatically updates the values ' in the clock0 array, then rearms itself. ' interrupt $ffe0 ' toc5 ISR clock0(3) = clock0(3) + 1 ' bump 1/100s if clock0(3) > 99 ' if overflow... clock0(3) = 0 ' zero it clock0(2) = clock0(2) + 1 ' bump secs if clock0(2) > 59 ' if overflow... clock0(2) = 0 ' zero it clock0(1) = clock0(1) + 1 ' bump minutes if clock0(1) > 59 ' if overflow... clock0(1) = 0 ' zero it clock0(0) = clock0(0) + 1 ' bump hours if clock0(0) > 23 ' if overflow... clock0(0) = 0 ' zero it endif endif endif endif poke toc5, peek(toc5) + DLY100s ' set next time pokeb tflg1, $08 ' clear toc5 flag end ' ' wait until LCDTIMER variable reaches 0 ' WaitLCD: lcdtimer = pull() do loop until lcdtimer = 0 return ' ' Assembly-language replacement for _OUTCH low-level ' routine. This version of _OUTCH writes a character ' to the LCD. All calls to PRINT and other SBasic ' display routines will now write to the LCD. ' asm PORTB equ $1004 _outch pshb ldab PORTB andb #$07 orab #$07 stab PORTB rs=1, e=0, msb=0 orab #$0f stab PORTB rs=1, e=1, msb=0 tab andb #$f0 orab #$0c stab PORTB rs=1, e=1, data andb #$f4 stab PORTB rs=1, e=0, data ldab PORTB andb #$07 orab #$07 stab PORTB rs=1, e=0, msb=0 orab #$0f stab PORTB rs=1, e=1, msb=0 tab lslb lslb lslb lslb andb #$f0 orab #$0c stab PORTB rs=1, e=1, data andb #$f4 stab PORTB rs=1, e=0, data ldd #$100 out1 subd #1 bne out1 pulb rts endasm ' ' Move to start of second line on LCD ' NewLine: gosub LCDCmd, $c0 return ' ' Move to start of first line on LCD, do not clear ' display. ' Home: gosub LCDCmd, $80 return ' ' Clear LCD, then move to start of first line. ' ClearLCD: gosub LCDCmd, 1 ' clear and home LCD gosub WaitLCD, 2 ' wait a bit return ' ' LCDDataN sends the top four bits of a char to the ' LCD's data register. This routine toggles the RS ' and E lines as needed to time the transfer, using ' four writes to port B. ' ' Step 1: Set RS=1, E=0 ' Step 2: Set RS=1, E=1 ' Step 3: Set RS=1, E=1, data to bits 4-7 ' Step 4: Set RS=1, E=0, data to bits 4-7 ' LCDDataN: pokeb portb, ((peekb(portb) and $07) or $07) pokeb portb, peekb(portb) or $0f pokeb portb, peekb(portb) or ((pull() and $f0) or $0c) pokeb portb, peekb(portb) and $f4 return ' ' LCDCmdN sends the top four bits of a char to the ' LCD's command register. This routine toggles the ' RS and E lines as needed to time the transfer, ' using four writes to port B. ' ' Step 1: Set RS=0, E=0 ' Step 2: Set RS=0, E=1 ' Step 3: Set RS=0, E=1, cmd to bits 4-7 ' Step 4: Set RS=0, E=0, cmd to bits 4-7 ' LCDCmdN: pokeb portb, peekb(portb) and $03 pokeb portb, peekb(portb) or $08 pokeb portb, peekb(portb) or ((pull() and $f0) or $08) pokeb portb, peekb(portb) and $f0 return ' ' LCDCmd sends a byte to the LCD's command register, ' using two calls to LCDCmdN. ' LCDCmd: gosub LCDCmdN, pick(0) ' send the top nybble place 0, lshft(pick(0)) ' move low nybble to top place 0, lshft(pick(0)) place 0, lshft(pick(0)) place 0, lshft(pick(0)) gosub LCDCmdN, pull() ' send the low nybble return ' ' InitLCD sends a string of commands to the LCD following ' power-up. Timing between commands is done with WaitLCD. ' InitLCD: gosub WaitLCD, 10 gosub LCDCmdN, $30 gosub WaitLCD, 2 gosub LCDCmdN, $30 gosub WaitLCD, 2 gosub LCDCmdN, $30 gosub WaitLCD, 2 gosub LCDCmdN, $20 gosub WaitLCD, 10 gosub LCDCmd, $28 gosub WaitLCD, 10 gosub LCDCmd, 8 gosub WaitLCD, 10 gosub LCDCmd, 1 gosub WaitLCD, 10 gosub LCDCmd, 6 gosub WaitLCD, 10 gosub LCDCmd, 12 return ' ' Display a number as two decimal digits. ' Print2d: if pick(0) < 10 outch '0' else outch '0' + (pick(0) / 10) endif outch '0' + (pull() mod 10) return ' ' Display time on top line or bottom line of LCD, ' depending on argument. ' ShowTime: if pick(0) = 0 gosub Home print " "; gosub Print2d, clock0(0) outch ':' gosub Print2d, clock0(1) outch ':' gosub Print2d, clock0(2) outch '.' gosub Print2d, clock0(3) endif if pull() = 1 gosub NewLine print " "; gosub Print2d, clock1(0) outch ':' gosub Print2d, clock1(1) outch ':' gosub Print2d, clock1(2) outch '.' gosub Print2d, clock1(3) endif return ' ' Wait for the user to press the Start switch. The ' logic includes a 40 msec debounce delay, using variable ' WAIT. ' WaitForStart: do waitwhile portc, $01 ' wait until pc0 goes low wait = 10 do loop until wait = 0 loop while peekb(portc) and $01 = $01 poke toc5, peek(toc5) + DLY100s pokeb tflg1, $08 ' clear TOC5 flag pokeb tmsk1, $08 ' allow TOC5 interrupts stopped = 0 return ' ' See if the user pressed the Stop switch. The logic ' includes a 40 msec debounce delay, using variable ' WAIT. ' CheckForStop: if peekb(portc) and $02 = 0 wait = 10 do loop until wait = 0 if peekb(portc) and $02 = 0 pokeb tmsk1, $00 ' disable TOC5 interrupts stopped = -1 ' show clock is stopped endif endif return ' ' The main program. Set up the interrupts, clear ' the two clock arrays, wait for the Start switch, update ' the displays, and wait for the Stop switch. ' main: pokeb ddrc, $fc ' pc0 & pc1 = inputs pokeb tflg2, %01000000 ' clear RTI flag pokeb tmsk2, %01000000 ' allow RTI interrupts interrupts on for n=0 to 3 clock0(n) = 0 clock1(n) = 0 next gosub InitLCD print " Stopwatch 1.0"; wait = 500 do loop until wait=0 gosub ClearLCD print " Press START"; gosub NewLine print " to begin"; do gosub WaitForStart gosub ClearLCD for n = 0 to 3 clock1(n) = clock0(n) clock0(n) = 0 next gosub ShowTime, 0 gosub ShowTime, 1 do gosub CheckForStop if wait = 0 gosub ShowTime, 0 wait = 60 endif loop until stopped <> 0 loop end