Wednesday 9 May 2018

Pulse rate detector using MSP430 - Software/Code

I have uploaded a series of videos on youtube on how to execute this project on my channel:
Youtube Channel
Pulse rate detector video
Please subscribe to my channel, if you found the project helpful. I'll be encouraged to do more projects with your support, do like/comment/subscribe and please find below the source code for the project:

MAIN.c


#include <msp430.h>
#include "lcd"
void delay(int);
void configWDT();
void configIO();
void configIR();
void configT();
void disableT();
void int_char();

int i=0;
int j=0;
char str[4];

int main(void)
{

configWDT();

configIO();

configIR();

InitializeLcm();

ClearLcmScreen();

PrintStr("Place finger tip");
LcmSetCursorPosition(2,0);
PrintStr("on the sensor");

while(1)
  {
  delay(10);
  //P1OUT |= BIT6;
  }

}

void configWDT()
  {
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  }

void configIO()
{
P1OUT=0x00;

P1DIR |= (BIT0 + BIT6); // P1.0 output
}

void configIR()
{
  P1REN |= BIT3; // P2 Enable Pullup/Pulldown
  P1OUT |= BIT3; // P2 pullup
  P1IE |= BIT3; // P2 interrupt enabled
  P1IES |= BIT3; // P2 Hi/lo falling edge
  P1IFG &= ~(BIT3); // P2 IFG cleared just in case
  _EINT();
}

void enablePulseIR()
{
  P2REN |= BIT1; // P2 Enable Pullup/Pulldown
  P2OUT |= BIT1; // P2 pullup
  P2IE |= BIT1; // P2 interrupt enabled
  P2IES |= BIT1; // P2 Hi/lo falling edge
  P2IFG &= ~(BIT1); // P2 IFG cleared just in case
//   _EINT();

}

void disablePulseIR()
{
  P2REN &= ~BIT1; // P2 Enable Pullup/Pulldown
  P2OUT &= ~BIT1; // P2 pullup
  P2IE &= ~BIT1; // P2 interrupt enabled
  P2IES &= ~BIT1; // P2 Hi/lo falling edge
  P2IFG |= (BIT1); // P2 IFG cleared just in case

}

void configT()
{
CCTL0 = CCIE;                             // CCR0 interrupt enabled
CCR0 = 50000;
TACTL = TASSEL_2 + MC_1;                  // SMCLK, upmode
}

void disableT()
{
  TACTL = 0X00;
}

void delay(int a)
{
    for(;a>0;a++)
    _delay_cycles(7);
}

void printResult()
{
int_char();
ClearLcmScreen();
PrintStr("Pulse Rate/min =");
LcmSetCursorPosition(2,0);
PrintStr(str);
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
if(i<350) i++;
else
{
P1OUT &= (~BIT0);                            // Toggle P1.0
disableT();
configIR();
disablePulseIR();
j=j*4;
printResult();
i=0;
j=0;
}
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
if((P1IFG & 0x08) == 0x08)
{
P1OUT |= BIT0;
configT();
enablePulseIR();
P1IFG &= ~BIT3;
ClearLcmScreen();
PrintStr("Please wait :");

}
}
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
P2IE &= ~BIT1;
j++;
P2IE |= BIT1;
P2IFG &= ~BIT1;
}

void int_char()
{
int s;
s=j%10;
str[2]=(char)(s+48);
j=j/10;
s=j%10;
str[1]=(char)(s+48);
j=j/10;
s=j%10;
str[0]=(char)(s+48);
str[3]='\0';
}


lcd.h


//
// MSP430 LCD Code
//
#define LCM_DIR P1DIR
#define LCM_OUT P1OUT

//
// Define symbolic LCM - MCU pin mappings
// We've set DATA PIN TO 4,5,6,7 for easy translation
//
#define LCM_PIN_RS BIT1 // P1.1
#define LCM_PIN_EN BIT2 // P1.2
#define LCM_PIN_D7 BIT7 // P1.7
#define LCM_PIN_D6 BIT6 // P1.6
#define LCM_PIN_D5 BIT5 // P1.5
#define LCM_PIN_D4 BIT4 // P1.4

#define LCM_PIN_MASK ((LCM_PIN_RS | LCM_PIN_EN | LCM_PIN_D7 | LCM_PIN_D6 | LCM_PIN_D5 | LCM_PIN_D4))

#define FALSE 0
#define TRUE 1

