; ***************************************************************************** ; LCD Dual Channel Audio/Ultrasonic Frequency Meter - 0-100kHz ; Based on PICAXE 20X2, running at 16 & 32MHz ; By Brett Cupitt ; October/November 2010: ; DESCRIPTION: Auto-range first, high freqs, & stepping down. Two reads ; done at optimal range. Then frequency counts averaged and freq calculated. ; Then go to other section and repeat. Top section (MOD = modulator) always ' displayed on top LCD line, while 2nd freq =OR= switch settings shown on 2nd. ; ***************************************************************************** 'Revs: '0.2 - 0.9 - initial build; irrelevant now '1.0 - Build outline of auto-ranging '1.1 - add m64 checking '1.2 - HiRange basically working inc syntax; discard m64 use in favour of m32 '1.3 - Completion of MOD s/w and full function & accuracy testing '1.4 - Add lower section (basically top section with pin changes and switch sensing '1.5 - Tarting up minor stuff; cosmetics; switch detect; LED support, tidy comments '1.6 - Final full testing of minor input circuit changes, all functs and in various ' combinations at various frequencies. Stable & well within stated tolerances. '1.6b - Found a test in sect 2 missing, though unlikely to ever be used. Initialise: pause 700 'little caps charge, settle states, etc serout b.7,n2400,(254,1," Initialising") pause 30 'display time serout b.7,n2400,(254,192," V1.6b 20X2 ") pause 1000 'let electronics & LCD settle 'NOTE: Sometimes comments overflow on to a 2nd line, especially when the line is 'obvious in nature. Some comments are sentences over 2+ lines. 'The T and L are the count identifiers, T=Top (modulator), L=Lower (main). Once a 'COUNT been done it calls the other sect; hence updated alternately. If you think 'the process could be used once for each section, there are so many changes needed, 'ie; input pin choice, display output, sw test, etc, it is harder than simply 're-using tested and working code. This was tried initially and miles more complex 'AND ended up running slower due to so many IF...THEN tests. CountingT: 'Count at M16 used until M32 counts seen as 'similar accuracy but made huge display diff. Let b50=1 'B50 tells OutOfRange where error came from. pulsout b.6,3000 'Led shows range sel. Can be omitted for spd & 'this line del. Use bi-col 3 leg led; (mine grn) setfreq m32 'These 6 lines are for software to count c.1,800,w4 'get feeling for frequency; @8MHz 50=1mS if w4=0 then CountingL: '0 measure so skip sect, goto other range if w4<100 then VLowT: 'go to 0-1kHz range if w4>99 and w4<3080 then LowCountT:'go to 1kHz - 30kHz range if w4>=3080 and w4<10500 then MidCountT: 'go to 30kHz - 130+kHz range if w4>=10600 then OutOfRange: 'h/w + s/w not designed for more than this 'range. Can work much higher with some mods. 'NOTE I use grn led here: and ref'd in text MidcountT: setfreq m32 'This range tends to under-read. The amount count c.1,800,w1 'of error fluctuates so cannot easily be pause 100 'programmed out. Usually about 1.2-1.9% low. count c.1,800,w2 'The 1st 5 steps take 2 sample counts at 32Mhz pause 100 '(5uS window). Must be short so Word does not 'overflow. 800 chosen also for direct readout setfreq m16 'as conversions can introduce errors and Word let w4=w1+w2 'size checking needed. 2 samples averaged to W4 let w4=w4/2 let w0=w4/100 'Our sample is 100th, not 1000th this time. let w5=w4//10 'Get a deminal place. serout b.7,n1200,(254,128,"MOD = ") 'Remove any gunk thats built up at EOL pause 15 'and try to reduce display flashing ;debug w2 'In case you want to experiment serout b.7,n1200,(254,134,#w0,".",#w5," kHz ")' Display it. Spaces after 'kHz' are to pause 30 'overwrite any pre-existing crap in this space goto CountingL: 'Start all over again LowCountT: 'Due to 65535 limit, 30kHz is cutoff for here 'Normal count routines follow setfreq m32 'Due to difficulty in rounding, small error count c.1,800,w1 'can creep in at 1st dec place. pause 100 'These lines measure 2 sample freqs with no count c.1,800,w2 'need for division or other conversion. Freq pause 100 'can be read staight from DEBUG let w1=w1*10 let w2=w2*10 setfreq m16 'Return to known freq let w4=w1+w2 'These lines add the two samples and average let w4=w4/2 'them. The 100 wait (above) could be longer 'for more accuracy, but slow down the process. serout b.7,n1200,(254,128,"MOD = ") 'Rem any gunk thats built up at EOL pause 10 'and wait... let w0=w4/1000 'W4 is the freq. These lines are here to let w6=w4//1000 'format it, adding dec place and removing the let w5=w6/100 'last digit which is a distraction in several serout b.7,n1200,(254,134,#w0,".",#w5," kHz ") 'ways. Displayed here with pause pause 30 'while loop starts again from beginning (how goto CountingL: 'else could a coarse change be detected?). 'This range can be very accurate but slows the display speed down CONSIDERABLY! The 'original lines of code remain & may be re-instated, but the speed penalty is real! 'Even as-is it is noticably slower than MidCount:, etc. To re-use, rem 4 apostrophes '& delete the line "let w0=w1". My preference was speed, but some may not agree. Use 'DEBUG and a DFM to experiment before committing to any change. VLowT: 'Sub 1kHz - the XR2206 covers this range well setfreq m16 'and the 0.1u, 1u & 10uF work mostly here, So it count c.1,4000,w1 'is fitting that attention be paid to the freq ;pause 100 'display. It is accurate in this range to +/- 3Hz ;count c.1,4000,w2 'worst case (against a quality DFM). pause 100 'Be aware display may take 1-2 secs to update. ;let w4=w1+w2 'See explanation above - it is the same here, ;let w0=w4/2 'just another range. ;debug w1 let w0=w1 serout b.7,n1200,(254,128,"MOD = ",#w0," Hz ") 'Small format difference for this pause 30 'range - no 'kHz' or dec place. goto CountingL: 'Yes, it works over 100kHz to an unknown freq but components and s/w rated & tested 'for 100kHz. This is an audio/ultrasonic (100kHz) project and higher freq's need a 'better s/w design conceptually. Where do you think HighCount: routine is? It works 'to 380kHz but has high error rate over this. More/longer samples req, slowing display. OutOfRange: 'Where b50 variable is used; plus for expansion. setfreq m16 'Set known frequency if b50=1 then OORT: 'Tells routine that msg came from CountLow range serout b.7,n1200,(254,192," Range >100 kHz ") 'and it is CountingT:'s turn next pause 60 'Be daring, have a guess goto CountingT: 'It is Modulator section's turn OORT: 'Routine for errors from modulator section, ie Top serout b.7,n1200,(254,192," Range >100 kHz ")'Low range gets next turn. pause 60 'Pause a bit so msg readable without excess slowing goto CountingL: 'Came from CountHi, so now it is CountLo's turn ;SLOT 1 'It may be assumed the top and lower sections are the same except for pin numbers and 'display commands. Only partly so. Top line 'MOD' is always the modulator frequency as 'if you are using AM/FSK, this is always relevant. With only a 2 line display, the 'second line is used to display switch settings - the FSK and AM switches, and their 'waveform association. Also, the XR2206 does not allow a tap-off to determine the freq 'the lower section uses - you will need a scope (which you would be using one any way). CountingL: readadc b.1, b47 'Read FSK Switch Off or On readadc b.2, b46 'Read AM switch Off or On ;debug b46 'Section detects positions of AM/FSK switches, setfreq m16 'Set to known frequency If b46>155 and b46<200 and b47>200 and b47<235 then AMFSKmsg: 'Botht AM/FSK modes selected If b46>155 and b46<200 and b47>250 then AMmsg: 'AM modulation selected - b46, pin 16 If b47>200 and b47<235 and b46>250 then FSKmsg: 'FSK modulation selected - b47, pin 17 if b46>250 and b47>250 then CStart: 'proceed to counting sectiopn goto CountingT: 'If something goes wrong, don't get hung up 'single b# not used - value varies as bat's-p/s drop AMmsg: 'AM enabled, mode OK serout b.7,n1200,(254,192," AM Mode ON ") pause 80 goto CountingT: FSKmsg: 'FSK enabled, mode OK serout b.7,n1200,(254,192," FSK Mode ON ") pause 80 goto CountingT: AMFSKmsg: 'AM & FSK selected, maybe invalid, so msg serout b.7,n1200,(254,128,"AM & FSK mode ON") 'warning of this. The waveform is quite odd pause 30 '& two patterns seem to overlay each other serout b.7,n1200,(254,192,"Odd - you sure? ") 'Difficult to trigger scope. Msg warns user pause 80 'to check its intended. You also lose freq goto CountingT: 'disp; else this would be nec at end of each sect. . CStart: 'START OF Main Function Section: selection & measurement let b50=0 'B50 = Tell OutOfRange routine where it occured pulsout b.5,3000 'Visual indication we are here (bi-col led - red in txt) setfreq m32 'set 32MHz and do initial count so we can count c.2,800,w4 'get feeling for frequency; @8MHz 50=1mS if w4=0 then CountingT: 'Don't waste time in here, go to top if w4<100 then VLowL: 'goto 0-1kHz range. No w4=0 test here for AM/FSK test. if w4>99 and w4<3080 then LowCountL:'go to 1kHz - 30kHz range if w4>=3080 and w4<13000 then MidCountL: 'go to 30kHz - 140kHz range if w4>=13000 then OutOfRange: 'h/w + s/w never designed for this range 'It can work much higher with some mods. MidcountL: setfreq m32 'This range tends to under-read. The amount count c.2,800,w1 'of error fluctuates so cannot easily be pause 100 'programmed out. Usually about 1.2-1.9% low. count c.2,800,w2 'These 5 steps take 2 sample counts at 32Mhz pause 100 '(5uS window). Must be short so Word does not 'overflow. 800 chosen also for direct readout setfreq m16 'as conversions can introduce errors and Word let w4=w1+w2 'size checking needed. These 4 steps take 2 let w4=w4/2 'samples and average them into w4. ;debug w2 let w0=w4/100 'Our sample is 100th, not 1000th this time. let w5=w4//10 'Get a deminal place. serout b.7,n1200,(254,192,"Main= ") 'Remove any gunk accumulated here pause 10 serout b.7,n1200,(254,198,#w0,".",#w5," kHz ")' Display it. Spaces are to pause 30 'overwrite any pre-existing message in this space goto CountingT: 'Start all over again LowCountL: 'Due to 65535 limit, 30kHz is cutoff for here ;debug w0 'Normal count routines follow setfreq m32 'Due to difficulty in rounding, small error count c.2,800,w1 'can creep in at 1st dec place. pause 100 'These lines measure 2 sample freqs with no count c.2,800,w2 'need for division or other conversion. Freq pause 100 'can be read staight from DEBUG let w1=w1*10 let w2=w2*10 setfreq m16 'Return to known freq let w4=w1+w2 'These lines add the two samples and average let w4=w4/2 'them. The 100 wait (above) could be longer ;debug w2 'for more accuracy, but slow down the process. serout b.7,n1200,(254,192,"Main= ") 'Remove any gunk thats built up here pause 10 'and wait... let w0=w4/1000 'W4 is the freq. These lines are here to let w6=w4//1000 'format it, adding dec place and removing the let w5=w6/100 'last digit which is a distraction in several serout b.7,n1200,(254,198,#w0,".",#w5," kHz ") 'ways. Displayed here with pause pause 30 'while loop starts again from beginning (how goto CountingT: 'else could a coarse change be detected?). 'This rane can be very accurate but slows the display speed down CONSIDERABLY! The 'original lines of code remain & may be re-instated, but the speed penalty is real! 'Even as-is its noticably slower than MidCount:, etc. To re-use, remove 4 apostrophes '& delete the line "let w0=w1". My preference was speed, but some may not agree. Use 'DEBUG and a DFM to experiment before committing to any change. VLowL: 'Sub 1kHz - the XR2206 covers this range well setfreq m16 'and the 0.1u, 1u & 10uF work mostly here, So it count c.2,4000,w1 'is fitting that attention be paid to the freq ;pause 100 'display. It is accurate in this range to +/- 3Hz ;count c.1,4000,w2 'worst case (against a quality DFM). pause 100 'Be aware display may take 1-2 secs to update. ;let w4=w1+w2 'See explanation above - it is the same here, ;let w0=w4/2 'just another range. ;debug w1 let w0=w1 serout b.7,n1200,(254,192,"Main= ",#w0," Hz ") 'Small format dif for this pause 30 'range - no 'kHz' or dec place. goto CountingT: ;End of program; Copyright Brett Cupitt NSW, November 2010