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: Hexi_KW40Z images
driver.cpp
00001 #include "mbed.h" 00002 #include "pwm_tone.h" /* Tone library for Buzzer Click */ 00003 #include "Hexi_OLED_SSD1351.h" /* Header file for OLED Display */ 00004 #include "string.h" 00005 #include "Hexi_KW40Z.h" /* Driver for button presses and BLE */ 00006 #include <math.h> /* Used for ADC conversion algorithm */ 00007 #include "images.h" /* BMPs of the images drawn to the OLED */ 00008 00009 /*****Function Prototypes*****/ 00010 void readSensors(); 00011 void ledColor(); 00012 void led_out(); 00013 void buzzer(); 00014 void CalculatePPM(); 00015 void dataQueue(); 00016 void initModules(); 00017 void StartHaptic(void); 00018 void StopHaptic(void const *n); 00019 void txTask(void); 00020 00021 PwmOut Buzzer(PTA10); /* Buzzer is attached to docking station port 1 */ 00022 AnalogIn AQSensor(PTB3); /* Air Quality sensor is attached to docking station port 2 */ 00023 AnalogIn COSensor(PTB6); /* Carbon Monoxide sensor is attached to docking station port 3 */ 00024 00025 /* Instantiate the SSD1351 OLED Driver */ 00026 SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); 00027 00028 BusOut led(PTC8, PTD0, PTC9); /* RGB Port Configurations */ 00029 DigitalOut haptic(PTB9); /* Port Configuration for vibrations */ 00030 /* Define timer for haptic feedback */ 00031 RtosTimer hapticTimer(StopHaptic, osTimerOnce); 00032 00033 int screen = 1; //detects which screen the user is currently on 00034 bool is_drawn1 = 0; //detects if the screen is already drawn to the screen 00035 bool is_drawn2 = 0; 00036 bool is_drawn3 = 0; 00037 bool is_drawn4 = 0; 00038 bool is_ble = 0; //detects if the device is currently running BLE mode 00039 00040 /* Screens */ 00041 const uint8_t *image1; //homescreen 00042 00043 const uint8_t *image2; //air quality screen 00044 00045 const uint8_t *image3; //co screen 00046 00047 const int green = 5, 00048 red = 6, /* LED Colors */ 00049 black = 7, 00050 yellow = 4; 00051 00052 bool is_sounding = false; /* Set to high if the buzzer is going off */ 00053 00054 int led_color; /* Variable to hold the current LED color */ 00055 00056 Ticker sensor_read, /* Used for the read sensor subroutine call */ 00057 buzzer_sound, /* Used for the sound buzzer subroutine call */ 00058 led_flash, /* Used to determine the flash rate */ 00059 ledcolor, /* Used to determine the LED color */ 00060 A2D_Convert, /* Used to convert the analog signal to digital */ 00061 push; /* Used to push values into the data array */ 00062 00063 float B_4 = 1000000/Ti4, /* Tones that will play on the buzzer click */ 00064 B_5 = 1000000/Ti5; 00065 00066 char text[20]; /* Static Text Buffer for OLED Display */ 00067 char AQ_level[20]; /* Dynamic Text Buffer for AQ total */ 00068 char CO_level[20]; /* Dynamic Text Buffer for CO total */ 00069 char average[20]; /* Dynamic Text Buffer for the Average total */ 00070 char total_total[20]; /* Dynamic Text Buffer for the Total total */ 00071 char ble_status[20]; /* Informs the user if BLE is activated or disabled */ 00072 00073 /* Either unit16_t or double */ 00074 double total, /* Variable to store the total total */ 00075 aq_ppm, /* Variable used to store the AQ PPM */ 00076 co_ppm, /* Variable used to store the CO PPM */ 00077 prev_value; /* Used for ARC Calculation */ 00078 double ARC; 00079 00080 uint16_t aq_total, /* Variable to store the AQ total */ 00081 co_total; /* Variable to store the CO total */ 00082 00083 /*Create a Thread to handle sending BLE Sensor Data */ 00084 Thread txThread; 00085 00086 /* Variables to handle the circular array algorithm */ 00087 const int SIZE = 500; 00088 double dataSet [SIZE]; 00089 int pushIndex = 0; 00090 bool calc = false; 00091 double avg = 0, sum = 0; 00092 00093 /* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */ 00094 KW40Z kw40z_device(PTE24, PTE25); 00095 00096 /* Below are the functions to handle button presses and screens */ 00097 void ButtonRight(void)//CO screen button 00098 { 00099 StartHaptic(); 00100 screen = 3; 00101 } 00102 00103 void ButtonLeft(void)//AQ screen button 00104 { 00105 StartHaptic(); 00106 screen = 2; 00107 } 00108 00109 void ButtonDown(void)//home screen button 00110 { 00111 StartHaptic(); 00112 screen = 1; 00113 } 00114 00115 void ButtonUp(void) {//toggles bluetooth mode 00116 StartHaptic(); 00117 screen = 4; 00118 kw40z_device.ToggleAdvertisementMode(); 00119 is_ble = !is_ble; 00120 } 00121 00122 void PassKey(void) 00123 { 00124 StartHaptic(); 00125 strcpy((char *) text,"PAIR CODE"); 00126 oled.TextBox((uint8_t *)text,0,25,95,18); 00127 00128 /* Display Bond Pass Key in a 95px by 18px textbox at x=0,y=40 */ 00129 sprintf(text,"%d", kw40z_device.GetPassKey()); 00130 oled.TextBox((uint8_t *)text,0,40,95,18); 00131 } 00132 00133 int main(){ 00134 00135 initModules(); 00136 00137 /* Subroutine Calls */ 00138 sensor_read.attach(&readSensors, 1); /* Read the sensor on a time interval */ 00139 A2D_Convert.attach(&CalculatePPM, 1); /* Convert the values read from the sensors to floating point ppm values */ 00140 push.attach(&dataQueue, 1); /* Push the value into the set and compute the average */ 00141 ledcolor.attach(&ledColor, 0.5); /* Determine the LED color */ 00142 led_flash.attach(&led_out, 0.25); /* Flash LED based on sensor data */ 00143 buzzer_sound.attach(&buzzer, 0.25); /* Sensor values are sent to buzzer function */ 00144 00145 /* Register callbacks to button presses */ 00146 kw40z_device.attach_buttonDown(&ButtonDown); 00147 kw40z_device.attach_buttonLeft(&ButtonLeft); 00148 kw40z_device.attach_buttonRight(&ButtonRight); 00149 kw40z_device.attach_buttonUp(&ButtonUp); 00150 kw40z_device.attach_passkey(&PassKey); 00151 00152 txThread.start(txTask); /*Start transmitting Sensor Tag Data */ 00153 00154 while (1) { /* Loop to process and display data to the OLED */ 00155 00156 /* Get OLED Class Default Text Properties */ 00157 oled_text_properties_t textProperties = {0}; 00158 oled.GetTextProperties(&textProperties); 00159 00160 /* Set text properties to green and right aligned for the dynamic text */ 00161 textProperties.fontColor = COLOR_GREEN; 00162 textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT; 00163 oled.SetTextProperties(&textProperties); 00164 00165 if (screen == 2){ //Air Quality Screen 00166 if(!is_drawn2){ 00167 is_drawn1 = 0; 00168 is_drawn3 = 0; 00169 is_drawn4 = 0; 00170 oled.DrawImage(image2,0,0); 00171 is_drawn2 = 1; 00172 } 00173 if (aq_ppm >= 50 and aq_ppm < 100){ 00174 textProperties.fontColor = COLOR_YELLOW; //color the font yellow 00175 oled.SetTextProperties(&textProperties); 00176 } 00177 else if (aq_ppm >= 100){ 00178 textProperties.fontColor = COLOR_RED; //color the font red 00179 oled.SetTextProperties(&textProperties); 00180 } 00181 sprintf(AQ_level,"%.2f",aq_ppm); /* Print the AQ PPM to the screen */ 00182 oled.TextBox((uint8_t *)AQ_level,35,76,35,15); 00183 } 00184 else if (screen == 3){ //Carbon Monoxide Screen 00185 if (!is_drawn3){ 00186 is_drawn2 = 0; 00187 is_drawn1 = 0; 00188 is_drawn4 = 0; 00189 oled.DrawImage(image3,0,0); 00190 is_drawn3 = 1; 00191 } 00192 if (co_ppm >= 50 and co_ppm < 100){ 00193 textProperties.fontColor = COLOR_YELLOW; //color the font yellow 00194 oled.SetTextProperties(&textProperties); 00195 } 00196 00197 else if (co_ppm >= 100) { 00198 textProperties.fontColor = COLOR_RED; //color the font red 00199 oled.SetTextProperties(&textProperties); 00200 } 00201 sprintf(CO_level,"%.2f",co_ppm); /* Print the CO PPM to the screen */ 00202 oled.TextBox((uint8_t *)CO_level,35,76,35,15); 00203 00204 } 00205 else if (screen == 1) { //Home Screen 00206 if (!is_drawn1){ 00207 is_drawn3 = 0; 00208 is_drawn2 = 0; 00209 is_drawn4 = 0; 00210 oled.DrawImage(image1,0,0); 00211 is_drawn1 = 1; 00212 } 00213 if (avg >= 50 and avg <100) { 00214 textProperties.fontColor = COLOR_YELLOW; //color the font yellow 00215 oled.SetTextProperties(&textProperties); 00216 } 00217 else if (avg >=100){ 00218 textProperties.fontColor = COLOR_RED; //color the font red 00219 oled.SetTextProperties(&textProperties); 00220 } 00221 00222 sprintf(average, "%.2f", avg); 00223 oled.TextBox((uint8_t *)average,53,23,35,15); 00224 00225 if (total >=50 and total < 100){ 00226 textProperties.fontColor = COLOR_YELLOW; //color the font yellow 00227 oled.SetTextProperties(&textProperties); 00228 } 00229 else if (total >= 100) { 00230 textProperties.fontColor = COLOR_RED; //color the font red 00231 oled.SetTextProperties(&textProperties); 00232 } 00233 else { 00234 textProperties.fontColor = COLOR_GREEN; //color the font green 00235 oled.SetTextProperties(&textProperties); 00236 } 00237 sprintf(total_total, "%.2f", total); /* Print the total to the screen */ 00238 oled.TextBox((uint8_t *)total_total,53,39,35,15); 00239 } 00240 00241 else if (screen == 4){ //BLE Pairing Screen 00242 if (!is_drawn4){ 00243 is_drawn3 = 0; 00244 is_drawn2 = 0; 00245 is_drawn1 = 0; 00246 oled.FillScreen(COLOR_BLACK); 00247 is_drawn4 = 1; 00248 } 00249 textProperties.alignParam = OLED_TEXT_ALIGN_CENTER; 00250 textProperties.fontColor = COLOR_BLUE; 00251 oled.SetTextProperties(&textProperties); 00252 strcpy((char *) text,"BLUETOOTH"); 00253 oled.TextBox((uint8_t *)text,0,25,95,18); 00254 if (is_ble) { 00255 textProperties.fontColor = COLOR_GREEN; 00256 oled.SetTextProperties(&textProperties); 00257 strcpy((char *) ble_status, "On"); 00258 oled.TextBox((uint8_t *)ble_status,0,55,95,18); 00259 } 00260 else { 00261 textProperties.fontColor = COLOR_RED; 00262 oled.SetTextProperties(&textProperties); 00263 strcpy((char *) ble_status, "Off"); 00264 oled.TextBox((uint8_t *)ble_status,0,55,95,18); 00265 } 00266 } 00267 Thread::wait(500); 00268 } 00269 00270 return 0; 00271 } 00272 void txTask(void){ 00273 while (1){ 00274 /*Notify Hexiwear App that it is running Sensor Tag mode*/ 00275 kw40z_device.SendSetApplicationMode(GUI_CURRENT_APP_SENSOR_TAG); 00276 kw40z_device.SendTemperature(100*aq_ppm); //send ppm Air Quality Click value 00277 kw40z_device.SendHumidity(100*co_ppm); //send ppm CO click value 00278 kw40z_device.SendPressure(100*total); //send total 00279 Thread::wait(1000); 00280 } 00281 } 00282 void initModules() { /* Function to initialize the system */ 00283 00284 /* Turns on the OLED Display*/ 00285 oled.PowerON(); 00286 00287 /* Sets the pointers to their respective images */ 00288 image1 = homescreen_bmp; 00289 image2 = airquality_bmp; 00290 image3 = co_bmp; 00291 } 00292 00293 void readSensors(){ /* Function to read sensors */ 00294 00295 /* Grab the analog signal from the sensors as 16 bit unsigned integers */ 00296 aq_total = AQSensor.read_u16(); 00297 co_total = COSensor.read_u16(); 00298 /* Grab the analog signal from the sensors as floats */ 00299 //aq_total = AQSensor.read(); 00300 //co_total = AQSensor.read(); 00301 00302 } 00303 00304 void ledColor(){ /* Function to determine the LED color */ 00305 00306 if ((total - avg) <= 10 and total < 50 and ARC < 10 ) { 00307 led = green; 00308 led_color = led; /* Store the LED color for the flash function */ 00309 } 00310 else if ((total - avg) > 10 and (total - avg) < 50 and total < 100 or (ARC >= 10 and ARC < 20)) { 00311 led = yellow; 00312 led_color = led; /* Store the LED color for the flash function */ 00313 } 00314 else if ((total - avg >= 50) or total >= 100 or avg >= 100 or ARC >= 20) { 00315 led = red; 00316 led_color = led; /* Store the LED color for the flash function */ 00317 } 00318 } 00319 00320 void led_out() { /* Function to flash LEDs */ 00321 00322 if (led == green) {return;} /* If green, don't blink */ 00323 else if (led == black) {led = led_color;} 00324 else {led = black;} 00325 00326 } 00327 00328 void buzzer() { /* Function to handle the buzzer sound */ 00329 00330 if ((total - avg) <=25 and ARC < 10){ /* No buzzer sound if PPM is under 10 */ 00331 Buzzer.period_us(0); 00332 is_sounding = false; 00333 } 00334 00335 else if ((total - avg) > 25 and (total - avg) < 50 and total < 100 or (ARC >=10 and ARC < 20)) { 00336 if (is_sounding == false){ /* If the buzzer is not triggered, trigger */ 00337 Buzzer.period_us(B_4); /* Period of B4 */ 00338 Buzzer.write(0.50f); /* 50% Duty Cycle on the Tone */ 00339 is_sounding = true; /* Signal that the buzzer is currently triggering */ 00340 } 00341 else { 00342 Buzzer.period_us(0); /* Turn off the buzzer (Period = 0us)*/ 00343 is_sounding = false; /* Signal that the buzzer is no longer triggering */ 00344 } 00345 } 00346 00347 else if ((total - avg) >= 50 or total >= 100 or avg >= 100 or ARC >= 20){ 00348 if (is_sounding == false){ 00349 Buzzer.period_us(B_5); /* Period of B5 */ 00350 Buzzer.write(0.50f); /* 50% Duty Cycle on the Tone */ 00351 is_sounding = true; 00352 } 00353 else { 00354 Buzzer.period_us(0); /* Turn off the buzzer */ 00355 is_sounding = false; 00356 } 00357 } 00358 } 00359 00360 void CalculatePPM(){ /* Function to convert the analog signals to digital based on 16 bit adc steps */ 00361 00362 const double AQ_Rl = 20000.0; // AQ_Rl (20kOhm) - Load resistance for AQ sensor 00363 const double CO_Rl = 18500.0; // CO_Rl (18.5kOhm) - Load resistance for CO sensor 00364 const double Vadc_33 = 0.0000503548; // ADC step 3,3V/65535 0.00503mV (16bit ADC) 00365 //const double Vadc_5 = 5.0/65535; // ADC step 5.0V/2^16 (65535, 16bit ADC) 00366 double Vrl; // Output voltage 00367 double Rs; // Rs (Ohm) - Sensor resistance 00368 double ratio; // Rs/Rl ratio 00369 double lgPPM; 00370 00371 if (aq_total > 65533) //prevents NAN error from overflow of 16 bits 00372 aq_total = 65530; 00373 Vrl = (double)aq_total * Vadc_33; // For 3.3V Vcc use Vadc_33 00374 Rs = AQ_Rl * (3.3 - Vrl)/Vrl; // Calculate sensor resistance 00375 ratio = Rs/AQ_Rl; // Calculate ratio 00376 lgPPM = (log10(ratio) * -0.8) + 0.9; 00377 aq_ppm = 6* pow(10,lgPPM) - 12; // Calculate air quality ppm 00378 00379 if (co_total > 65533) //prevents NAN error from overflow of 16 bits 00380 co_total = 65530; 00381 Vrl = (double)co_total * Vadc_33; // For 3.3V Vcc use Vadc_33 00382 Rs = CO_Rl * (3.3 - Vrl)/Vrl; // Calculate sensor resistance 00383 ratio = Rs/CO_Rl; // Calculate ratio 00384 lgPPM = (log10(ratio) * -0.8) + 0.9; 00385 co_ppm = 6* pow(10,lgPPM) - 12; // Calculate carbon monoxide ppm 00386 00387 if (aq_ppm < 0) 00388 aq_ppm = 0; //prevents underflow 00389 else if (aq_ppm >= 1000) 00390 aq_ppm = 999.99; //prevents overflow 00391 00392 if (co_ppm <0) 00393 co_ppm = 0; 00394 else if (co_ppm >= 1000) 00395 co_ppm = 999.99; 00396 00397 /* Calculate the total */ 00398 total = co_ppm + aq_ppm; 00399 if (total < 0) 00400 total = 0; 00401 else if (total >= 1000) 00402 total = 999.99; 00403 } 00404 00405 void dataQueue() 00406 { /* Beginning of function */ 00407 if (pushIndex != SIZE and !calc){ /* Initially pushing values into the set */ 00408 dataSet[pushIndex] = total; //push value into the queue 00409 sum += dataSet[pushIndex]; //add the value to the sum 00410 pushIndex++; //increment the push index 00411 00412 if (pushIndex == SIZE){ 00413 avg = sum / SIZE; //compute the average once the queue is full 00414 calc = true; //flag calc 00415 ARC = dataSet[SIZE - 1] - dataSet[SIZE - 2]; 00416 pushIndex = 0; //reset the push index back to 0 00417 } 00418 } 00419 00420 else if (pushIndex != SIZE and calc){ /* Pushing values into the set once the set is full */ 00421 sum -= dataSet[pushIndex]; //subtract the value to be overriden from the sum 00422 dataSet[pushIndex] = total; //push the value into the set 00423 sum += dataSet[pushIndex]; //add the value to the sum 00424 avg = sum / SIZE; //compute average 00425 if (pushIndex == 0){ 00426 prev_value = dataSet[SIZE - 1]; 00427 ARC = dataSet[pushIndex] - prev_value; 00428 } 00429 else { 00430 prev_value = dataSet[pushIndex - 1]; 00431 ARC = dataSet[pushIndex] - prev_value; 00432 } 00433 pushIndex++; //increment the push index 00434 00435 if (pushIndex == SIZE) 00436 pushIndex = 0; //reset the push index back to 0 00437 } 00438 00439 } /* End of function */ 00440 00441 void StartHaptic(void) 00442 { 00443 hapticTimer.start(50); 00444 haptic = 1; 00445 } 00446 00447 void StopHaptic(void const *n) { 00448 haptic = 0; 00449 hapticTimer.stop(); 00450 }
Generated on Wed Jul 13 2022 17:48:03 by
1.7.2