Photo-gate timer with a PICAXE 20M2
From ShawnReevesWiki
Jump to navigationJump to searchProgram 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.
See Photo-gate timer for a full discussion.
;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