This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430G2553: Pulse Sensor ,I can not read the BPM(beat per minute ) value on the Lcd Display

Part Number: MSP430G2553

I want to take a value of 1ms from the pulse sensor and calculate the BPM according to this value. When I press the BPM value on the screen, I can not read anything. My code is down. Where am I making mistakes. Could you guide me. Thanks.

#include <msp430g2553.h>
#include "lcdLib.h"
#include <stdint.h>
unsigned int ADC_Result = 0x0000;
void adc_init();
void i2s(int i,char *s);
char s[100];
unsigned int BPM=0;      
unsigned int IBI = 600;  
volatile int Signal;
unsigned int Noise =0;
unsigned long sampleCounter=0;
unsigned long lastBeatTime=0;
unsigned int P =512;                
unsigned int T = 512;               
unsigned int thresh = 512;       
unsigned int amp = 100;     
unsigned int Pulse= 0;
unsigned int secondBeat= 0;
unsigned int firstBeat= 1;
unsigned int rate[10];
void timer_init();
//void lcd (void);
volatile int QS=0;
volatile int runningTotal = 0;
void BPM_Hesapla(void);
int main(void) {
	
        WDTCTL  = WDTPW + WDTHOLD;
	DCOCTL  =  CALDCO_1MHZ;
	BCSCTL1 = CALBC1_1MHZ;

 
  P1DIR = 0x40;
  P1SEL = 0x01;
  
  lcdInit();
  adc_init();
  timer_init();
  __bis_SR_register(GIE);
	while (1) {
     
}
}

