Updated 24-Nov-2010
Short description:
A heart rate receiver was build in hardware and connected to a PIC microcontroller to be able to display hart reate to a LCD display. The PIC microcontroller is programmed in C to measure the time between heart beats, displays the beats per minute (BPM) and the time (timems) between consequent heart beats. The microcontroller sends the the BPM through a serial communication cable to the PC.
Hardware:
- Polar heart rate transmitter belt
- MikroE EasyPIC5 development board with a PIC16F887 microcontroller and a 2x16 character HD44780 compatible LCD display
- MikroE MicroC Pro compiler for PIC
- Polar RMCM-01 heart rate receiver module
Below: Left: The PCB with the Polar RMCM-01 heart rate receiver and 3V voltage regulator. Right: Polar heart rate transmitter belt
The Polar heart rate module is mounted together with a 3V voltage regulator and is supplied with 5V and GND from the EasyPIC5 development board. The output from the Polar RMCM01 module is connected to Port B pin 7 (RB7) of the development board.
Above is the schematic of the 3V voltage regulator and a Polar heart rate module
The 2x16 character in the development board displays BPM and the beat to beat interval. In this picture my heart rate was very low.
Program code description:
Internally of the PIC16F887 a timer interrupt increases a counter with one every 1ms. This is the base of the time measurement. On every heart beat the RMCM-01 module outputs a short positive pulse on pin RB7 of the PIC16F887. In the program, the RMCM-01 pulse generates a heart beat interrupt. When a heart beat intterupt occurs the value of the counter is the heart beat interval in ms and the counter is set back to 0. The PIC16F887 is running at a 8 Mhz clock. I chose to use timer2 of the PIC16F887 because timer 2 uses a prescaler (/4), a compare value(100) and a postscaler(/5) to generate a interrupt every 1ms. Calculation: 8Mhz*(/4)*(/4)*100*(/5)=1kHz or 1ms.
The code:
/* Project name:
Jaspers heart rate receiver using timer2
* Description:
The code displays heart Beats Per Minute(BPM) and time between heart beats
(ms) on the LCD display and also send it through uart.
* Test configuration:
MCU: PIC16F887
Dev.Board: EasyPIC5
Oscillator: HS, 8 MHz
Ext. Modules: LCD 2x16
Ext. Hardware: Polar RMCM-01 Heart Rate receiver on RB7
SW: mikroC PRO for PIC
* NOTES:
- Turn on LCD backlight switch (SW9.7) on development board. */
// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
volatile unsigned int CNT;
volatile unsigned short DisplayBPMflag = 0;
unsigned short BPM;
unsigned int timems, count;
char txtBPM[6],txtTimems[6] ;
void interrupt(void){
if(INTCON.RBIF){ // check portB interrupt on change
if (PORTB.B7){ // check RB7 on rising edge
CNT = count; // Copy count2 value to CNT
count = 0 ; // reset count2 value
DisplayBPMFlag = 1; // set flag that the BPM can be put to LCD in the main loop
}
INTCON.RBIF = 0; // Clear RB interrupt flag at rising AND at falling edge
}
if(PIR1.TMR2IF){
PIR1.TMR2IF = 0; // clear timer2 interrupt flag
count++; // increase by 1
}
}
void main(){
ANSEL = ANSELH = 0; // ALL set as Digital I/O
TRISB = 0xC0; // Set RB7 and RB6 as input, rest is output
Lcd_Init(); // Start LCD
Lcd_Cmd(_LCD_CLEAR); // Clear LCD
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
Lcd_Out(1,1,"BPM"); // Write text in first row
Lcd_Out(1,9,"Time(ms)"); // Write text in second row
INTCON = 0; // Clear INTCON register
INTCON.PEIE = 1; // Periphereal interrupt enable
INTCON.RBIE = 1; // RB PORT interrupt on change enable
IOCB.IOCB7 = 1; // RB PIN 7 interrupt on change enable
INTCON.RBIF = 0; // Clear RB port interrupt on change flag
T2CON = 0x21; // prescaler 1:4, postscaler 1:5 (osc/4)
PR2 = 100; // count to 100 (this results in an interrupt every 1ms)
PIR1.TMR2IF = 0; // timer2 to PR2 interrupt flag bit p86
T2CON.TMR2ON = 1; // Timer2 ON
PIE1.TMR2IE = 1; // Timer2 interrupt enable
INTCON.GIE = 1; // Global interrupt enable bit
uart1_init(9600); // Initializes serial communication at 9600 bps
while(1){ // program loops around in here
if(displayBPMFlag == 1){
DisplayBPMFlag = 0; // clear displayBPMflag
if(CNT>250&CNT<2000){ // When heart rate is in normal range (30-240BPM)
BPM = 60000/CNT; // calculate BPM
Timems = CNT; } // time(ms)
else{BPM = 0; timems = 0;} // otherwise display 0
ByteToStr(BPM, txtBPM); // convert BPM to string
Lcd_Out(2,1,txtBPM); // display BPM string on LCD
WordToStr(timems, txtTimems); // convert Timems to string
Lcd_Out(2,12,txtTimems); // display Timems string on LCD
uart1_write(BPM); // send BPM through uart
//uart1_write(timems>>8); // send high byte of timems through uart
//uart1_write(timems); // send low byte of timems through uart
}
}
}
Future:
In the future I want to display a heart rate graph on the PC screen. Eventually I would like to make a simple game. The goal is to quickly induce relaxation (or reduce stress) by means of bio-feedback of the heart rate change. Breathing in temporary increases heart rate and breathing out temporary decrease heart rate. Variation of heart rate is called heart rate variability, and is still in research these days. The goal is to maximize the change of heart rate. Therefor I want to display the change in heart rate. Points are scored when the change in heart rate is large and when the time increases. When a certain amount of points are scored (after 5 minutes) you will be very relaxed.