Photo-gate timer with a PICAXE 20M2

From ShawnReevesWiki
Revision as of 18:19, 14 March 2014 by Shawn (talk | contribs) (Created page with "===Program listing=== This program can be compiled for a PICAXE 20M2, paired with a Newhaven 3V i2c LCD display. It will watch for high signals on five input pins, starting wi...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Program listing

This program can be compiled for a PICAXE 20M2, paired with a Newhaven 3V i2c LCD display. It will watch for high signals on five input pins, starting with C.5, and display times between C.5 tripping and the rest of the gates.

;2014 Shawn Reeves
;Hardware notes:
;only C.1 to C.5 may be used as interrupts on the 20M2 or 20X2 parts
;Only 20X2 and greater parts offer a dedicated hardware timer. To use 20M2, we use software counting
;Tested with a 20M2 to 20ms precision, but may drift with temperature, ICs, VCC.
;For more precise timing, leave the PICAXE environment for a crystal-timed µC with hardware timer.
;Attach a photo-gate to pins 5, 6 (and optionally 7, 8, then 9) of the PICAXE 20M2
;Tie unused photo-gate pins to ground or spurious signals will trip floating pins.
;Gates should provide TTL output 
;LCD display contrast depends on voltage of power supplied.
; Here it is adjusted to be readable from 3.3V to to 2.9V. Lower voltage will make lighter characters.

#picaxe 20M2	;declare type so compiler works correctly.
symbol count1 = w1	;track the time at second gate (pin 6)
symbol count2 = w2	;track the time at third gate
symbol count3 = w3	;track the time at fourth gate
symbol count4 = w4	;track the time at fifth gate
symbol counter = w5	;track the time since first gate was crossed (pin 5)
symbol loopWord = w6
symbol ones = b14
symbol tens = b15
symbol hundreds = b16
symbol thousands = b17
symbol tenThousands = b18

symbol interruptPin = b1 	;Track which gate we expect to close next
symbol LCDAddress = 124	;0x7C
symbol controlByte = 0
symbol functionSetDisplay = 0x38
symbol clearDisplay = 1
symbol homeDisplay = 2
symbol updatePeriod = 100	;How often to refresh display, in centiseconds. The larger, the more precise the timing

init:
pause 1000	;give a second for inputs to settle
;setfreq will affect all future timing instructions, including pause, pauseus, and hi2csetup
setfreq m32
;HI2CSETUP I2CMASTER, slaveaddress, i2cfast | i2cslow | i2cfast_8 | i2cslow_8 | i2cfast_16 | etc, i2cbyte | i2cword
HI2CSETUP I2CMASTER, LCDAddress, i2cfast_32, i2cbyte
initLCD:
hi2cout 0,($38);%00111000; FUNCTION SET 8 bit, 2 line, not double-height, 0, instruction set zero
pause 2
hi2cout 0,($39);%00111001; FUNCTION SET 8 bit, 2 line, not double-height, 0, instruction set one
pause 2
hi2cout 0,($14);%00010100; OSC set 1/5 bias, frequency last three bits
hi2cout 0,(%01111111);%01111000; Contrast set, four least significant contrast bits
hi2cout 0,(%01011101);%01011110; Power/ICON set, Icon on, booster on, two most significant contrast bits
hi2cout 0,($6D);%01101101; FOLLOWER CONTROL, follower on, last three bits follower amp ratio
hi2cout 0,($38);BACK TO INSTRUCTION SET ZERO
hi2cout 0,($0C);%00001100; DISPLAY ON, display on, cursor off, cursor position off
hi2cout 0,($01)		; Clear display
hi2cout 0,($06);%00000110;	ENTRY MODE, increment cursor, don't shift display
pause 3

restarting:
hi2cout 0, ($80)	;set data address to beginning of line 1
hi2cout $40, ("waiting for 1st gate")

counter = 0
count1 = 0
count2 = 0
count3 = 0
count4 = 0
interruptPin = 32	;%00100000	;Start at C.5
;set interrupt on inputs along port C, starting with C.5, C.4, ... for each photogate
setint interruptPin,interruptPin	;Interrupt only on current expected pin

main:
;Breaking 10µs pause into 1µs pauses, since interrupt causes program to go to next line
;;no matter how far pause was in execution.
;the timing overhead for each iteration of the following loop is about 40µs
for loopWord = 2 to updatePeriod
	pauseus 7700	;in units of 10µs (divided by frequency scale, 8), so this will count every 10 ms, our least significant digit
	inc counter
next loopWord
pauseus 6000	;adjust down from 10ms to account for display routine below. since setfreq is 32, 8000 is 10ms.
inc counter
#ifdef calibrateTime
	;the following conversion and display take about 2.5ms
	BINTOASCII counter, tenThousands, thousands, hundreds, tens, ones	;display counter to calibrate timing
	hi2cout 0, ($C8)	;set data address to middle of line 2
	hi2cout $40, (tenThousands, thousands, hundreds, %00101110, tens, ones)
#else
	pauseus 1500;estimate of amount of overhead the above time display would take.
#endif

goto main


interrupt:
if interruptPin = 32 then	;first gate was tripped, so start counting
	counter = 0
	count1 = 0
	count2 = 0
	count3 = 0
	count4 = 0
	interruptPin = 16
	setint interruptPin,interruptPin	;Interrupt only on current expected pin
	hi2cout 0, ($80)	;set data address to beginning of line 1
	hi2cout $40, ("1st gate tripped")
else if interruptPin = 16 then	;next gate was tripped, get time
	count1 = counter
	interruptPin = 8
	setint interruptPin,interruptPin	;Interrupt only on current expected pin
	hi2cout 0, ($80)	;set data address to beginning of line 1
	BINTOASCII count1, tenThousands, thousands, hundreds, tens, ones
	hi2cout $40, (tenThousands, thousands, hundreds, %00101110, tens, ones,32,32,32,32,32,32,32,32,32,32);clear 1st line
else if interruptPin = 8 then
	count2 = counter
	interruptPin = 4
	setint interruptPin,interruptPin	;Interrupt only on current expected pin
	hi2cout 0, ($88)	;set data address to middle of line 1
	BINTOASCII count2, tenThousands, thousands, hundreds, tens, ones
	hi2cout $40, (tenThousands, thousands, hundreds, %00101110, tens, ones,32,32)
else if interruptPin = 4 then
	count3 = counter
	interruptPin = 2
	setint interruptPin,interruptPin	;Interrupt only on current expected pin
	hi2cout 0, ($C0)	;set data address to beginning of line 2
	BINTOASCII count3, tenThousands, thousands, hundreds, tens, ones
	hi2cout $40, (tenThousands, thousands, hundreds, %00101110, tens, ones)
else if interruptPin = 2 then
	count4 = counter
	interruptPin = 32	;allow hitting the original to reset
	hi2cout 0, ($C8)	;set data address to middle of line 2
	BINTOASCII count4, tenThousands, thousands, hundreds, tens, ones
	hi2cout $40, (tenThousands, thousands, hundreds, %00101110, tens, ones)
endif

return