void adc_init(){ 
     ADC10CTL0 &= ~ENC;
     ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + MSC ;
     ADC10CTL1 = INCH_0 + SHS_0 + ADC10SSEL_0 + ADC10DIV_0 + CONSEQ_2;                 
     ADC10AE0   = BIT0;     
}
void timer_init(){
  TACTL = TASSEL_2 + ID_0 + MC_1 + TAIE ;
  TACCR0  = 1000;
  TACCTL0 = CCIE;
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void timer_interrupt(void){
  
 
  ADC10CTL0 |= ENC + ADC10SC;  // Start Conversion again
  Signal = ADC10MEM;
  sampleCounter += 2;               
  Noise = sampleCounter - lastBeatTime;
   if(Signal < thresh && Noise > (IBI/5)*3){
      if (Signal < T){
          T = Signal;
          }    
   }
    if(Signal > thresh && Signal > P){
          P = Signal;
     }
    
    if (Noise > 250){

if ( (Signal > thresh) && (Pulse == 0) && (Noise > ((IBI/5)*3) )){  
    Pulse = 1;                                 
    P1OUT |= 0x40;
    IBI = sampleCounter - lastBeatTime;
    lastBeatTime = sampleCounter; 
    if(secondBeat){              
      secondBeat = 0;     
      for(int i=0; i<=9; i++){   
        rate[i] = IBI;                      
      }
    }                       
    if(firstBeat){                     
        firstBeat = 0; 
        secondBeat = 1;   
        return;                          
     }
    runningTotal = 0;
    for(int i=0; i<=8; i++){
      rate[i] = rate[i+1]; 
      runningTotal += rate[i];      
    }
    rate[9] = IBI;                   
    runningTotal += rate[9];             
    runningTotal /= 10;             
    BPM = 60000/runningTotal;
    QS = 1;   
    if((BPM>10) && (BPM<140)){
    lcdSetText("BPM: ", 0, 0); 
    i2s(BPM,s);
    lcdSetText(s, 0, 1); 
    
   
    }
    }             

}          
     if (Signal < thresh && Pulse == 1){          
    P1OUT &= ~0x40;
    Pulse = 0;                      
    amp = P - T;                        
    thresh = amp/2 + T;            
    P = thresh;                         
    T = thresh;
  }
    if (Noise > 2500){    
    thresh = 512; 
    P = 512; 
    T = 512; 
    firstBeat = 1;                 
    secondBeat = 0;
    lastBeatTime = sampleCounter;
  }
          
}

void i2s(int i,char *s) // Convert Integer to String
{char sign;short len;char *p;
sign='+';len=0;p=s;
if(i<0){sign='-';i=-i;}
do{*s=(i%10)+'0';s++;len++;i/=10;}while(i!=0);
if(sign=='-'){*s='-';s++;len++;}
for(i=0;i<len/2;i++){p[len]=p[i];p[i]=p[len-1-i];p[len-1-i]=p[len];}
p[len]=0;
}


  • Hi,

    I'm not sure what your setup looks like or what you're referring to when you say "When I press the BPM value on the screen, I can not read anything." This makes trying to debug your uncommented code almost impossible. Can you be more descriptive about what is connected to the MSP430 and direct me to the area of your code where you are having issues?

    Best regards,
    Caleb Overbay
  • How can i check the timer interrupt in the adc result. I want to stop Adc and take the momentary data and process it. But the adc result is constantly changing. I made regulations in the code.

    #include <msp430g2553.h>
    #include "lcdLib.h"
    #include <stdint.h>
    unsigned int ADC_Result = 0x0000;
    void adc_init();
    void i2s(int i,char *s);
    char s[100];
    unsigned int BPM=0; 
    unsigned int IBI = 600; 
    volatile int Signal;
    unsigned int Noise =0;
    unsigned long sampleCounter=0;
    unsigned long lastBeatTime=0;
    unsigned int P =512; 
    unsigned int T = 512; 
    unsigned int thresh = 512; 
    unsigned int amp = 100; 
    unsigned int Pulse= 0;
    unsigned int secondBeat= 0;
    unsigned int firstBeat= 1;
    unsigned int rate[10];
    void timer_init();
    //void lcd (void);
    volatile int QS=0;
    volatile int runningTotal = 0;
    void BPM_Hesapla(void);
    int main(void) {
    
    WDTCTL = WDTPW + WDTHOLD;
    DCOCTL = CALDCO_1MHZ;
    BCSCTL1 = CALBC1_1MHZ;
    
    
    P1DIR = 0x40;
    P1SEL = 0x01;
    
    lcdInit();
    adc_init();
    timer_init();
    __bis_SR_register(GIE);
    while (1) {
    lcdSetText("BPM: ", 0, 0); 
    i2s(BPM,s);
    lcdSetText(s, 0, 1); 
    
    
    }
    }
    
    void adc_init(){ 
    ADC10CTL0 &= ~ENC;
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + MSC;//ADC10IE;
    ADC10CTL1 = INCH_0 + SHS_0 + ADC10SSEL_0 + ADC10DIV_0 + CONSEQ_0; 
    ADC10AE0 = BIT0; 
    }
    void timer_init(){
    CCTL0 = CCIE;
    CCR0 = 1000;
    TACTL = TASSEL_2 + ID_0 + MC_1;
    }
    /*
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void){
    
    
    
    }
    */
    
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void timer_interrupt(void){
    ADC10CTL0 |= ENC + ADC10SC; 
    while (ADC10CTL1 & ADC10BUSY);
    Signal = ADC10MEM;
    sampleCounter += 2; 
    Noise = sampleCounter - lastBeatTime;
    if(Signal < thresh && Noise > (IBI/5)*3){
    if (Signal < T){
    T = Signal;
    } 
    }
    if(Signal > thresh && Signal > P){
    P = Signal;
    } 
    if (Noise > 250){
    if ( (Signal > thresh) && (Pulse == 0) && (Noise > ((IBI/5)*3) )){ 
    Pulse = 1; 
    P1OUT |= 0x40;
    IBI = sampleCounter - lastBeatTime;
    lastBeatTime = sampleCounter; 
    if(secondBeat){ 
    secondBeat = 0; 
    for(int i=0; i<=9; i++){ 
    rate[i] = IBI; 
    }
    } 
    if(firstBeat){ 
    firstBeat = 0; 
    secondBeat = 1; 
    return; 
    }
    runningTotal = 0;
    for(int i=0; i<=8; i++){
    rate[i] = rate[i+1]; 
    runningTotal += rate[i]; 
    }
    rate[9] = IBI; 
    runningTotal += rate[9]; 
    runningTotal /= 10; 
    BPM = 60000/runningTotal;
    QS = 1; 
    }
    
    } 
    if (Signal < thresh && Pulse == 1){ 
    P1OUT &= ~0x40;
    Pulse = 0; 
    amp = P - T; 
    thresh = amp/2 + T; 
    P = thresh; 
    T = thresh;
    }
    if (Noise > 2500){ 
    thresh = 512; 
    P = 512; 
    T = 512; 
    firstBeat = 1; 
    secondBeat = 0;
    lastBeatTime = sampleCounter;
    }
    
    }
    
    void i2s(int i,char *s) // Convert Integer to String
    {char sign;short len;char *p;
    sign='+';len=0;p=s;
    if(i<0){sign='-';i=-i;}
    do{*s=(i%10)+'0';s++;len++;i/=10;}while(i!=0);
    if(sign=='-'){*s='-';s++;len++;}
    for(i=0;i<len/2;i++){p[len]=p[i];p[i]=p[len-1-i];p[len-1-i]=p[len];}
    p[len]=0;
    }

  • There are minor problems with this code. I am using the variable samplecounter to hold the record in time. But I do not make it. Although the maximum BPM value has been set to 240 (Noise> 250 in condition), there are overvalues.
  • Hi,

    Again, I need you to describe the issue in more detail and please comment your code. It's very difficult to understand what you're trying to accomplish.

    I recommend looking into the ADC examples provided in MSP430Ware. The example linked below uses a Timer to trigger an ADC conversion, then the ADC interrupt service routine is used to read the value in ADCMEM:

    http://dev.ti.com/tirex/#/?link=Software%2FMSP430Ware%2FDevices%2FMSP430G2XX%2FMSP430G2553%2FPeripheral%20Examples%2FRegister%20Level%2Fmsp430g2x33_adc10_11.c

    Best regards, 
    Caleb Overbay

  • Hi.First of all thank you very much for your return.

    I want to calculate the time between the two strokes by using the pulse shape there, and calculate the heartbeat time per minute according to this time. https://pulsesensor.com/pages/pulse-sensor-amped-arduino-v1dot1 

    acıklamalı_pulsekodu.txt
    #include <msp430g2553.h>
    #include "lcdLib.h"
    #include <stdint.h>
    unsigned int ADC_Result = 0x0000;
    void adc_init();
    void i2s(int i,char *s);
    char s[100];
    unsigned int BPM=0;       // used to hold the pulse rate
    unsigned int IBI = 600;    // holds the time between beats
    volatile int Signal;       // holds the incoming raw data
    unsigned int Noise =0;     // the expected time for the second after a pulse,The variable Noise will help avoid noise later.
    unsigned long sampleCounter=0; //The sampleCounter variable is what we use to keep track of time
    unsigned long lastBeatTime=0;   
    unsigned int P =512; 
    unsigned int T = 512; 
    unsigned int thresh = 512;  // Threshold value for 10 bit adc
    unsigned int amp = 100; 
    unsigned int Pulse= 0;   // true when pulse wave is high, false when it's low
    
    unsigned int secondBeat= 0;
    unsigned int firstBeat= 1;
    unsigned int rate[10];
    void timer_init();
    //void lcd (void);
    volatile int QS=0;     //becomes true when Msp430 finds a beat.
    volatile int runningTotal = 0;
    void BPM_Hesapla(void);
    int main(void) {
    
    WDTCTL = WDTPW + WDTHOLD;
    DCOCTL = CALDCO_1MHZ;
    BCSCTL1 = CALBC1_1MHZ;
    
    
    P1DIR = 0x40;
    P1SEL = 0x01;
    
    lcdInit();
    adc_init();
    timer_init();
    __bis_SR_register(GIE);
    
    
    while (1) {
    lcdSetText("BPM: ", 0, 0); 
    i2s(BPM,s);
    lcdSetText(s, 0, 1); 
    
    
    }
    }
    //adc configuration
    void adc_init(){ 
    ADC10CTL0 &= ~ENC;
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + MSC;//ADC10IE;
    ADC10CTL1 = INCH_0 + SHS_0 + ADC10SSEL_0 + ADC10DIV_0 + CONSEQ_0; 
    ADC10AE0 = BIT0; 
    }
    //timer configuration
    void timer_init(){
    CCTL0 = CCIE;
    CCR0 = 1000;
    TACTL = TASSEL_2 + ID_0 + MC_1;
    }
    
    #pragma vector=TIMER0_A0_VECTOR
    
    __interrupt void timer_interrupt(void){
    ADC10CTL0 |= ENC + ADC10SC; 
    while (ADC10CTL1 & ADC10BUSY);
    Signal = ADC10MEM;    // adc değerini sinyale atadık
    sampleCounter += 2;    // we increased our time variable by two
    Noise = sampleCounter - lastBeatTime;   
    
    /* This function is called every 2 milliseconds. First thing to do is to take an analog reading of the Pulse Sensor. 
    Next, we increment the variable sampleCounter. The sampleCounter variable is what we use to keep track of time. 
    The variable N will help avoid noise later.
    Next, we keep track of the highest and lowest values of the PPG wave, to get an accurate measure of amplitude.   */
    
    if(Signal < thresh && Noise > (IBI/5)*3)  //
    {
    if (Signal < T){
    T = Signal;
    } 
    }
    if(Signal > thresh && Signal > P){
    P = Signal;
    } 
    /* Variable P and T hold peak and trough values, respectively. 
    The thresh variable is initialized at 512 (middle of analog range) and changes during run time to track a point at 50% of amplitude as we will see later. 
    There is a time period of 3/5 IBI that must pass before T gets updated as a way to avoid noise and false readings from the dicroic notch. 
    Now, lets check and see if we have a pulse. */
    
    if (Noise > 250){
    if ( (Signal > thresh) && (Pulse == 0) && (Noise > ((IBI/5)*3) )){ 
    Pulse = 1; 
    P1OUT |= 0x40;
    IBI = sampleCounter - lastBeatTime;
    lastBeatTime = sampleCounter; 
    /*
    Before we even consider looking for a heart beat, a minimum amount of time has to pass.
     This helps avoid high frequency noise. 250 millisecond minimum N places an upper limit of 240 BPM. 
     If you expect to have a higher BPM, adjust this accordingly and see a doctor. 
     When the waveform rises past the thresh value, and 3/5 of the last IBI has passed, we have a pulse! Time to set the Pulse flag and turn on the pulsePin LED. 
     (note: if you want to do something else with pin 13, comment out this line, and the later one too). 
     Then we calculate the time since the last beat to get IBI, and update the lastBeatTime.
    
    The next bit is used to make sure we begin with a realistic BPM value on startup.   
    */
    if(secondBeat){ 
    secondBeat = 0; 
    for(int i=0; i<=9; i++){ 
    rate[i] = IBI; 
    }
    } 
    if(firstBeat){ 
    firstBeat = 0; 
    secondBeat = 1; 
    return; 
    }
    /*
    The boolean firstBeat is initialized as true and secondBeat is initialized as false on start up, so the very first time we find 
    a beat and get this far in the ISR, we get kicked out by the return; in the firstBeat conditional. That will end up throwing the
     first IBI reading away, cause it's lousy. The second time through, we can trust (more or less) the IBI, and use it to seed the 
     rate[] array in order to start with a more accurate BPM. The BPM is derived from an average of the last 10 IBI values, hence the need to seed.
    Lets calculate BPM!
    */
    
    
    
    runningTotal = 0;
    for(int i=0; i<=8; i++){
    rate[i] = rate[i+1]; 
    runningTotal += rate[i]; 
    }
    rate[9] = IBI; 
    runningTotal += rate[9]; 
    runningTotal /= 10; 
    BPM = 60000/runningTotal;
    QS = 1; 
    }}
    /*
    First, we grab a large variable, runningTotal, to collect the IBIs, then the contents of rate[] are shifted over and added to runnungTotal.
     The oldest IBI (11 beats ago) falls out of position 0, and the fresh IBI gets put into position 9. Then it's a simple process to average 
     the array and calculate BPM. Last thing to do is to set the QS flag (short for Quantified Self, awesome kickstarter supporters!) so the 
     rest of the program knows we have found the beat. That's it for the things to do when we find the beat.
    
    There's a couple of other loose ends that need tying off before we're done, like finding the not-beat.
    */
    
    if (Signal < thresh && Pulse == 1){ 
    P1OUT &= ~0x40;
    Pulse = 0; 
    amp = P - T; 
    thresh = amp/2 + T; 
    P = thresh; 
    T = thresh;
    }
    /*Pulse was declared true during the upward rise in Pulse Sensor signal when we found the beat, above, 
    so when the signal crosses thresh going down, we can figure that the pulse is over. A little housekeeping 
    in clearing pulsePin and the Pulse boolean. Then the amplitude of the wave that just passed is measured,
     and thresh is updated with the new 50% mark. P and T are reset to the new thresh. The algorithm is now primed and ready to find the next beat.
    
    There's one more question to ask before the ISR is done. What if there are no beats?*/
    if (Noise > 2500){ 
    thresh = 512; 
    P = 512; 
    T = 512; 
    firstBeat = 1; 
    secondBeat = 0;
    lastBeatTime = sampleCounter;
    }
    /*If there is no beat event for 2.5 seconds, variables used to find the heartbeat are 
    reinitialized to the start up values. Sort of a soft soft-reset. That's the end of the ISR!*/
    
    }
    
    void i2s(int i,char *s) // Convert Integer to String
    {char sign;short len;char *p;
    sign='+';len=0;p=s;
    if(i<0){sign='-';i=-i;}
    do{*s=(i%10)+'0';s++;len++;i/=10;}while(i!=0);
    if(sign=='-'){*s='-';s++;len++;}
    for(i=0;i<len/2;i++){p[len]=p[i];p[i]=p[len-1-i];p[len-1-i]=p[len];}
    p[len]=0;
    }

    I have uploaded the code above with reference to the site. Thank you so much

    Best regards

  • hi ,

          I am not sure what's your issue is but you can try this approach to achieve your task.

          1>  Analyse the analog output of sensor.

          2>  then using ADC make its digital approximation. for analysis you can send it serially to pc  and can check how good you are getting the digital approximation of sensor signal.

         3>  If you get  correct approximation by which i mean from digital values you can correctly guess you analog signal, the adc part is over you don't have to think about it from now.

         4>   now start a counter of a fix period , and now this time send counter's count along with adc value you were sending in previous step serially to pc.

         5>  now you can calculate timing value manually. if you get the right values what you are expecting ,implement the logic inside controller .DONE.

**Attention** This is a public forum