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++;
    }
}

Sunday 4 February 2018

Stress measurement using Raspberry Pi

Introduction:

The aim of this project is to measure the stress that a subject applies on a stress-ball and categorize it into three possible levels, i.e. high, medium or low, and the same is displayed on the thermometer on the screen.
The FSR-402 (force sensor) is mounted on a stress ball and the analog signal generated by it on the application of pressure is supplied to AD7705 which converts the same into a digital signal and feeds it to raspberry pi where the software classifies the pressure in any of the available 3 different categories and displays the output in the form of a graph and thermometer on the screen.

Set-up/Project in action


Software:

The Raspberry pi gets the digital sensor input on its GPIO pin from AD7705. The communication interface used is SPI with the device at /dev/spidev0.0. The file related to the same is accessed whenever a read/write has to be performed.

After initialization, a new thread is started which reads the ADC output continuously and stores it in a buffer. The window.CPP file reads the value from the adcreader, whenever a sample is present and a timer event will trigger to plot all the data collected during the 20ms refresh rate on the screen.

Code is available on Github: https://github.com/waffles1/stress_measurement

Hardware:

Hardware can be divided into two parts:
1. The Analog-Digital Converter (ADC) Circuit
2      2. Pressure sensor circuit
Analog-Digital Converter required the following components:
1 x MCP1525
1 x 0.1µF
2 x 1 µF
1 x AD7705
The pressure sensor circuit required the following components:
1 x FSR402
2 x 1kΩ
1 x 1MΩ



Implementation of the circuit diagram:
Circuit
The maximum resistance of the FSR is 10MΩ and the minimum is 300Ω (provided in the datasheet). Upon applying pressure on the FSR, the value of the resistance decreases which results in a voltage drop greater than 80mV and less than 1.9V (wheat-stone bridge was used). The 1kΩ resistors provide a voltage drop of 1.5V at Ain-. Using the 1MΩ resistor, the differential input range is 1.49-1.5Vwhich is well within the voltage drop range. The wheat-stone bridge provides a differential input to the AD7705.

Conclusion:

Application of pressure results in a change in the waveform. The thermometer of QT displays the amount of pressure. A full bar means maximum pressure while an empty bar means no pressure. The AD7705 A/D converter was used to change analog to digital values and was displayed on the monitor. Video will be made available soon on my YouTube channel, do subscribe to my channel for video explanations:



Monday 15 January 2018

Controlling an LCD using MSP430 via a shift register 74HC595

Introduction

In this post, we will control an LCD using MSP430G2553 via a shift register, 74HC595.

I have already executed a project on controlling an LCD in 4 bit mode using an MSP430  (Pulse Rate Detector): https://youtu.be/dle8M3QlXc4

Although, 4 bit mode reduces the amount of pins required for operation when compared with 8 bit mode, we can further reduce the number of pins required from MSP430 to 3 by using a shift register!

These three pins are required for ENABLE (LCD ENABLE pin), Data and Clocks respectively.

74HC595

74HC595 is a high speed 8-bit serial in, parallel out shift register consisting of a storage register and 3 state-outputs.

Both the shift and the storage registers have a separate clock (SH_CP, ST_CP). During the positive transition of the SH_CP, data is shifted and the content is transferred to storage register during positive transition of ST_CP (check the datasheet of 74HC595 for detailed explanation and pin diagram).

In this project, both the clocks are tied together to reduce the number of pins, thus, the shift register will always be one clock ahead of the storage register. Thus, if we want to receive a serially transferred 8 bit data, an extra clock pulse should be provided after the transmission of the 8-bit serial data as the storage register lags by a single clock pulse w.r.t the shift register.
The OE pin is active low, hence, it is connected to ground for extracting the parallel output.

Circuit Diagram

The hardware connections are straight-forward. The shift register output is connected to the LCD data lines and RS control pin (Data/Command control). Both the clocks are tied together and controlled via a single port pin of MSP430, one pin is connected to ENABLE of LCD and the third port pin is connected to the DATA pin of the shift register. The R/W pin of LCD is grounded as only write operation is performed for this project.

OE pin of shift register is grounded and MR is pulled to 5Volts, Q0 - Q3 are each connected to D4 - D7 of the LCD, and Q4 is connected to RS.


Circuit Diagram

Software

Comment below your email ID to get access to the Software/Code for this project.

Demonstration

Check the project in action: