' Frequency counter (0.5 Hz to 40 MHz)
' Counts frequency on P0, sends ASCII to PC at 115200 Baud
' 1.0 Second gate time (gate time will be longer if frequency is < 2 Hz)
' Based very closely on Bean's Freq Counter3.pbas; he deserves credit
' for the good ideas, and I get the blame for the mistakes in porting
' to fastspin BASIC
#ifdef __FASTSPIN__
' real Propeller
sub setphsa(x as uinteger)
phsa = x
end sub
function getphsa() as uinteger
return phsa
end function
'
' sample routine to convert an array to a string
'
function bufToString(b as const ubyte ptr) as string
dim s as string
s = b
return s
end function
'
' PropBASIC compatibility routine
'
sub countera(ctrmode, apin, bpin, freq = 1, phs = 0)
ctra = (ctrmode<<23) or apin or (bpin<<9)
frqa = freq
phsa = phs
end sub
#else
' PC emulation routines
sub setphsa(x as uinteger)
' do nothing
end sub
function getphsa() as uinteger
return 1000
end function
sub countera(ctrmode as uinteger, apin as uinteger, bpin as uinteger, freq as integer, phs as integer)
end sub
#define waitpne(a, b, c)
#define waitpeq(a, b, c)
'
' sample routine to convert an array to a string
'
function bufToString(b as ubyte ptr) as string
dim s as string
s = *cast(zstring ptr, b)
return s
end function
dim shared fakecounter as uinteger
function getcnt() as uinteger
fakecounter = fakecounter + 1
return fakecounter
end function
#endif
const signal = 5 ' pin for input
dim as uinteger cntStart ' "cnt" value at start of measurement
dim as uinteger cntTime ' "cnt" value at start of measurement
dim as uinteger sigCnt ' "cnt" value at start of measurement
dim asciibuf(20) as ubyte
print "Running frequency counter"
#ifdef __FASTSPIN__
direction(signal) = input
#endif
' set up to count positive edges on pin 0
countera 80, signal, 0, 1, 0
#ifdef __FASTSPIN__
var sigmask = 1 << signal
#else
var sigmask = 1 shl signal
#endif
var temp = 0 ' loop counter
var digit = 0 ' current digit
var digitSum = 0 ' for leading zero removal
do
' wait for a signal pulse to synchronize to the system counter
waitpne(sigmask, sigmask, 0)
waitpeq(sigmask, sigmask, 0)
setphsa(0)
cntstart = getcnt() - 4
' count input pulses until 1.0 seconds have elapsed
do
waitpne(sigmask, sigmask, 0)
waitpeq(sigmask, sigmask, 0)
sigCnt = getphsa()
cntTime = getcnt() - cntStart
loop until cntTime > 80000000
cntTime = cntTime - 4 ' to account for sigCnt = phsa instruction
if cntTime <= 160000000 then
' Since cntTime is in 80MHz units, the frequency is sigCnt / (cntTime / 80_000_000) = Hertz
' Rearranged this can be written as (sigCnt * 80_000_000) / cntTime = Hertz
'
' We want the result in milliHertz (1/1000 of a hertz) so we need to use:
' (sigCnt * 80_000_000_000) / cntTime = milliHertz
'
' Okay, now we have a problem, 80_000_000_000 cannot even be represented in 32 bits. Hmmm
' What if we calculate the answer one digit at a time...
'
' The leftmost digit is MegaHertz and that digit can be calculated as:
' (sigCnt * 80) / cntTime = MegaHertz. This we can do easily.
'
' Now the "trick" is how do we get the next digit ?
' We take the remainder from the division, multiply it by 10 and divide again.
' by repeating this process of taking the remainder and multipling by 10 we
' can get as many digits as we need until we run out of precision.
'
digitSum = 0 ' Sum of all digits so far. Used to create replace leading zeros with spaces
sigCnt = sigCnt * 8 ' scale signal count to get MHz digit
for temp = 1 to 14
digit = sigCnt / cntTime
sigCnt = sigCnt MOD cntTime
sigCnt = sigCnt * 10
digitSum = digitSum + digit ' see if non-zero digits have appeared
digit = digit + asc("0") ' convert to ASCII
if temp < 10 and digitSum = 0 then
digit = asc(" ")
endif
asciibuf(temp) = digit
' insert commas if needed
if (temp=2) or (temp=6) then
temp = temp + 1
if (digitSum = 0) then
asciibuf(temp) = asc(" ")
else
asciibuf(temp) = asc(",")
endif
endif
' insert decimal point
if (temp = 10) then
temp = temp+1
asciibuf(temp) = asc(".")
end if
next
asciibuf(15) = asc(" ")
asciibuf(16) = asc("H")
asciibuf(17) = asc("z")
asciibuf(18) = 0
print bufToString(@asciibuf(1))
else
print "Too low (< 0.5 Hz)"
endif
loop