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 Hexiwear_zeta

Files at this revision

API Documentation at this revision

Comitter:
nbaker
Date:
Thu Apr 12 22:18:24 2018 +0000
Parent:
15:330794a9f347
Child:
17:746dc1b7b218
Commit message:
v2.14-Retasked hr_led Ticker to turn off heart rate zone LEDs. added HR screen #7 to screens that get refreshed with new data twice a second. Reduced WDT back to 2 seconds. Increased rolling average to 10 samples. removed 0.05s wait during HR read.

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/main.cpp	Wed Apr 11 02:23:07 2018 +0000
+++ b/main.cpp	Thu Apr 12 22:18:24 2018 +0000
@@ -20,6 +20,11 @@
 Display data screen update routines
 
 **************   Versions  ****************
+v2.14 - Retasked hr_led Ticker to turn off heart rate zone LEDs thereby preventing the 
+system from having to spend half its time in a wait state. added HR screen #7 to  
+screens that get refreshed with new data twice a second. Reduced WDT back to 2 seconds.  
+Increased rolling average to 10 samples. removed 0.05s wait during HR read.
+
 v2.13 - Added heart rate measurement, heart rate simulation, 
 improved heart rate leds, and optimized heart rate functionalities
 
@@ -70,11 +75,12 @@
 
 
 /* General  Definitions */
-#define SW_Ver          2.13    // For displaying software version
+#define SW_Ver          2.14    // For displaying software version
 #define LED_ON          0
 #define LED_OFF         1
 #define SCRN_TIME       10.0    // Set OLED screen turn off time to 10.0 seconds
-#define WDT_TIME        5.0     // Set Watch Dog timer to 1.5 seconds (1.5s reset in certain subroutines)
+#define WDT_TIME        2.0     // Set Watch Dog timer to 1.5 seconds (1.5s reset in certain subroutines)
+#define MAX_AVE_NUM     10       // maximum averaging depth of rolling average for batt, temp and humid
 #define Debug           1       // If "Debug" is defined, our code will compile for debug.  Comment out for Production code.
 
 #define FXOS8700_I2C_ADDRESS_ (0x1E<<1) //pins SA0,SA1=0 
@@ -90,6 +96,8 @@
 #define EXIT_BELOW      75
 #define EXIT_ABOVE      100
 #define VIB_OPT_2       75      // Haptic vibration pattern option for heart rate functions
+#define HR_LED_on_time  0.5 //how long should zone LED stay on for?
+#define HR_LED_period   1.0 //how often should zone LED blink?
 /* I2C Address */
 #define HR_W_ADDR          0xAE
 #define HR_R_ADDR          0xAF 
@@ -153,6 +161,7 @@
 void Enable_Heart_Rate();
 void Disable_Heart_Rate();
 void Led_Zone_Indicator();
+void Led_Zone_Indicator_off(); // turns off LEDs after 0.5 seconds instead of using a wait command
 void Heat_Index_Calculation();
 void fall_config(uint8_t);         //function call to setup fall detecting modes
 void accel_sensor_config(uint8_t); 
@@ -251,14 +260,16 @@
 uint8_t heat_index;                  // used in Heat index calc
 int hi_calc;                    // used in Heat index calc
 int adjustment;                 // used in Heat index calc
+bool randomized = 0; //Initialize to 0, since srand has not been called
+int simulation_stage = 0;
+uint32_t hr_data[100];
 // slow changing variables
 int sample_ftemp = 0;               // used in Heat index calc
 int sample_humid = 0;               // used in Heat index calc
 uint8_t batt_per_level = 0;         //
 uint8_t Ave_Num  = 0; 
-bool randomized = 0; //Initialize to 0, since srand has not been called
-int simulation_stage = 0;
-uint32_t hr_data[100];
+
+
 // Pointers for screen images 
 const uint8_t *Hexi_Heart_ = Hexi_Heart_bmp;
 //const uint8_t *NB_Linkedin = NB_Linkedin_bmp;  
