Shahariar
Published © CC BY-SA

Relaxation Breathing Exercise Tracker

A device to guide and track breathing exercise sessions for post Covid recovery of patient's lung capacity

BeginnerFull instructions provided2 hours852
Relaxation Breathing Exercise Tracker

Things used in this project

Hardware components

EK-TM4C123GXL TM4C Tiva LaunchPad
Texas Instruments EK-TM4C123GXL TM4C Tiva LaunchPad
×1
1.54 Inch E-paper display
×1
Hall Effect Fluid Flow Sensor
×1
Mouth tip
×1
Buzzer
Buzzer
×1
Battery Holder, AA x 3
Battery Holder, AA x 3
×1
AA Batteries
AA Batteries
×1

Software apps and online services

Energia
Texas Instruments Energia

Hand tools and fabrication machines

Tape, Green
Tape, Green
Box, General Purpose
Box, General Purpose
Soldering iron (generic)
Soldering iron (generic)
Hot glue gun (generic)
Hot glue gun (generic)
Premium Female/Female Jumper Wires, 40 x 3" (75mm)
Premium Female/Female Jumper Wires, 40 x 3" (75mm)

Story

Read more

Schematics

Schematic

Code

main.c

C/C++
final
///////////// Header Files ////////////////
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sysctl.h>
#include <eeprom.h>

#include <SPI.h>
#include "epd1in54.h"
#include "epdif.h"
#include "epdpaint.h"
#include "imagedata.h"

int COLORED  = 0; // White in Black on epaper
int UNCOLORED = 1;  // Black in White on epaper
unsigned char image[8120];  // buffer for epaper

// variable array to write and read eeprom
uint32_t romdata_written[2] ;
uint32_t romdata_read[2] ;

// ISR variable for frequency of flow sensor pulses
volatile unsigned long frequency = 0;
volatile unsigned long last_micro = 0;

// variable for number of breaths during exercise
uint32_t breath_counter = 0;
uint32_t net_breaths = 0;

/////////// Enum for epaper//////////////
////// width must be multiple of 8///////
Paint paint(image, 0, 0);  // epaper enum
Epd epd;                   // epaper enum

char VAL[9]; // buffer for int to char conversion

/////////////////////////////////////////////////
////////////// I/O pin mapping //////////////////

//// I/O pins used interfacing paper display ////
// see inside epdif.c , epdif.h files and also //
// check for tiva tm4c123 energia SPI0 pinmap  //

// #define RST_PIN   9  // PA6 (GPIO)
// #define DC_PIN    10 // PA7 (GPIO)
// #define BUSY_PIN  19 // PB2 (GPIO)
// #define MSI_SPI0  8  // PA5 (SPI0)
// #define MIS_SPI0  13 // PA4 (SPI0)
// #define CSL_SPI0  12 // PA3 (SPI0)
// #define CLK_SPI0  11 // PA2 (SPI0)
// note : MISO (PA4) has no actual physical wiring
//  between tm4c123 and epaper, just SPI MISO pin
///////////////////////////////////////////////////
///////////////////////////////////////////////////

//// Input for sensing AIR flow   ////
#define FLOW_METER 31       // PF4

//Tiva on board RGB LED for breath sequence//
#define LED_BLU 40           // PF2 
#define LED_RED 30           // PF1 
#define LED_GRN 39           // PF3 
#define BUZZER 32            // PD7 

///////////////////////////////////////////////
//ISR to measure pulses from air flow sensor //
///////////////////////////////////////////////
void PortFIntHandler()
{
  // clear interrupt
  uint32_t flag = 0;
  flag = GPIOIntStatus(GPIO_PORTE_BASE, true);
  GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
  // measuring frequency // f=1000000/t (t in uSeconds)
  frequency = 1000000.0 / (micros() - last_micro);
  last_micro = micros();
  // time_passed =  last_micro- first_micro ;
}

////////////////////////////////////////////////
////////////////////////////////////////////////

