Frequency meter with a PICAXE 08M2
From ShawnReevesWiki
For an explanation, see Frequency meter. This program runs on an inexpensive PICAXE 08M2 micro-controller with mere software timing. For better accuracy and precision, switch to a micro-controller with hardware-timer-interrupt, and/or increase oscillator frequency to decrease the time instructions take.
Program listing
;2014 Shawn Reeves ;measures a frequency of switches between .1Hz and 50Hz ;To improve precision, and accuracy, decrease period, ; which will require more careful measurement of instructional overhead. #picaxe 08m2;tell compiler which chip ;UNCOMMENT ONLY ONE OF THE FOLLOWING TO ALLOW DISPLAY METHOD, since Serial and SPI conflict on C.0 ;#define useSerial #define useSPILCD ;Define interruptOnHigh if pin goes high when switch on, else comment out ;#define interruptOnHigh symbol switchPin = C.3 symbol clockPin = C.1;idle low, clock on rise, wait for falling to load next bit. symbol dataPin = C.2;high = on symbol loadDataPin = C.4;high = load shift register to segs. AKA CSB symbol interruptPin = %00001000 ;C.3 symbol interruptValue = %00000000 ;interrupt on low symbol slowbit = bit0 ;track if frequency too low to measure. symbol counter = b2 symbol byteOut = b3 symbol shiftCounter = b4 #ifdef useSPILCD symbol RS = C.0;Note this conflicts with serial out, so one or the other! symbol tenthousands = b8 symbol thousands = b9 symbol hundreds = b10 symbol tens = b11 symbol ones = b12 #endif symbol counts = w7 symbol mHz = w8 symbol period = w9 symbol loopWord = w10 init: pause 100 ;wait 0.1s for LCD to power up #ifdef useSPILCD ;This routine should initialize the Electronic Assembly DOG-ME-081 8 character LCD display ;use symbol command to assign loadDataPin, RS, dataOut, and SCK to out pins ;assign a byte variable to byteOut and shiftCounter initDOG: high loadDataPin low loadDataPin low RS ;The following lines from Electronic Assembly's data sheet, with cursor mode altered. ;One might repeat the following command many times to get the attention of the ST7032 driver byteOut = %00110000 ;Function Set, 1 line, instruction table 0 gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %00110001 ;Function Set, 1 line, instruction table 1 gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %00110001 ;Function Set, 1 line, instruction table 1, repeat request recommended by ST7032 datasheet gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %00011100 ;Bias 1/4, 1 line LCD gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %01010001 ;Booster off, set contrast C5, C4 gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %01101010 ;set voltage follower on, gain 2/7 gosub shiftout_MSBFirst pause 200;recommended by ST7032 datasheet byteOut = %01110100 ;set contrast C3, C2, C1 gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %00001100 ;display on, cursor off, blink cursor position gosub shiftout_MSBFirst pauseus 27;recommended by ST7032 datasheet byteOut = %00000001 ;clear display, home cursor gosub shiftout_MSBFirst pauseus 2 byteOut = %00000110 ;entry from right to left (or opposite?), no scrolling. gosub shiftout_MSBFirst high RS #endif ;useSPILCD setint interruptValue, interruptPin main: ;Breaking 10ms pause into 1ms 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 100 pauseus 990 ;in units of 10µs, so this will count every 10 ms, our least significant digit inc period next loopWord pauseus 800 ;adjust down from 10ms to account for display routine(s) below. inc period if period > 1000 then ;more than ten seconds have passed. slowbit = 1 else slowbit = 0 endif sendData: #ifdef useSerial sertxd (#mHz,"mHz",13,10) #endif #ifdef useSPILCD low RS ;about to issue a command byteOut = 1 ;clear display and go to first position gosub shiftout_MSBFirst high RS ;about to issue data if slowbit = 0 then bintoascii mHz, tenthousands, thousands, hundreds, tens, ones byteOut = tenthousands gosub shiftout_MSBFirst byteOut = thousands gosub shiftout_MSBFirst byteOut = "." gosub shiftout_MSBFirst byteOut = hundreds gosub shiftout_MSBFirst byteOut = tens gosub shiftout_MSBFirst byteOut = ones gosub shiftout_MSBFirst byteOut = "H" gosub shiftout_MSBFirst byteOut = "z" gosub shiftout_MSBFirst else byteOut = "-" gosub shiftout_MSBFirst byteOut = "-" gosub shiftout_MSBFirst endif #endif ;useSPILCD goto main ;This subroutine requires byte variables shiftcounter, byteOut; port.pins dataOut, and SCK ;RS pin should be set high or low before, according to whether a command or data is to be sent. shiftout_MSBFirst: for shiftCounter = 1 to 8 if byteOut > 127 then ;MSb must be 1 high dataPin else low dataPin endif ;data must be set at least 10ns before clock rises. If overclocking, uncomment the following line: ;pauseus 1 pulsout clockPin,1 ;rising clock edge initiates read of data byteOut = byteOut * 2 ;Shift the value so we mask the next bit ;data must remain set at least 150ns after clock rises. pauseus 1 ;wait 10 microseconds. next shiftCounter pause 1 return interrupt: mHz = 50000 / period mHz = mHz * 2 ;fingers crossed period was greater than 1. period = 0 debounce: pauseus 1990 ;debounce period = period + 2 if pin3 = 0 then goto debounce endif setint interruptValue, interruptPin return