
Fitbit code using RTOS
Dependencies: mbed PulseSensor2 SCP1000 mbed-rtos 4DGL-uLCD-SE LSM9DS1_Library_cal PinDetect FatFileSystemCpp GP-20U7
Diff: main.cpp
- Revision:
- 0:bcfec522ef98
- Child:
- 2:f96f7a311486
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Apr 21 22:52:20 2020 +0000 @@ -0,0 +1,394 @@ +#include "mbed.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); + +Ticker display; +Ticker LCD_clock; +Ticker Barometer; +Ticker GPS; +Ticker HR; +Ticker setup; + +int bpm; +int steps = 0; +int flights = 0; +float distance = 0.0; +float calories = 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; + +// 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() { + 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); +} + +void setup_screen(void) { + 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; + } +} + +void update_screen(void) { + read_pot(); + 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, 118, 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 MI", 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; + } +} + +void readHR(){ + 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));; +} + +void readBarometer(){ + 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; +} + +void readGPS(){ + 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) { + distance = distance + (3963*acosf(sinf(old_lat)*sinf(latitude)+cosf(old_lat)*cosf(latitude)*cosf(longitude-old_lon))); + } + old_lat = latitude; + old_lon = longitude; + //pc.printf("%f, %f, %f\r\n", latitude, longitude, distance); + } + } +} + +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(); + setup.attach(&setup_screen, 0.3); + + while(setup_state) { + pc.printf("%d", screen); + } + + // Off button + pb.attach_deasserted(&button); + + // set up the display + setup.detach(); + uLCD.cls(); + display.attach(&update_screen, 0.5); + LCD_clock.attach(&display_time, 0.7); + + // 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 + FILE *fp = fopen( "/msc/data.txt", "w"); + if(fp == NULL) { + error("Could not open file for write\n"); + } + fprintf(fp, "Sample Number, Pressure (Pa), Acceleration Magnitude (Gs), Heart Rate (bpm), Latitude (degrees), Longitude (degrees)\n"); + + + Barometer.attach(&readBarometer, 2); + GPS.attach(&readGPS, 10); + HR.attach(&readHR, 0.5); + + while(run) { + // Read Sensors + //bpm = PPG.get_BPM(); + 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; + + // Save the data to the usb flash drive and print to the terminal + fprintf(fp, "%d, %lu, %f, %d, %f, %f\r\n", sample_num, pressure, avg, bpm, latitude, longitude); + //pc.printf("%d, %lu, %f, %d, %f, %f\r\n", sample_num, pressure, avg, bpm, latitude, longitude); + sample_num++; + one = !one; + // Sampling rate of ~200 Hz + wait(0.2); + } + fclose(fp); + one = 0; +} \ No newline at end of file