The HexiHeart is a demo project product that takes advantage of many of the onboard Hexiwear sensors and capabilities to create a multifunctional fitness and safety watch.
Dependencies: FXAS21002 FXOS8700 Hexi_KW40Z Hexi_OLED_SSD1351 MAXIM W25Q64FVSSIG HTU21D MPL3115A2 TSL2561
Fork of HexiHeart_Alex by
Diff: main.cpp
- Revision:
- 4:0803151bc5e4
- Parent:
- 3:6792c1ba586c
- Child:
- 5:e1431272be79
diff -r 6792c1ba586c -r 0803151bc5e4 main.cpp --- a/main.cpp Thu Feb 08 03:25:01 2018 +0000 +++ b/main.cpp Mon Feb 12 19:31:23 2018 +0000 @@ -13,10 +13,14 @@ #include "FXOS8700.h" // 3D Accelorometer & Mag #include "FXAS21002.h" // 3-Axis Gyroscope #include "Hexi_OLED_SSD1351.h" // OLED fuctions + // Non-Freescale HTU21D - combo temperature and Humidity +#include "W25Q64FV.h" // W25Q64FVSSIG Serial Flash + // Non-Freescale MPL3115A2 - pressure sensor +#include "Hexi_Battery/hexi_battery.h" // Battery status #include "OLED_types.h" // Text attributs #include "string.h" #include "OpenSans_Font.h" -#include "MAX30101.h" +#include "MAX30101.h" // Non-Freescale MAX30101 - Optical Heart rate sensor /* We need to confirm whether it's better to include and @@ -36,13 +40,15 @@ #define EXIT_BELOW 75 #define EXIT_ABOVE 100 #define VIB_OPT_2 75 +#define FXOS8700_I2C_ADDRESS_ (0x1E<<1) //pins SA0,SA1=0 void StartHaptic(void); void StartHaptic(int x); void StopHaptic(void const *n); void error_screen(void); -void update_display(void); +void update_display(void);// Screen lables refreshed +void update_data(void); // Screen data(only)refreshed void Decrement_Age(); void Set_Max_Bpm(); void Set_Zone_Boundaries(); @@ -59,6 +65,11 @@ void Disable_Heart_Rate(); void Led_Zone_Indicator(); +void fall_config(uint8_t); +void fall_detect(void); +void fall_det_end(void); +void fall_detect_off(void); +void impact_detect(void); // ***************** Global variables *********************** char text_1[20]; // Text buffer - Do we need more? @@ -66,7 +77,7 @@ bool Led_Zones = 1; bool HR_Enable = 0; bool OLED_ON = 1; // Turn OLED power on/off -bool Fall_Alert = 0; // Initialize as no active alert +bool Fall_Alert = 1; // Initialize as no active alert bool Panic_Alert = 0; // Initialize as no active alert bool Fall_Alert_Mode = 1; // Initialize with fall alert mode on bool Heart_Rate_Mode = 0; // Initialize with Heart rate off @@ -99,10 +110,24 @@ FXOS8700 mag(PTC11, PTC10); // Mag (same chip as Accel) //MAX30101 heart(PTB1, PTB0); //Heart Rate Chip +// initialize I2C bus for FXOS8700, FXAS-Gyro, MPL-Pressure + I2C i2c_bus1(PTC11, PTC10); // (SDA, SCL) + DigitalOut RED_Led(LED1); DigitalOut GRN_Led(LED2); DigitalOut BLU_Led(LED3); DigitalOut haptic(PTB9); +DigitalOut Led_clk1(PTA12); +DigitalOut Led_clk2(PTA13); +DigitalOut Led_clk3(PTA14); + +DigitalOut OLED_PWR(PTC13); // this pin turns on/off 15V to OLED display +DigitalOut Non_Free_PWR(PTB13); // this pin turns on/off non-freescale sensors (Pres/Temp/Hum/Light) +DigitalOut HR_PWR(PTA29); // this pin turns on/off Heart rate sensor +//DigitalIn Sw1(PTA12); //Switch 'T1' on docking station AND Led_clk1!! +//DigitalIn Sw2(PTA13); //Switch 'T2' on docking station AND Led_clk2!! +DigitalIn Sw3(PTA15); //Switch 'T3' on docking station + /* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */ KW40Z kw40z_device(PTE24, PTE25); @@ -110,14 +135,18 @@ /* Define timer for haptic feedback */ RtosTimer hapticTimer(StopHaptic, osTimerOnce); +//***************** Interrups ***************** +InterruptIn Accel_INT1(PTC1); // Accel sensor's interupt 1 +InterruptIn Accel_INT2(PTD13); // Accel sensor's interupt 2 + //***************** Tickers and Timers ***************** Ticker Screen_Timer;// use ticker to turn off OLED -void timout_timer() // turn off display mode -{ - oled.FillScreen(COLOR_BLACK); // Clear screen.. is there a better command for this? - OLED_ON = 0; // set flag to off - Screen_Timer.detach(); +void timout_timer(){ // turn off display mode +// oled.FillScreen(COLOR_BLACK); // Clear screen.. is there a better command for this? + OLED_PWR = 0; // Turn off OLED power supply + OLED_ON = 0; // set flag to off + Screen_Timer.detach(); // detach Ticker }//end routine void ButtonUp(void) @@ -421,7 +450,15 @@ } case 2: {// Fall Alert option StartHaptic(); - // toggle on/off + if(Fall_Alert == 1){ + Accel_INT1.fall(&fall_detect_off); // turn off Accel sensor's int#1 calls interupt routine + Fall_Alert = 0; + } + else{ + Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine + Fall_Alert = 1; + } + update_display(); break; } case 3: {// Heart Rate Monitoring option @@ -668,24 +705,39 @@ int main() { + OLED_PWR = 1; // Turn on OLED power supply oled.FillScreen(COLOR_BLACK); // Clear screen // ***************** Local variables *********************** // float accel_data[3]; float accel_rms=0.0; - + int i; + // ************** configure sensor modules ****************** - accel.accel_config(); + // accel.accel_config(); // configure sensor + fall_config(1); // configure sensor for fall detect + // Fall_config(Fall_Alert_Mode); // configure sensor for fall mode mag.mag_config(); -// gyro.gyro_config(); + gyro.gyro_config(); RED_Led = LED_OFF; GRN_Led = LED_OFF; BLU_Led = LED_OFF; + Led_clk1 = 0; // LEDs on docking station default to off, need to turn on with a 1 + Led_clk2 = 0; // LEDs on docking station default to off, need to turn on with a 1 + Led_clk3 = 0; // LEDs on docking station default to off, need to turn on with a 1 + Non_Free_PWR = 1; // Start with non-freescale sensors (Pres/Temp/Hum/Light)on + HR_PWR = 1; // Start with Heart rate sensor powered on + // ***** Register callbacks/interupts to application functions ********* kw40z_device.attach_buttonUp(&ButtonUp); kw40z_device.attach_buttonDown(&ButtonDown); kw40z_device.attach_buttonLeft(&ButtonLeft); kw40z_device.attach_buttonRight(&ButtonRight); - kw40z_device.attach_buttonSlide(&ButtonSlide); + // kw40z_device.attach_buttonSlide(&ButtonSlide); + +// ***** attaching interupts to functions ********* + Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine + // Accel_INT2.fall(&impact_detect); //Accel sensor's int#2 calls interupt routine + // **** Get OLED Class Default Text Properties **************** oled_text_properties_t textProperties = {0}; @@ -715,20 +767,56 @@ Screen_Timer.attach(&timout_timer,(SCRN_TIME));//start ticker timer for turning off LCD // ******************* Main Loop ************************* while (true) { + i=0; + while (i<20)// used for "Heart beat flash and updated any displayed data) + { + Thread::wait(500); // wait 0.5 sec each loop + if(OLED_PWR==1){ + // update_data(); + }// end if + i++; + }// end while(i<20) +// wait(10); // wait 10 sec each loop, was orig half sec + RED_Led = LED_ON; // Used only for diagnostic of wait command + Led_clk3 = 1; // Used only for diagnostic of wait command + wait(0.01); // BLIP led 1/10 sec each loop + RED_Led = LED_OFF; // Used only for diagnostic of wait command + Led_clk3 = 0; + Thread::wait(490); // keep up the pace, at 0.5 sec (0.01s+0.49s) update date - Thread::wait(500); // wait half a sec in each loop - } +// update_data(); // refresh display date w/o updating entire display + + } // end of while(true) + } // ************** end of main() void update_display(void) { + OLED_PWR = 1; // make sure OLED power supply is on oled_text_properties_t textProperties = {0}; // Need these to change font color oled.GetTextProperties(&textProperties); // Need these to change font color switch(Screen_Num) { case 0: {// Main Screen + HexiwearBattery battery; + battery.sensorOn(); oled.FillScreen(COLOR_BLACK); // Clear screen - oled.Label((uint8_t *)"Batt",60,0); // Display "Batt" at x,y + + if (battery.isBatteryCharging()) { + textProperties.fontColor = COLOR_GREEN; + oled.SetTextProperties(&textProperties); + // sprintf(text_1, "%s", "chrg"); + sprintf(text_1, "%i%%+", (uint8_t)battery.readLevelPercent()); + Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED while fully charged + } else { + sprintf(text_1, "%i%%", (uint8_t)battery.readLevelPercent()); + } + oled.TextBox((uint8_t *)text_1,60,0,35,15); //show level value of battery originaly at 55,40,35,15 + + textProperties.fontColor = COLOR_WHITE; + oled.SetTextProperties(&textProperties); + + oled.Label((uint8_t *)"Batt",35,0); // Display "Batt" at x,y oled.Label((uint8_t *)"Date",35,20); // Display "Date" at x,y oled.Label((uint8_t *)"Time",35,40); // Display "Time" at x,y oled.Label((uint8_t *)"H.I.",10,80); // Display "H.I." at x,y @@ -751,6 +839,13 @@ case 2: {// Fall Alert option oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Fall Alert",20,5); // Display at x,y + oled.Label((uint8_t *)"Protection",15,25); + if (Fall_Alert == 1){ + oled.Label((uint8_t *)" On ",42,40); + } + else { + oled.Label((uint8_t *)" Off ",40,40); + } oled.Label((uint8_t *)"*",85,15); // "*" at x,y oled.Label((uint8_t *)"*",85,60); // "*" at x,y oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y @@ -1516,7 +1611,7 @@ } else { Heart_Rate -= 1; } -} +} // end of Decrement_Heart_Rate void Led_Zone_Indicator() { @@ -1568,6 +1663,178 @@ wait(0.5); RED_Led = LED_OFF; } - } + } +}//end of Led_Zone_Indicator +/***************************************************************************** +Name: fall_detect() +Purpose: Interupt rutine called when accelerometer IC has detected a free-fall >= 0.5g + +******************************************************************************/ + +void fall_detect(){// fall detect interupt rutine +if(Fall_Alert == 1){ + +// for now just turn on display and give haptic feedback + Screen_Num = 22; //Change to screen 22 (Fall diag screen) + Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED + if (OLED_ON == 0) { + OLED_ON = 1; // Scree was off, set to On + } // endif + +//__disable_irq(); // Disable all Interrupts +// oled.Label((uint8_t *)" Fall Detected ",05,70); // Display at x,y + + update_display(); + BLU_Led = LED_ON; // LEDs default to on, need to turn off + Led_clk2 = 1; // Turn LED2 on docking station on + haptic = 1; + Accel_INT1.rise(&fall_det_end); // Accel sensor's int#1 calls interupt routine +//__enable_irq(); // Enable all Interrupts +}// end if +}//end fall_detect interupt routine + + +void fall_detect_off(){// fall detect interupt rutine +// for now just turn on display and give haptic feedback +}//end fall_detect_off interupt routine + +void fall_det_end(){ + haptic = 0; // Turn off Haptic + BLU_Led = LED_OFF; // Turn off HexiHeart Blue LED + Led_clk2 = 0; // Turn off LED2 on docking station on + oled.Label((uint8_t *)" ",05,70); // clear display at x,y + Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine +} //end fall_det_end interupt routine + +/***************************************************************************** +Name: impact_detect() +Purpose: Interupt rutine called when accelerometer IC has detected a vector +magnitude acceleration >= 3.0g + +******************************************************************************/ + +void impact_detect(){ + // oled.Label((uint8_t *)" Impact Detected ",05,60); // Display at x,y + // GRN_Led = LED_ON; // LEDs default to on, need to turn off + Led_clk3 = 1; // Turn LED2 on docking station on +}//end impact_detect interupt routine + +/***************************************************************************** +Name: fall_config() +Purpose: Used to set accelerometer IC's internal registers to set up chip level +interrupts +Inputs: int value from 0 to 256 +Returns: None +******************************************************************************/ + -} +void fall_config(uint8_t Num){ +// use case switches here to configure for +switch(Num) { + case 0: {// configure as normal (or maybe sleep) + char d[2]; + d[0] = FXOS8700_CTRL_REG1; //Puts device in Standby mode + d[1] = 0x00; + i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2); + + d[0] = FXOS8700_CTRL_REG1; //Puts device back into active mode + d[1] = 0x01; + i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d, 2); + oled.Label((uint8_t *)" Mode 0 ",30,60); // Display "mode" at x,y + break; + } + case 1: {// configure for free-fall int + StartHaptic(); // for debug + char d[2]; + d[0] = FXOS8700_CTRL_REG1; //Config reg1 + d[1] = 0x00; //Put device in Standby mode + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step1 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x0e; //XYZ_DATA_CFG (set full-scall range) + d[1] = 0b00000000; //Set data to default range of +/-2g for full range (2x0.488mg/LSB), High-pass filter off + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step1a error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x0a; //TRIG_CFG (address of trigger config reg) + d[1] = 0b00000100; //Trigger on freefall + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step2 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x15; //A_FFMT_CFG (address of Free fall trigger config reg), write in Standby only + d[1] = 0b00111000; //set to freefall, and look at all axis. + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step3 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x17; //A_FFMT_THS (address of Free fall threshold reg), write in Active or Standby + d[1] = 0b00001000; //set freefall threshold to about 756mg for now + // d[1] = uint8_t(1000*Fall_Thresh/63); //set freefall threshold - Resolution is 63mg/LSB, 0b111_1111 is maximum value + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step4 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x18; //A_FFMT_COUNT (address of Free fall debounce counter), write in Active or Standby + d[1] = 0b00000110; //with ODR at 100Hz, should equal 60mS debounce time or 120mS in Sleep + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step5 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x2b; //CTRL_REG2 (address of control reg), write in Standby only + d[1] = 0b00001101; //Turns Auto-Sleep mode on and low-noise, low power + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step6 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x2c; //CTRL_REG3 (address of Int control reg), write in Standby only + d[1] = 0b00001000; //FFMT will wake chip from sleep, int are active high + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step7 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x2d; //CTRL_REG4 (address of Int enable reg), write in Standby only + d[1] = 0b00000100; // FFMT int enabled and for debug I'm using a sleep int + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step8 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = 0x2e; //CTRL_REG5 (Int routing reg), write in Standby only + d[1] = 0b00000100; // Make FFMT int output on pin INT1(PTC1) + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step9 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + d[0] = FXOS8700_CTRL_REG1; //CTRL_REG1, write in Standby only except for bit[0] + d[1] = 0b00011001; //Auto-Sleep mode on set to 50Hz, ODR set to 100Hz Puts device back into Active mode + if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ + oled.Label((uint8_t *)" Step10 error ",30,05); // Display "error" at x,y + wait(3.0); // display for 3 seconds + }//end if + + //oled.FillScreen(COLOR_BLACK); // Clear screen + oled.Label((uint8_t *)" Mode 1 ",30,60); // Display "mode" at x,y + GRN_Led = LED_ON; // LEDs default to on, need to turn on + break; + } + default: { + oled.Label((uint8_t *)" Mode ? ",30,60); // Display "mode" at x,y + // unknown config + break; + } +}// end switch + +}// end Fall_config +