//
// Routine Desc:
//
// This is the function that must be called
// whenever the LCM needs to be told to
// scan it's data bus.
//
// Parameters:
//
// void.
//
// Return
//
// void.
//
void PulseLcm()
{
    //
    // pull EN bit low
    //
    LCM_OUT &= ~LCM_PIN_EN;

    __delay_cycles(200);

    //
    // pull EN bit high
    //
    LCM_OUT |= LCM_PIN_EN;
    __delay_cycles(200);

    //
    // pull EN bit low again
    //
    LCM_OUT &= (~LCM_PIN_EN);
    __delay_cycles(200);
}

//
// Routine Desc:
//
// Send a byte on the data bus in the 4 bit mode
// This requires sending the data in two chunks.
// The high nibble first and then the low nible
//
// Parameters:
//
// ByteToSend - the single byte to send
//
// IsData - set to TRUE if the byte is character data
// FALSE if its a command
//
// Return
//
// void.
//
void SendByte(char ByteToSend, int IsData)
{
    //
    // clear out all pins
    //
    LCM_OUT &= (~LCM_PIN_MASK);

    //
    // set High Nibble (HN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT |= (ByteToSend & 0xF0);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }
    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();

    //
    // set Low Nibble (LN) -
    // usefulness of the identity mapping
    // apparent here. We can set the
    // DB7 - DB4 just by setting P1.7 - P1.4
    // using a simple assignment
    //
    LCM_OUT &= (~LCM_PIN_MASK);
    LCM_OUT |= ((ByteToSend & 0x0F) << 4);

    if (IsData == TRUE)
    {
        LCM_OUT |= LCM_PIN_RS;
    }
    else
    {
        LCM_OUT &= ~LCM_PIN_RS;
    }

    //
    // we've set up the input voltages to the LCM.
    // Now tell it to read them.
    //
    PulseLcm();
}

//
// Routine Desc:
//
// Set the position of the cursor on the screen
//
// Parameters:
//
// Row - zero based row number
//
// Col - zero based col number
//
// Return
//
// void.
//
void LcmSetCursorPosition(char Row, char Col)
{
    char address;

    //
    // construct address from (Row, Col) pair
    //

    if (Row == 0)
    {
        address = 0;
    }
    else
    {
        address = 0x40;
    }

    address |= Col;
    SendByte(0x80 | address, FALSE);
}

//
// Routine Desc:
//
// Clear the screen data and return the
// cursor to home position
//
// Parameters:
//
// void.
//
// Return
//
// void.
//
void ClearLcmScreen()
{
    //
    // Clear display, return home
    //
    SendByte(0x01, FALSE);
    SendByte(0x02, FALSE);
}

//
// Routine Desc:
//
// Initialize the LCM after power-up.
//
// Note: This routine must not be called twice on the
// LCM. This is not so uncommon when the power
// for the MCU and LCM are separate.
//
// Parameters:
//
// void.
//
// Return
//
// void.
//
void lcd_delay()
{
__delay_cycles(100000);
}

void InitializeLcm(void)
{
    //
    // set the MSP pin configurations
    // and bring them to low
    //
    LCM_DIR |= LCM_PIN_MASK;
    LCM_OUT &= ~(LCM_PIN_MASK);
    //
    // wait for the LCM to warm up and reach
    // active regions. Remember MSPs can power
    // up much faster than the LCM.
    //
   lcd_delay();

    //
    // initialize the LCM module
    //
    // 1. Set 4-bit input
    //
    LCM_OUT &= ~LCM_PIN_RS;
    LCM_OUT &= ~LCM_PIN_EN;

    LCM_OUT = 0x28;
    PulseLcm();
//SendByte(0x33, FALSE);
//SendByte(0x32, FALSE);
    //
    // set 4-bit input - second time.
    // (as reqd by the spec.)
    //
    SendByte(0x28, FALSE);

    //
    // 2. Display on, cursor off
    SendByte(0x0c, FALSE);

    //
    // 3. Cursor move auto-increment
    //
    SendByte(0x06, FALSE);
}

//
// Routine Desc
//
// Print a string of characters to the screen
//
// Parameters:
//
// Text - null terminated string of chars
//
// Returns
//
// void.
//
void PrintStr(char *Text)
{
    char *c;
    c = Text;

    while ((c != 0) && (*c != 0))
    {
        SendByte(*c, TRUE);
        c++;
    }
}