/* Copyright (c) 2003 by Rick Moll All rights reserved. */ char PROG_NAME[] = "Handy Board HRM "; char PROG_DATE[] = "29-Jan-2003"; /* Handy Board HRM was created to demonstrate how to interface my HRM receiver circuit to a microcontroller. This code requires the receiver to be connected to the Handy Board's analog port 0. The algorithm used is simplistic, but is sufficient to show how to detect the transmitted heart beat signal and calculate a heart rate. There are, however, some important limitations to the algorithm and the code implementing it. Here are some particular limitations you should be aware of and some experiments you might try to better understand their consequences: 1) Heart beats are detected with a simple fixed trigger level. Consequently, magnetic noise in the environment can cause erroneously high heart rates to be calculated. Try this experiment, hold the HRM receiver up to a computer CRT or even up close to the Handy Board's own LCD. What happens to the displayed heart rate? Try changing the DEAD_TIME parameter in the code, now what heart rate is displayed when you hold the HRM receiver up to the Handy Board LCD? 2) The heart rate is recalculated at each heart beat, so the displayed heart rate can vary considerably with each beat. Try this experiment, watch your heart beat displayed on the Handy Board LCD as you slowly breath in and out. Is there a pattern? Set a commercial HRM wrist style receiver next to the Handy Board, how often is the commercial unit's display being updated -- what algorithm does the commercial unit seem to be using? 3) The magnetic pulses generated by the HRM chest strap transmitters are fairly short, typically around 5 milliseconds. Since the algorithm is implemented in a fairly high level language, the code loop which waits for the next heart beat to be triggered must be carefully crafted to ensure that it runs fast enough and doesn't miss any beats. Try this experiment, add some more code to this loop, say a call to msleep(). What happens? Can you suggest a way to measure the frequency at which this loop runs? Can you suggest a better method for implementing the algorithm? */ /* Algorithm Parameters */ int TRIGGER_LEVEL = 80; long DEAD_TIME = 100L;/* milliseconds */ long MAX_BEAT_WAIT = 5000L;/* milliseconds */ void main() { /* State Variables state: 0 -> no signal detected 1 -> 1 heart beat detected 2 -> 2 or more heart beats detected */ int state; long this_time; long last_time; /* Temporary Variables */ long wait_time; int heart_rate;/* beats/minute */ /* Turn off all system interrupt features, except LCD printfs. */ poke( 0x39, 1 ); /* Flash the program name and date on the LCD. */ printf("%s%s\n", PROG_NAME, PROG_DATE); msleep(3000L); /* Loop forever, waiting for heart beat signals and updating the LCD. */ state = 0; for (;;) { /* Update LCD to display current state. */ if (state > 1) { /* beats/min = (60,000 msecs/min) / (msecs/beat) = (30,000 msecs/min) / ((msecs/beat)/2) */ heart_rate = 30000 / ((int)(this_time-last_time)/2); printf("hr: %d\n", heart_rate); } else if (state > 0) { printf("signal found\n"); } else { printf("no signal\n"); } /* Previous this_time becomes last_time. */ last_time = this_time; /* If we detected a heart beat last time, delay for DEAD_TIME milliseconds so that we don't redetect the same beat. */ if (state > 0) for (;;) { wait_time = mseconds()-last_time; if (wait_time > DEAD_TIME) break; } /* Loop for up to MAX_BEAT_WAIT milliseconds while looking for the next heart beat signal. */ for (;;) { /* If we detect a heart beat, update the state variables to show that we got a beat and break to update LCD. */ if (_raw_analog(0) < TRIGGER_LEVEL) { this_time = mseconds(); if (state < 2) state++; break; } /* If we've waited for MAX_BEAT_WAIT milliseconds, update the state variables to show we no longer detect a signal and break to update LCD. */ wait_time = mseconds()-last_time; if (wait_time > MAX_BEAT_WAIT) { this_time = mseconds(); state = 0; break; } } } }