Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed PulseSensor2 SCP1000 mbed-rtos 4DGL-uLCD-SE LSM9DS1_Library_cal PinDetect FatFileSystemCpp GP-20U7
main.cpp
- Committer:
- dyu2021
- Date:
- 2020-04-22
- Revision:
- 31:3363c6923beb
- Parent:
- 25:41ec16a87ebd
- Child:
- 32:cdbd7de8ae10
File content as of revision 31:3363c6923beb:
#include "mbed.h"
#include "rtos.h"
#include "LSM9DS1.h"
#include "SCP1000.h"
#include "PulseSensor.h"
#include "PinDetect.h"
#include "uLCD_4DGL.h"
#include "GPS.h"
#include "MSCFileSystem.h"
SCP1000 scp1000(p5,p6,p7,p8);
LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);
PulseSensor PPG(p17);
uLCD_4DGL uLCD(p28,p27,p29);
Serial pc(USBTX, USBRX);
DigitalOut one = LED1;
DigitalOut two = LED2;
DigitalOut three = LED3;
DigitalOut four = LED4;
AnalogIn pot(p20);
PinDetect pb(p21);
GPS gps(p13, p14);
#define FSNAME "msc"
MSCFileSystem msc(FSNAME);
int bpm;
int steps = 0;
int flights = 0;
float distance = 0.0;
float calories = 0;
int oldSteps = 0;
const int stepGoal = 100;
float stride_length = 0.0;
unsigned long pressure;
float latitude = 0;
float longitude = 0;
float old_lat = 0;
float old_lon = 0;
#define PI 3.14159
unsigned long p_buff[4];
int count = 0;
int mode = 1;
int oldMode = 1;
bool run = true;
int gender;
int weight;
int age;
int screen = 1;
int oldScreen = 1;
bool setup_state = true;
Timer usb_timer;
Thread thread1;
Thread thread2;
Thread thread3;
Thread thread4;
Thread thread5;
Mutex serial_mtx;
Mutex usb_mtx;
// when the pushbotton is pressed the run flag is set to false and the main
// function while loop exits so that the data file can be closed
// so press the button when you're ready to be done collecting data
void button (void) {
run = false;
}
void next() {
oldScreen = screen;
screen++;
if(screen == 4) {
setup_state = false;
}
}
// Reads the value of the potentiometer and averages over 3 readings to get rid
// of random spikes/zero values. Returns either a 1, 2 or 3 based on which 3rd
// of its range the potentiometer is in and which screen should be displayed
void read_pot() {
float m1;
float m2;
float m3;
oldMode = mode;
m1 = pot.read();
m2 = pot.read();
m3 = pot.read();
if(m1 < 0.2 && m2 < 0.2 && m3 < 0.2) {
mode = 1;
} else if(m1 >= 0.2 && m1 < 0.4 && m2 >= 0.2 && m2 < 0.4 && m3 >= 0.2 && m3 < 0.4) {
mode = 2;
} else if(m1 >= 0.4 && m1 < 0.6 && m2 >= 0.4 && m2 < 0.6 && m3 >= 0.4 && m3 < 0.6) {
mode = 3;
} else if(m1 >= 0.6 && m1 < 0.8 && m2 >= 0.6 && m2 < 0.8 && m3 >= 0.6 && m3 < 0.8) {
mode = 4;
} else if(m1 >= 0.8 && m2 >= 0.8 && m3 >= 0.8) {
mode = 5;
}
//when the mode changes, clear the screen
}
//Display the time on the top
void display_time() {
while(1) {
serial_mtx.lock();
uLCD.locate(1, 1);
uLCD.color(WHITE);
uLCD.text_width(2);
uLCD.text_height(3);
time_t seconds = time(NULL);
char timeBuffer[32];
strftime(timeBuffer, 32, "%I:%M %p\r\n", localtime(&seconds));
uLCD.printf("%s", timeBuffer);
serial_mtx.unlock();
Thread::wait(700);
}
}
void setup_screen(void) {
while(1) {
serial_mtx.lock();
if (oldScreen != screen) {
uLCD.filled_rectangle(0,0, 128, 128, BLACK);
oldScreen++;
}
switch(screen) {
case 1:
//Gender
uLCD.locate(2, 1);
uLCD.text_width(2);
uLCD.text_height(2);
uLCD.puts("Gender");
uLCD.text_width(3);
uLCD.text_height(3);
uLCD.locate(1, 3);
uLCD.putc('M');
uLCD.locate(4, 3);
uLCD.putc('F');
if(pot.read() > 0.5) {
gender = 0;
uLCD.rectangle(13, 60, 48, 100, BLACK);
uLCD.rectangle(75, 60, 110, 100, GREEN);
} else {
gender = 1;
uLCD.rectangle(75, 60, 110, 100, BLACK);
uLCD.rectangle(13, 60, 48, 100, GREEN);
}
break;
case 2:
//Weight
uLCD.color(WHITE);
uLCD.locate(9, 14);
uLCD.text_width(1);
uLCD.text_height(1);
uLCD.puts("lbs");
uLCD.locate(2, 1);
uLCD.text_width(2);
uLCD.text_height(2);
uLCD.puts("Weight");
weight = 0.45 * (90 + pot.read() * 210);
char weight_string[3];
if(weight < 100) {
sprintf(weight_string, " %d", weight);
} else {
sprintf(weight_string, "%d", weight);
}
uLCD.text_width(3);
uLCD.text_height(3);
uLCD.locate(2, 3);
uLCD.color(GREEN);
uLCD.puts(weight_string);
uLCD.line(35, 100, 110, 100, WHITE);
break;
case 3:
//Age
uLCD.color(WHITE);
uLCD.locate(3, 1);
uLCD.text_width(2);
uLCD.text_height(2);
uLCD.puts("Age");
age = (int) (10 + pot.read() * 89);
char age_string[2];
sprintf(age_string, "%d", age);
uLCD.text_width(3);
uLCD.text_height(3);
uLCD.locate(2, 3);
uLCD.color(GREEN);
uLCD.puts(age_string);
uLCD.line(40, 100, 90, 100, WHITE);
break;
}
serial_mtx.unlock();
Thread::wait(100);
}
}
void update_screen(void) {
while(1) {
read_pot();
serial_mtx.lock();
if (oldMode != mode) {
uLCD.filled_rectangle(0,0, 128, 128, BLACK);
}
// print the information to the LCD display
switch(mode) {
case 1:
//Step count
//uLCD.media_init();
//uLCD.set_sector_address(0x0000, 0x0005);
//uLCD.display_image(50, 45);
uLCD.filled_rectangle(10, 110, 118, 115, BLACK);
uLCD.locate(3, 11);
uLCD.text_height(1);
uLCD.text_width(1);
uLCD.color(WHITE);
uLCD.printf("%4d steps",steps);
uLCD.filled_rectangle(10, 110, 10 + int(steps * (110/stepGoal)), 115, WHITE);
break;
case 2:
// Heart rate
//uLCD.media_init();
//uLCD.set_sector_address(0x0000, 0x000A);
//uLCD.display_image(50, 45);
uLCD.locate(5, 11);
uLCD.text_height(1);
uLCD.text_width(1);
uLCD.color(WHITE);
uLCD.printf("%3d BPM", bpm);
break;
case 3:
//Distance
//uLCD.media_init();
//uLCD.set_sector_address(0x0000, 0x000F);
//uLCD.display_image(50, 45);
uLCD.locate(6, 11);
uLCD.text_height(1);
uLCD.text_width(1);
uLCD.color(WHITE);
uLCD.printf("%4.2f ft", distance);
break;
case 4:
//Calories
//uLCD.media_init();
//uLCD.set_sector_address(0x0000, 0x0000);
//uLCD.display_image(50, 45);
uLCD.locate(4, 11);
uLCD.text_height(1);
uLCD.text_width(1);
uLCD.color(WHITE);
uLCD.printf("%4d cal", (int)calories);
break;
case 5:
//Floors
//uLCD.media_init();
//uLCD.set_sector_address(0x0000, 0x0014);
//uLCD.display_image(50, 45);
uLCD.locate(4, 11);
uLCD.text_height(1);
uLCD.text_width(1);
uLCD.color(WHITE);
uLCD.printf("%2d floors", flights);
break;
}
serial_mtx.unlock();
Thread::wait(100);
}
}
void readHR(){
while(1) {
bpm = PPG.get_BPM();
//calories = calories + (.0083)*.239*(gender*(-55.0969+.6309*bpm+.1988*weight+.2017*age)+(1-gender)*(-20.4022+.4472*bpm-.1263*weight+.074*age));
calories = calories + (.0083)*0.239*(gender*(-55.0969+.6309*bpm+.1988*0.453592*weight
+.2017*age)+(1-gender)*(-20.4022+.4472*bpm-.1263*0.453592*weight+.074*age));
//converted weight from lbs to kilograms
//Alternate way to calculate distance (likely more accurate)
//distance = distance + (steps - oldSteps)* stride_length;
//oldSteps = steps;
Thread::wait(500);
}
}
void readBarometer()
{
while(1) {
pressure = scp1000.readPressure();
if(count >= 0) count--;
unsigned long dif;
if(pressure < p_buff[0]) {
dif = p_buff[0] - pressure;
} else {
dif = 0;
}
if(pressure != 0 && p_buff[0] != 0 && dif > 40 && dif < 60 && count < 0) {
flights++;
count = 2;
}
p_buff[0] = p_buff[1];
p_buff[1] = p_buff[2];
p_buff[2] = p_buff[3];
p_buff[3] = pressure;
Thread::wait(2000);
}
}
void readGPS(){
while(1) {
serial_mtx.lock();
if(gps.connected()) {
if(gps.sample()) {
if(gps.ns == 'S') {
longitude = gps.longitude*PI/180;
} else {
longitude = -gps.longitude*PI/180;
}
if(gps.ew == 'W') {
latitude = gps.latitude*PI/180;
} else {
latitude = -gps.latitude*PI/180;
}
if(latitude != 0 && longitude != 0 && old_lat != 0 && old_lon != 0) {
float a = sinf(old_lat)*sinf(latitude)+cosf(old_lat)*cosf(latitude)*cosf(longitude-old_lon);
if(a > 1) a = 1;
distance = distance + (.75*acosf(a));
}
old_lat = latitude;
old_lon = longitude;
//pc.printf("%f, %f, %f\r\n", latitude, longitude, distance);
}
}
serial_mtx.unlock();
Thread::wait(10000);
}
}
void saveData() {
// Save the data to the usb flash drive and print to the terminal
FILE *fp = fopen( "/msc/data.txt", "a");
if(fp == NULL) {
error("Could not open file for write\n");
}
time_t seconds = time(NULL);
char date[32];
strftime(date, 32, "%m/%d/%y", localtime(&seconds));
fprintf(fp, "%s\t%d\t%d\t%0.2f\t%0.2f\n\r", date, steps, flights, calories, distance);
pc.printf("%s\t%d\t%d\t%0.2f\t%0.2f\n\r", date, steps, flights, calories, distance);
fclose(fp);
}
int main() {
//Set RTC time
set_time(1256729737);
// Next screen button
pb.mode(PullUp);
pb.attach_deasserted(&next);
pb.setSampleFrequency();
//set up the display
uLCD.baudrate(3000000);
uLCD.background_color(BLACK);
uLCD.cls();
thread1.start(setup_screen);
while(setup_state) {
pc.printf("%d\r\n", screen);
}
thread1.terminate();
// Off button
pb.attach_deasserted(&button);
// set up the display
uLCD.cls();
thread1.start(update_screen);
thread2.start(display_time);
// LED indicates whether or not data is being collected
one = 0;
two = 0;
three = 0;
four = 0;
// Start sensors
int sample_num = 1;
PPG.start();
IMU.begin();
IMU.calibrate(1);
float ax;
float ay;
float az;
float mag = 0;
float buffer[2] = {0};
float avg_buffer[2] = {0};
float avg;
// Initialize data file on usb flash drive
usb_mtx.lock();
FILE *fp = fopen( "/msc/data.txt", "r+");
if(fp == NULL) {
error("Could not open file for write\n");
}
//Check to see if file is empty, not working right now
fseek (fp, 0, SEEK_END);
int size = ftell(fp);
if (0 == size) {
fprintf(fp, "Date\tSteps\tFloors\tCalories\tDistance (ft)\r\n");
pc.printf("Data.txt rewritten\r\n");
}
fclose(fp);
usb_mtx.unlock();
thread3.start(readBarometer);
thread4.start(readGPS);
thread5.start(readHR);
usb_timer.start();
while(run) {
// Read Sensors
IMU.readAccel();
ax = IMU.calcAccel(IMU.ax);
ay = IMU.calcAccel(IMU.ay);
az = IMU.calcAccel(IMU.az);
// Calculate the 3 point moving average of the magnitude of the
// acceleration vector
mag = sqrt((ax*ax) + (ay*ay) + (az*az));
avg = (buffer[0] + buffer[1] + mag) / 3;
buffer[0] = buffer[1];
buffer[1] = mag;
// Count a step if the previous point was a maximum (greater than the
// current point and 2 points back) and was greater than the threshold
// value of 1.05
if(sample_num > 1) {
float dif1 = avg_buffer[1] - avg_buffer[0];
float dif2 = avg_buffer[1] - avg;
float peak_prominence = 0.01;
if(dif1 > peak_prominence && dif2 > peak_prominence) {
steps++;
}
}
avg_buffer[0] = avg_buffer[1];
avg_buffer[1] = avg;
sample_num++;
one = !one;
// Sampling rate of ~200 Hz
if(usb_timer.read() >= 30) {
//pc.printf("Starting USB Write\r\n");
usb_mtx.lock();
saveData();
usb_mtx.unlock();
usb_timer.stop();
usb_timer.reset();
usb_timer.start();
}
Thread::wait(200);
}
one = 0;
}