@@ -342,7 +353,7 @@
 void timout_timer(){ // turn off display mode
         HexiwearBattery battery;
         battery.sensorOn();  
-    if (battery.isBatteryCharging() || batt_per_level > 99) {
+    if (battery.isBatteryCharging() || (uint8_t)battery.readLevelPercent() > 99) {
         oled.DimScreenOFF();
         Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED while fully charged
     } //end if
@@ -444,8 +455,8 @@
                 StartHaptic();
                 maxInit();
                 maxEnable();
-                hr_led.attach(&Led_Zone_Indicator, 1);
-                hr_ticker.attach(&processHeartRate, 5);
+                hr_led.attach(&Led_Zone_Indicator, HR_LED_period); // blink every second
+                hr_ticker.attach(&processHeartRate, 5); 
                 break;
             }
             case 8: {// Alert History
@@ -540,14 +551,14 @@
                 break;
             }
             case 32: {//Turn on HR led blinking for manual demonstration
-                hr_led.attach(&Led_Zone_Indicator, 1);
+                hr_led.attach(&Led_Zone_Indicator, HR_LED_period);
                  break;
             }
             case 33:{//Start heart rate simulation
                 StartHaptic();
                 if(maxim == 0)
                 {
-                    hr_led.attach(&Led_Zone_Indicator, 1);
+                    hr_led.attach(&Led_Zone_Indicator, HR_LED_period);
                     hr_simulation.attach(&HR_Simulation, 5.0);                  
                 }
                 update_display();
@@ -807,6 +818,9 @@
             }
             case 32: {//End HR led used for manual demonstration
                 hr_led.detach();
+                 RED_Led = LED_OFF; 
+                 GRN_Led = LED_OFF;
+                 BLU_Led = LED_OFF;
                 break;
             }
             case 33: {//End HR Simulation early
@@ -816,6 +830,9 @@
                     hr_simulation.detach();
                     simulation_stage = 0;
                     hr_led.detach();
+                    RED_Led = LED_OFF; 
+                    GRN_Led = LED_OFF;
+                    BLU_Led = LED_OFF;
                 }
                 update_display();
                 break;
@@ -1403,7 +1420,7 @@
 {
 //__STATIC_INLINE void __set_PMCTRL(0b01000000);// set K64 SMC_PMCTRL register to VLPR (Very low power run) mode
  //   SMC->PMCTRL = (uint8_t)((SYSTEM_SMC_PMCTRL_VALUE) & (SMC_PMCTRL_RUNM_MASK)); // Enable VLPR mode    
-    SMC->PMCTRL = (0b01000000);// set K64 SMC_PMCTRL register to VLPR (Very low power run) mode 
+ //   SMC->PMCTRL = (0b01000000);// set K64 SMC_PMCTRL register to VLPR (Very low power run) mode << did nothing for battery time
     
 //set_time(1256729737);  // Set RTC time to Wed, 28 Oct 2009 11:35:37
 //set_time((Year-1970)*365*24*3600+(days of this year)*24*3600+(hr)*3600 + (min)*60 + (Sec) - fudge factor);  // Set RTC time to Mon, 19 Feb 2018 10:00
@@ -1433,7 +1450,7 @@
     fall_config(10);            // SW reset accell and gyro sensor 
  //   gyro_sensor_config(10);     // SW reset gyro sensor 
     press_config(0);            // put pressure sensor into 2uA standby, we're not using it
-    MAX30101_test_config(10);   // SW reset accell sensor 
+ //   MAX30101_test_config(10);   // SW reset HR sensor << power is off
     oled.FillScreen(COLOR_BLACK); // Clear screen 
     
 // *****************  Local variables  ***********************
@@ -1487,7 +1504,7 @@
 /*
     oled.FillScreen(COLOR_BLACK); // Clear screen
     oled.DrawImage(Hexi_Heart_,0,0);  // my Hexi_Heart image is offset for some reason
-    wait(0.5);  // wait 3 seconds
+    wait(0.5);  // wait 0.5 seconds
 */
     oled.FillScreen(COLOR_BLACK); // Clear screen
     
@@ -1529,26 +1546,27 @@
     {
     Thread::wait(500);          // wait 0.5 sec each loop
     CLRWDT();
- //   SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
- //   __WFI();
-  //  deepsleep();
+
     if(OLED_PWR==1){
-    update_display_date();     // refresh display date w/o updating entire display 
+    update_display_date();     // refresh display data twice a second w/o updating entire display 
         }// end if
           
     i++;
-    }// end while(i<20)
+    }// end 10 second while(i<20) loop 
+    if(maxim==0){// don't use red LED while heart rate zone routine is active
     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
-//    NVIC_VLPW(0.01);          // BLIP led 1/10 sec each loop
-//   NVIC_SystemReset(); // software reset
+    if(maxim==0){// don't use red LED while heart rate zone routine is active
     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 
     
     CLRWDT();
-    UpDate_Ave(); // Update slow changing measurements once every 30 seconds 
+    UpDate_Ave(); // Update slow changing measurements once every 10.5 seconds 
     } // end of while(true)
 
 }
@@ -1998,7 +2016,8 @@
             oled.TextBox((uint8_t *)text,55,23,15,15); //Increase textbox for more digits
         
         /* Display Units */
-            strcpy((char *) text,"dF");oled.Label((uint8_t *)text,71,23);
+            strcpy((char *) text,"dF");
+            oled.Label((uint8_t *)text,71,23);
             
             break;
         }
