|
DAN131
Build a Frequency
Counter
By Michael
Simpson
Updated on 01/28/2005
I have built a few frequency counters in
the past but decided to do one based on the Dios. In this
application note we will be concertinaing on the software. I will
present 3 different programs each one will show you a different way of
building a frequency counter.
Counter 1
Here we will use Dios only code to set up
timer0 to give us a 1 second interval count. We will count the
number of cycles during that interval.
The input will be placed on IOport 15.
For the output we will just display the count in the debug window.
One advantage of this type counter is the
input can be placed on any of the IOports because its primarily software
based.
Download
it here
'=======================================================
'Demonstrate a simple Software Frequency Counter
' Uses timer0 as a 1 second timer
'=======================================================
func main()
dim fcount
again:
fcount = countpulses()
print fcount,"Hz"
goto again
endfunc
'======================================================
'Count the cycles
'======================================================
func countpulses()
dim fcount
clear fcount
'----------------------------------------------------
'First thing setup timer 0
'----------------------------------------------------
INTCON.bit(2)=0 'clear timer0 overflow flag
T0CON.bit(7)=0 'Make sure its off
TMR0H=103 '1 second (you must always write high byte first
TMR0L=150
T0CON.bit(6)=0 '16 bit mode
T0CON.bit(5)=0 'Internal clock
T0CON.bit(3)=0 'Assign prescale
T0CON.bit(2)=1 'Prescale Each Tic = 25.6us
T0CON.bit(1)=1 'Prescale
T0CON.bit(0)=1 'Prescale
T0CON.bit(7)=1 'Start Timer
loop1:
if INTCON.bit(2) = 1 then exit fcount
if IOPORT(15) = 0 then goto loop1
loop2:
if INTCON.bit(2) = 1 then exit fcount
if IOPORT(15) = 1 then goto loop2
inc fcount
goto loop1
endfunc
There is 1 fundamental problem with this
type counter. Even with the speed of the Dios Its only good
for up to 6000hz. If you know you are only be measuring low
frequency values then this may be all you need.
Counter 2
We will do pretty much the same thing as
counter 1 except the time critical sections will be done with inline
assembly. I decided to use a floating point variable to hold the
final result because Im using 24 bytes as the counter here.
The input will be placed on IOport 15.
For the output we will just display the count in the debug window.
Just like the previous example the input
can be placed on any of the IOports because its primarily software based.
Download it here
'=======================================================
'Demonstrate a simple Software Frequency Counter
' Uses timer0 as a 1 second timer
'=======================================================
func main()
gconst freqin 15
dim bnum as float
dim inum as integer
again:
countpulses()
inum = BYTE1 * 256 + BYTE0
bnum = BYTE2 *65535 + inum
print bnum
goto again
endfunc
'===============================================
'Go get a reading
'===============================================
func countpulses()
'Clear counters
BYTE0=0
BYTE1=0
BYTE2=0
'----------------------------------------------------
'First thing setup timer 0
'----------------------------------------------------
INTCON.bit(2)=0 'clear timer0 overflow flag
T0CON.bit(7)=0 'Make sure its off
TMR0H=103 '1 second (you must always write high byte first)
TMR0L=150
T0CON.bit(6)=0 '16 bit mode
T0CON.bit(5)=0 'Internal clock
T0CON.bit(3)=0 'Assign prescale
T0CON.bit(2)=1 'Prescale Each Tic = 25.6us
T0CON.bit(1)=1 'Prescale
T0CON.bit(0)=1 'Prescale
'-----------------------------------------
'Inline assembly section
'-----------------------------------------
startasm
bsf T0CON,7 'Start timer0
'Look for 1
loop1:
btfsc INTCON,TMR0IF
goto alldone
if inp.freqin = 0 then
goto loop1
endif
'look for 0
loop2
btfsc INTCON,TMR0IF
goto alldone
if inp.freqin = 1 then
goto loop2
endif
incf BYTE0,f
btfss STATUS,Z
goto loop1
incf BYTE1,f
btfss STATUS,Z
goto loop1
incf BYTE2,f
goto loop1
alldone
clrf T0CON 'Stop timer
bcf INTCON,TMR0IF 'Clear flag
endasm
'------------------------------------------
endfunc
Ok what's wrong with this program.
Well for one thing it is only good for readings up to 100,000 Hz.
The other problem is that its got just a little too much assembly code.
Counter 3
In this example we are going to put a
little more emphases on some of the internal capabilities of the Dios and
simplify the assembly to just 5 instructions.
We are still going to use timer0 as out
interval timer (gate). But instead of counting the incoming pulses
our self we will let the Dios hardware do it.
Most of the internal timers can be used as
counters. In this case we are going to use timer1 as a counter to
count the pin transitions.
This simplifies the time critical
instructions needed. One disadvantage is that the input must be
placed on IOport 15.
One feature I have added to this program is
the ability to change the gate interval. This will allow us to
extend the range of the counter as the cost of resolution.
Resolution
Download it here
'================================================
'Multi Gate Frequency Counter
'================================================
' Uses hardware timer 0 as gate timer
' hardware timer 1 as counter
' Frequency input on pin 15
func main()
global gate
gate = 1
again:
countpulses()
goto again
endfunc
'===============================================
'Go get a reading
'===============================================
func countpulses()
dim fcount
again:
pause 10
clearcounter
setgate(gate)
'Turn on gate timer and start counter
'-----------------------------------------
startasm
bsf T0CON,7 'Turn on timer0 Gate
bsf T1CON,0 'Start counter
loop:
btfss INTCON,TMR0IF
goto loop
'If we make it here then we have count
bcf T1CON,0 'Stop counter
endasm
'------------------------------------------
if PIR1.bit(0)=1 then
print "Overflow"
gate = gate + 1
goto again
endif
fcount = TMR1L
fcount = TMR1H * 256 + TMR1L
if fcount < 6000 and gate > 1 then
gate = gate -1
goto again
endif
displaycount(gate,fcount)
endfunc
'=================================================
'Display the counter results
'=================================================
func displaycount(tgate,fcount)
dim v10000,v1000,v100,v10,v1
bintodec fcount,v10000,v1000,v100,v10,v1
branch tgate,do1,do1,do2,do3
do1:
print tgate,": ",v10000,v1000,",",v100,v10,v1,"Hz"
exit 0
do2:
print tgate,": ",v10000,v1000,v100,".",v10,v1,"KHz"
exit 0
do3:
print tgate,": ",v10000,v1000,v100,v10,".",v1,"KHz"
exit 0
endfunc
'=================================================
'Sets the gate time
'0 or 1 is 1 second gate
'2 .1 second gate
'3 .01 gate
'=================================================
func setgate(tgate)
INTCON.bit(2)=0 'clear overflow flag TMR0IF
T0CON.bit(7)=0 'Turn it off
T0CON.bit(6)=0 '16 bit mode
T0CON.bit(5)=0 'Internal clock
T0CON.bit(3)=0 'Assign prescale
branch tgate,do1,do1,do2,do3
'1 second gate
do1:
TMR0H=102 '1 second
TMR0L=215
T0CON.bit(2)=1 'Prescale Each Tic = 25.6us
T0CON.bit(1)=1 'Prescale
T0CON.bit(0)=1 'Prescale
exit 0
'.1 seconds gate
do2:
TMR0H=240 '.1 second
TMR0L=175
T0CON.bit(2)=1 'Prescale Each Tic = 25.6us
T0CON.bit(1)=1 'Prescale
T0CON.bit(0)=1 'Prescale
exit 0
'.01 seconds gate
do3:
TMR0H =59 '.01 second
TMR0L = 244
T0CON.bit(2)=0 'Prescale Each Tic = .2us
T0CON.bit(1)=0 'Prescale
T0CON.bit(0)=0 'Prescale
exit 0
endfunc
'=================================================
'This function clears the 16bit hardware counter
' and preps it for next gate
'=================================================
func clearcounter()
T1CON.bit(0)=0 'Turn it off
PIR1.bit(0)=0 'clear counter overflow TMR1IF
TMR1H=0
TMR1L=0
T1CON.bit(7)= 1 '16 bit operation
T1CON.bit(5)=0 'Prescale
T1CON.bit(4)=0 'Prescale
T1CON.bit(3)=0 'No Oscillator
T1CON.bit(2)=1 'Ignored
T1CON.bit(1)=1 'External
endfunc
As you can see this example is a bit more
complicated. Most of the code is devoted to the automatic gate
interval selection. If you want to do that manually you could
remove about 50% of the code.
I have only tested this counter up to 6Mhz.
Also I will be updating this application note in the future to improve the
accuracy by tweaking the timer interval values.
Update: I used a HP 53131
to calibrate the gate timers. Now its one accurate
program!!!!
Since I do most of my testing with digital
devices. I did not add and kind of amplifier or signal conditioner
to the input.
If you want to make a actual meter all you
need do now is include the LCD library and create your own digital
frequency counter. Just add a couple LCD display commands in the
place of the print commands in the displaycount function.
Later I will be taking several of these
application notes to create a whole new project called the ultimate
utility meter.
Parts
list
DiosPro 40 Pin Chip
Dios Workboard
Deluxe
Easy RS232 Driver
DiosPro 28 Pin Chip
Dios 32 Pin Carrier
(Carrier #1)
9 Pin Cable
Breadboard Regulator
|