void setup()
{
  // initialize I/O pins //
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_BLU, OUTPUT);
  pinMode(LED_GRN, OUTPUT);
  pinMode(BUZZER,  OUTPUT);

  // wrire I/O pins init states //
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_BLU, LOW);
  digitalWrite(LED_GRN, LOW);
  digitalWrite(BUZZER,  LOW);

  // set PF4 as input pullup //
  pinMode(FLOW_METER, INPUT_PULLUP); // <---- PORT F pin 4, PF4

  // configure for falling edge interrupt
  GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_FALLING_EDGE);

  // associate with ISR function
  GPIOIntRegister(GPIO_PORTF_BASE, PortFIntHandler);

  // enable interrupt to sense AIR flow pulses
  //GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_4);

  // Initialize EEPROM for storing breathing data
  SysCtlPeripheralEnable(SYSCTL_PERIPH_EEPROM0);
  while (!SysCtlPeripheralReady(SYSCTL_PERIPH_EEPROM0))
  {}
  EEPROMInit();
  EEPROMRead(romdata_read, 0x80, sizeof(romdata_read));
  net_breaths = romdata_read[0];

  // clear and init e paper //
  flush_epd();
  init_epd();

 

  // flush_epd();
  // init_epd();
  // show device intro logo //
  // epd.SetFrameMemory(Meno_Logo);
  epd.DisplayFrame();
  delay(1200);

  flush_epd();
  init_epd();

  // enable interrupt to sense AIR flow pulses //
  GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_4);
}

////////////////////////////////////////////////
////////////////////////////////////////////////

void loop()
{
  // all *_epd() and paint.*() -> epaper functions

  // show user instruction on display and LED //
  erase_epd();
  while (frequency == 0)
  {
    digitalWrite(LED_BLU, HIGH);
    delay(100);
    paint.DrawStringAt(8, 26, "TAKE A LONG" , &Font24, COLORED);
    paint.DrawStringAt(8, 60, "DEEP BREATH" , &Font24, COLORED);
    paint.DrawStringAt(5, 133, "Breath Counter:", &Font16, COLORED);
    paint.DrawStringAt(5, 155, "Past Sessions", &Font16, COLORED);
    paint.DrawStringAt(5, 170, "Breath Counts:", &Font16, COLORED);
    paint.DrawStringAt(170, 133, itoa(breath_counter, VAL, 10), &Font16, COLORED);
    paint.DrawStringAt(160, 170, itoa(net_breaths, VAL, 10), &Font16, COLORED);

    epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
    epd.DisplayFrame();
    digitalWrite(LED_BLU, LOW);
    delay(200);

  }
  // wait while breath in
  while (micros() < last_micro + 200000)
  {
    digitalWrite(LED_BLU, HIGH);
  }

  // hold breath

  digitalWrite(LED_BLU, LOW);
  digitalWrite(LED_RED, HIGH);
  erase_epd();
  paint.DrawStringAt(8, 26, " HOLD YOUR " , &Font24, COLORED);
  paint.DrawStringAt(8, 60, "  BREATH ! " , &Font24, COLORED);
  paint.DrawStringAt(5, 133, "Breath Counter:", &Font16, COLORED);
  paint.DrawStringAt(5, 155, "Past Sessions", &Font16, COLORED);
  paint.DrawStringAt(5, 170, "Breath Counts:", &Font16, COLORED);
  paint.DrawStringAt(170, 133, itoa(breath_counter, VAL, 10), &Font16, COLORED);
  paint.DrawStringAt(160, 170, itoa(net_breaths, VAL, 10), &Font16, COLORED);

  epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
  epd.DisplayFrame();


  delay(4000);
  digitalWrite(LED_RED, LOW);
  frequency = 0;

  erase_epd();
  while (frequency == 0)
  {

    digitalWrite(LED_GRN, HIGH);
    delay(100);
    paint.DrawStringAt(8, 26, "BREATH OUT" , &Font24, COLORED);
    paint.DrawStringAt(8, 60, "SLOWLY ..." , &Font24, COLORED);
    paint.DrawStringAt(5, 133, "Breath Counter:", &Font16, COLORED);
    paint.DrawStringAt(5, 155, "Past Sessions", &Font16, COLORED);
    paint.DrawStringAt(5, 170, "Breath Counts:", &Font16, COLORED);
    paint.DrawStringAt(170, 133, itoa(breath_counter, VAL, 10), &Font16, COLORED);
    paint.DrawStringAt(160, 170, itoa(net_breaths, VAL, 10), &Font16, COLORED);

    epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
    epd.DisplayFrame();
    digitalWrite(LED_GRN, LOW);
    delay(200);
  }

  // wait while breath out
  while (micros() < last_micro + 200000)
  {
    digitalWrite(LED_GRN, HIGH);
  }
  digitalWrite(LED_GRN, LOW);
  frequency = 0;
  breath_counter += 1;
  digitalWrite(BUZZER, HIGH);
  delay(150);
  digitalWrite(BUZZER, LOW);




  //******************************************//
  // update eeprom with breath count info //
  // *****************************************//

  EEPROMRead(romdata_read, 0x80, sizeof(romdata_read));

  // update data before writing to eeprom, (first 32 byte area)
  romdata_written[0] =  romdata_read[0] + 1;

  // write/save data to eeprom to 0x80 address with max size 64 bytes (32+32)
  EEPROMProgram(romdata_written, 0x80, sizeof(romdata_written));

  // Read eeprom 0x80 location data for new value
  EEPROMRead(romdata_read, 0x80, sizeof(romdata_read));
  net_breaths = romdata_read[0];

  if (breath_counter >= 5)
  {
    erase_epd();
    digitalWrite(LED_RED, HIGH);
    digitalWrite(LED_GRN, HIGH);
    digitalWrite(LED_BLU, HIGH);
    while (1)
    {

      paint.DrawStringAt(8, 15, "YOU JUST HAVE" , &Font20, COLORED);
      paint.DrawStringAt(8, 35, " SUCCESSFULLY" , &Font20, COLORED);
      paint.DrawStringAt(2, 55, "  COMPLETED  ", &Font20, COLORED);
      paint.DrawStringAt(2, 78, "  YOUR BREATHING ", &Font16, COLORED);
      paint.DrawStringAt(2, 93, " EXERCISE SESSION ", &Font16, COLORED);

      paint.DrawStringAt(5, 133, "Breath Counter:", &Font16, COLORED);
      paint.DrawStringAt(5, 155, "Past Sessions", &Font16, COLORED);
      paint.DrawStringAt(5, 170, "Breath Counts:", &Font16, COLORED);
      paint.DrawStringAt(170, 133, itoa(breath_counter, VAL, 10), &Font16, COLORED);
      paint.DrawStringAt(160, 170, itoa(net_breaths, VAL, 10), &Font16, COLORED);

      epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
      epd.DisplayFrame();

    }
  }

}

