Sampling a low frequency analog pulse
Archiver
Posts: 46,084
Chris-
Flexible, precise timing is not one of the Stamp's strong suits. If
you need a lot of accuracy, you'll probably need an external timer,
and several are available for your Stamp.
If you can live with some imprecision, you can use instruction
timing to get pretty close, probably within one or two beats per
minute. Consider the following program:
'{$STAMP BS2}
pulse_pin CON 1 ' or whatever
high_count VAR WORD
low_count VAR WORD
start:
high_count = 0
low_count = 0
' wait for beginning of cycle
awaitStartLow:
BRANCH ~pulse_pin,[noparse][[/noparse]awaitStartLow] ' loop awaiting low pin
awaitStartHigh:
BRANCH pulse_pin,[noparse][[/noparse]awaitStartHigh] ' loop awaiting high pin
' now wait for high pulse and next low pulse to finish
awaitLowPulse:
high_count = high_count + 1 ' takes ~140 usec
BRANCH ~pulse_pin,[noparse][[/noparse]awaitLowPulse] ' takes ~334 usec
awaitHighPulse:
low_count = low_count + 1 ' takes ~140 usec
BRANCH pulse_pin,[noparse][[/noparse]awaitHighPulse] ' takes ~334 usec
' show results
DEBUG DEC 63,300 / ( ( high_count + low_count ) / 2 )
GOTO start
Each iteration through awaitLowPulse or awaitHighPulse takes about
474 usec. The heartbeat period would then be ( high_count +
low_count ) * 474 usec. So we're measuring the period in increments
of roughtly 1/2 msec.
A heartbeat rate of 60 beats per minute (BPM) would correspond to
about high_count + low_count = 2110. 120 BPM would correspond to
about 1055. So we get pretty close by dividing 126,600 by the sum
of high_count and low_count:
126,600 / 2110 = 60
126,600 / 1055 = 120
But 126,000 is too large for the Stamp to deal with, so the
following approximation is used instead:
( 126,660 / 2 ) / ( 2110 / 2 ) = 63,300 / 1055 = 60
This ought to get you pretty close to where I think you want to be.
The group's high-octane mathematicians will hopefully point out the
embarrassing errors and suggest better approaches to the above. Hope
this helps.
Out of curiosity, what device are you using to supply the pulse
stream?
Regards,
Steve
On 11 Dec 01 at 14:56, cbeatson wrote:
> Hi,
>
> I am trying to sample a low frequency pulse, and output the data in
> beats per minute (this is data from a heart rate monitor) on a BS2...
Flexible, precise timing is not one of the Stamp's strong suits. If
you need a lot of accuracy, you'll probably need an external timer,
and several are available for your Stamp.
If you can live with some imprecision, you can use instruction
timing to get pretty close, probably within one or two beats per
minute. Consider the following program:
'{$STAMP BS2}
pulse_pin CON 1 ' or whatever
high_count VAR WORD
low_count VAR WORD
start:
high_count = 0
low_count = 0
' wait for beginning of cycle
awaitStartLow:
BRANCH ~pulse_pin,[noparse][[/noparse]awaitStartLow] ' loop awaiting low pin
awaitStartHigh:
BRANCH pulse_pin,[noparse][[/noparse]awaitStartHigh] ' loop awaiting high pin
' now wait for high pulse and next low pulse to finish
awaitLowPulse:
high_count = high_count + 1 ' takes ~140 usec
BRANCH ~pulse_pin,[noparse][[/noparse]awaitLowPulse] ' takes ~334 usec
awaitHighPulse:
low_count = low_count + 1 ' takes ~140 usec
BRANCH pulse_pin,[noparse][[/noparse]awaitHighPulse] ' takes ~334 usec
' show results
DEBUG DEC 63,300 / ( ( high_count + low_count ) / 2 )
GOTO start
Each iteration through awaitLowPulse or awaitHighPulse takes about
474 usec. The heartbeat period would then be ( high_count +
low_count ) * 474 usec. So we're measuring the period in increments
of roughtly 1/2 msec.
A heartbeat rate of 60 beats per minute (BPM) would correspond to
about high_count + low_count = 2110. 120 BPM would correspond to
about 1055. So we get pretty close by dividing 126,600 by the sum
of high_count and low_count:
126,600 / 2110 = 60
126,600 / 1055 = 120
But 126,000 is too large for the Stamp to deal with, so the
following approximation is used instead:
( 126,660 / 2 ) / ( 2110 / 2 ) = 63,300 / 1055 = 60
This ought to get you pretty close to where I think you want to be.
The group's high-octane mathematicians will hopefully point out the
embarrassing errors and suggest better approaches to the above. Hope
this helps.
Out of curiosity, what device are you using to supply the pulse
stream?
Regards,
Steve
On 11 Dec 01 at 14:56, cbeatson wrote:
> Hi,
>
> I am trying to sample a low frequency pulse, and output the data in
> beats per minute (this is data from a heart rate monitor) on a BS2...
Comments
I am trying to sample a low frequency pulse, and output the data in beats per
minute (this is data from a heart rate monitor) on a BS2.
To calculate frequency, the formula is F = 1/P, but I am having problems
measuring the period. The pulse width is too wide to use pulsin, and I would
like the reading to be as close to real time as possible.
I have tried to sample the state of the pin at various rates using pause to
simulate a timer, but the higher the sampling rate, the less accurate it gets.
I'm assuming that the logic overhead is adding time to the pause cycle and
throwing off the timer.
Is there a good way, that someone knows, to sample low frequency analog pulses
through the BS2?
TIA,
Chris
Application notes. Note #20 "An acurate timebase", page 197. I think this will
be helpful to you.
Do You Yahoo!?
Check out Yahoo! Shopping and Yahoo! Auctionsfor all of your holiday gifts!
[noparse][[/noparse]Non-text portions of this message have been removed]
Here is a routine I use for timing the duration of a long pulse:
' waits for P12 to go LOW
' then runs a counter to see how long it stays low
' has an escape term, about 27 seconds max on BS2
' converts to time in ~1 millisecond resolution
xc var word
timer:
xc=0
timer0: ' wait here until in12 goes LOW
if in12 then timer0
timer1: ' 1228 loops per second, 8.143E-4 seconds per loop
xc=xc+1
branch in12|xc.bit15,[noparse][[/noparse]timer1] ' count until in12 OR xc.bit15 goes HIGH
xc.bit15=0
debug ? xc ** 53368 ' answer in milliseconds (1000/1228 = 53368/65536)
goto timer
The business with xc.bit15 allows the loop to time out even if the
pin never goes back low. The result is zero if the timout occurs.
Pick a different bit if you want a faster timeout. The timout is
about 27 seconds. The 1228 loops per second figure is one I obtained
empirically on one particular Stamp. The **53368 in the debug command
converts to real time milliseconds. Your mileage may vary, but it
should be within a few percent, depending as it does on the accuracy
of the ceramic resonator. More on timing at
http://www.emesystems.com/BS2speed.htm
I have some tutorials on calculating the reciprocal at
http://www.emesystems.com/BS2math2.htm
Here is another way to do the calculation Steve Parkis suggested,
using divide and remainder technique:
result = 126,600 / myCount ---- but 126600 is too big for the
Stamp, so in Stampese:
result = 12660/myCount*10+((12660//myCount*10)/myCount)
works so long as 2<myCount<6554
or for one more decimal place, to 0.2:
result = (63300/myCount*10+((63300//myCount*10)/myCount))*2
works so long as 10<myCount<6554
-- best regards
Tracy Allen
electronically monitored ecosystems
http://www.emesystems.com
mailto:tracy@e...
>Hi,
>
>I am trying to sample a low frequency pulse, and output the data in
>beats per minute (this is data from a heart rate monitor) on a BS2.
>
>To calculate frequency, the formula is F = 1/P, but I am having
>problems measuring the period. The pulse width is too wide to use
>pulsin, and I would like the reading to be as close to real time as
>possible.
>
>I have tried to sample the state of the pin at various rates using
>pause to simulate a timer, but the higher the sampling rate, the
>less accurate it gets. I'm assuming that the logic overhead is
>adding time to the pause cycle and throwing off the timer.
>
>Is there a good way, that someone knows, to sample low frequency
>analog pulses through the BS2?
>
>TIA,
>Chris
generator. Its basic resolution turned out to be 1177 counts per
second, for a timing resolution of better than one millisecond. This
held within the one millisecond tolerance for input frequencies I
tested from 0.5 hz to 100 hz. It has an emergency exit timer is set
at 3.5 seconds (to keep the program from locking up if the P12 gets
stuck), but that can be made as long as 27 seconds with the technique
shown.
' Long pulse timer demo
' Times one entire cycle 01 in train of 01010
' This uses Stamp pin P12
' Program holds in the "wait" loops until a 1->0 transition
' then times the next whole 01 cycle
' The resolution is 1177 counts per second on a BS2e
' (That is empirical result using a precision 1 second source)
' uses counter also as exit to keep loop from locking up
' the result is zero when it times out, just like pulsin.
' using bit 12 gives 3.5 second timeout
' using bit 15 instead would give 27 second timeout.
' http://www.emesystems.com/BS2speed.htm
' Tracy Allen, mailto:tracy@e...
xc var word
top:
xc=0 ' use the counter as emergency exit
wait0: ' wait here while p12 is low
xc=xc+1
branch in12|xc.bit12,[noparse][[/noparse]wait0]
xc.bit12=~xc.bit12 ' flip exit condition
wait1: ' wait here while p12 is high
xc=xc+1
if int12&xc.bit12 then wait1
xc=0 ' will be both timer and emergency exit
timer0: ' time how long p12 is low
xc=xc+1
branch xc.bit12|in12,[noparse][[/noparse]timer0]
xc.bit12=~xc.bit12 flip the exit condition
timer1: ' time how long p12 is high
xc=xc+1 ' continue with the same counter
if xc.bit12&in12 then timer1
doneTiming:
xc=xc*xc.bit12 ' make sure result is zero when timeout occurs
xc.bit12=0 ' timeout bit := zero
debug dec xc,tab,dec xc**55681,cr ' report the result in raw count
' and converted to milliseconds.
' 1000/1177 = 55681/65536
' can do other program tasks here
goto top ' repeat the demo