Shop OBEX P1 Docs P2 Docs Learn Events
Sampling a low frequency analog pulse — Parallax Forums

Sampling a low frequency analog pulse

ArchiverArchiver Posts: 46,084
edited 2001-12-13 06:55 in General Discussion
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...

Comments

  • ArchiverArchiver Posts: 46,084
    edited 2001-12-11 14:56
    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
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-12 04:51
    Check Parallax's Basic Stamp Proramming Manual V1.9, under Basic Stamp I
    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]
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-12 19:31
    Hi Chris,

    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
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-13 03:44
    is the language "Stampese" or "Stamplish"?
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-13 06:55
    I timed the following loop on a BS2e with a precision clock
    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
Sign In or Register to comment.