///////////////////////////////////////////////
////////////////main loop ends here ///////////
///////////////////////////////////////////////


///////////////////////////////////////////////
///////////// Function body ///////////////////
///////////////////////////////////////////////

// clean up dark spots on epaper display //

void flush_epd (void)
{
  if (epd.Init(lut_full_update) != 0)
  {
    return;
  }
  epd.ClearFrameMemory(0xFF);
  epd.DisplayFrame();
  //epd.ClearFrameMemory(0xFF);
  //epd.DisplayFrame();

}

// initialize full e paper display //

void init_epd(void)
{
  ///// Init Full Display Update ///////////
  if (epd.Init(lut_full_update) != 0)
  {
    return;
  }
  ///// Init Partial Display Update ////////
  if (epd.Init(lut_partial_update) != 0)
  {
    return;
  }
  ////////// Clears Up Full Disp ///////////
  // bit set = white, bit reset = black
  epd.ClearFrameMemory(0xFF);
  epd.DisplayFrame();
  // epd.ClearFrameMemory(0xFF);
  // epd.DisplayFrame();

}

// clean up lines on epaper //
void erase_epd(void)
{
  paint.SetWidth(200);
  paint.SetHeight(200);
  paint.SetRotate(ROTATE_180);
  paint.Clear(UNCOLORED);
}

full code

C/C++
unzip and open with Energia IDE 1.8.7
No preview (download only).

Credits

Shahariar

Shahariar

74 projects • 265 followers
"What Kills a 'Great life' is a 'Good Life', which is Living a Life Inside While Loop"

Comments