@@ -2836,8 +2855,14 @@
     Determine_Current_Zone();
 } 
 
+/*****************************************************************************
+Name: Led_Zone_Indicator()
+Purpose: Ticker interupt routine called every 1.0 Seconds in order to Blink LED to indicate current Heart Rate zone
+Inputs: hr_led Ticker
+******************************************************************************/
 void Led_Zone_Indicator()
 {
+    CLRWDT();// Reset watchdog timer before we do this long opperation
   if(Led_Zones == true)
   {
     if(Current_Zone == 1)
@@ -2845,10 +2870,10 @@
         BLU_Led = LED_OFF;
         RED_Led = LED_ON;
         GRN_Led = LED_ON;
-        
-        wait(0.5);
-        RED_Led = LED_OFF;
-        GRN_Led = LED_OFF;
+        hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED
+        //wait(0.5);
+        //RED_Led = LED_OFF;
+        // GRN_Led = LED_OFF;
     }  
     else if(Current_Zone == 2)
     {
@@ -2862,8 +2887,9 @@
             GRN_Led = LED_OFF;
         }
         BLU_Led = LED_ON;
-        wait(0.5);  
-        BLU_Led = LED_OFF; 
+        hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED
+       // wait(0.5);  
+       // BLU_Led = LED_OFF; 
     }
     else if(Current_Zone == 3)
     {
@@ -2876,20 +2902,36 @@
             RED_Led = LED_OFF;
         }
         GRN_Led = LED_ON;
