Photo-gate timer with a PICAXE 20M2
From ShawnReevesWiki
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