-        wait(0.5);  
-        GRN_Led = LED_OFF; 
+        hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED
+      //  wait(0.5);  
+     //   GRN_Led = LED_OFF; 
     }
     else if(Current_Zone == 4)
     {
         GRN_Led = LED_OFF;
         RED_Led = LED_ON;
-        wait(0.5);  
-        RED_Led = LED_OFF; 
+        hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED
+       // wait(0.5);  
+       // RED_Led = LED_OFF; 
     }
   }  
 }//end of Led_Zone_Indicator 
 
 /*****************************************************************************
+Name: Led_Zone_Indicator_off()
+Purpose: Ticker interupt routine called every 0.5 Seconds after LEDs turned on to turn them back
+off.  This avoids the 0.5 wait every second, freeing up the system.
+Inputs: hr_led Ticker
+******************************************************************************/
+ //turns off LEDs after 0.5 seconds instead of using a wait command
+void Led_Zone_Indicator_off(){
+    RED_Led = LED_OFF; 
+    GRN_Led = LED_OFF;
+    BLU_Led = LED_OFF;
+    hr_led.attach(&Led_Zone_Indicator, HR_LED_period); // blink every second
+    }//end void Led_Zone_Indicator_off()
+
+/*****************************************************************************
 Name: Heat_Index_Calculation()
 Purpose: Calculates the heat index using the temperature and humidity sensors
 Inputs: None
@@ -4249,6 +4291,23 @@
             
             break;
         }// end case 0
+        
+        case 7: {// Heart Rate Zone
+            textProperties.fontColor = COLOR_WHITE;
+            oled.SetTextProperties(&textProperties);
+            sprintf(display_buff, "%u", Heart_Rate);
+            textProperties.fontColor = COLOR_RED; //Change font to red
+            oled.SetTextProperties(&textProperties);//Implement color change
+            oled.Label((uint8_t *)display_buff,43,25); // Display at x,y
+            textProperties.fontColor = COLOR_GREEN;
+            oled.SetTextProperties(&textProperties); //implements the color change
+            sprintf(display_buff, "%u", Age); //Convert int to char array for displaying user age
+            oled.Label((uint8_t *)display_buff,43,45); // Display at x,y
+            textProperties.fontColor = COLOR_WHITE;
+            oled.SetTextProperties(&textProperties);
+
+            break;
+        }// end case 7
                      
             case 21: {// Fall Alert Diagnostic Screen
             if(Fall_Alert_Mode == 0){
@@ -4417,15 +4476,16 @@
     }//end if
     else{
     // updated measurments on a rolling average basis: 1/4 new measurement to 3/4 running average
-    batt_per_level = (Ave_Num-1)*batt_per_level/Ave_Num + (uint8_t)battery.readLevelPercent()/Ave_Num;
+    batt_per_level = (uint8_t)((Ave_Num-1)*batt_per_level/Ave_Num + battery.readLevelPercent()/Ave_Num);
     sample_ftemp = (Ave_Num-1)*sample_ftemp/Ave_Num + temphumid.sample_ftemp()/Ave_Num;
     sample_humid = (Ave_Num-1)*sample_humid/Ave_Num + temphumid.sample_humid()/Ave_Num;  
         }//end else
     Ave_Num++;
-    if(Ave_Num>4){
-        Ave_Num = 4;//set limit 
+    if(Ave_Num > MAX_AVE_NUM){
+        Ave_Num = MAX_AVE_NUM;//set limit 
         }    
 }// end UpDate_Ave
+
 void HR_Simulation(void)
 {
     if(randomized == 0)
@@ -4464,7 +4524,7 @@
     }
     simulation_stage++;
     Determine_Current_Zone();  
-    update_display();
+    //update_display();  // I don't think we should update display, let update_data() do that
 }
 
 void readRegs(int addr, uint8_t * data, int len)
@@ -4680,6 +4740,9 @@
     hr_measure_ticker.detach();  
     Disable_Heart_Rate();
     hr_led.detach();
+    RED_Led = LED_OFF; 
+    GRN_Led = LED_OFF;
+    BLU_Led = LED_OFF;
 }
 
 void processHeartRate(void)
@@ -4690,9 +4753,9 @@
     for(int i = 0; i < 100; i++)
     {
         hr_data[i] = readFIFO();
-        if(i % 3 == 1)
-            wait(0.05);
-    }
+        //if(i % 3 == 1) // there seems to be a missing "{" here
+         //   wait(0.01); // every third read wait 0.05s, this adds about 1.65s 
+     }
   
     
     peak = isPeak(hr_data);
@@ -4701,7 +4764,7 @@
     if(hr >= HR_Zone1[0] && hr <= HR_Zone4[1])
     {
         Heart_Rate = hr;
-        update_display();
+     //   update_display();//I don't think we need to update display here, let update_data do that
     }
     Determine_Current_Zone();