This is some program for air quality monitoring device. Its capabilities span quite a broad range: -read sensor (selection of 2 kinds - both worthless actually) -store measurements on SD card (nice formatting included ®) -display current measurement on LCD -sleep between measurement (but on my Nucleo platform power draw was still unacceptably high) -change measurement interval with on-board keys
Dependencies: DS1307 DS1820 DSM501 GP2Y1010AU0F I2CEeprom SDFileSystem TextLCD_YWROBOT WakeUp keypad_ADC mbed
main.cpp
00001 #include "mbed.h" 00002 //#include <errno.h> 00003 //#include <stdio.h> 00004 #include "SDFileSystem.h" // sd card 00005 #include "I2CEeprom.h" // eeprom present on the tinyRTC module 00006 #include "DS1307.h" 00007 #include "DS1820.h" // thermometer present on the tinyRTC module 00008 #include "TextLCD.h" // D1 robot LCD & keypad shield 00009 #include <string> 00010 #include <iomanip> // setprecision 00011 #include <sstream> // stringstream 00012 #include <algorithm> // replace 00013 //#include "DSM501.cpp" // dust sensor 00014 #include "GP2Y1010AU0F.cpp" 00015 #include "keypad_ADC.cpp" // keys on the shield 00016 #include "WakeUp.h" 00017 00018 LowPowerTimeout oneSecondTimeout; 00019 bool oneSecondTimeoutExpired = false; 00020 00021 DS1820 thermometer(PC_9); // rom: wlutowany w płytkę z RTC 0x28ff2b0586160356 00022 Serial pc(USBTX, USBRX, 57600); // tx, rx for debug and usb pc comunications 00023 I2C i2c(PB_9, PB_8); 00024 I2CEeprom eeprom(&i2c, 0xA0, 1, 4096); // memory map: 0 - interval is [s] for measurement, 1 - file number. auto incremented, 2 - same file (0) or new everytime (1), 9 - measureTime upper byte 00025 //DS1307 rtc(&i2c); // start DS1307 class and give it pins for connections of the DS1307 device 00026 TextLCD lcd(D8, D9, D4, D5, D6, D7, TextLCD::LCD16x2, D10); 00027 SDFileSystem sd(PC_12, PC_11, PC_10, PD_2, "sd", NC, SDFileSystem::SWITCH_NONE, 5000000); 00028 //DSM501 dust(PC_1, PC_0); // vout2, vout1 | blue , yellow od góry 00029 GP2Y1010AU0F dust(A1, PA_4); 00030 DigitalOut led(LED1); 00031 keypad_ADC keys(A0); 00032 DigitalIn button(USER_BUTTON, PullUp); 00033 LowPowerTimeout lcdBacklightTimeout; 00034 00035 int lcd_mount(int passthrough) 00036 { 00037 if (passthrough == 0) { 00038 lcd.locate(14,0); 00039 lcd.putc(7); 00040 led = 1; 00041 } 00042 return passthrough; 00043 } 00044 00045 int lcd_unmount(int passthrough) 00046 { 00047 if (passthrough == 0) { 00048 lcd.locate(14,0); 00049 lcd.putc(' '); 00050 led = 0; 00051 } 00052 return passthrough; 00053 } 00054 00055 void lcdBacklightOff() 00056 { 00057 lcd.setBacklight(TextLCD::LightOff); 00058 } 00059 void lcdBacklightOn() 00060 { 00061 lcd.setBacklight(TextLCD::LightOn); 00062 } 00063 string floatToString(float value, bool dotToComma, char precision = 2) 00064 { 00065 // nice temperature foramting 00066 std::ostringstream temperature_str_dot; 00067 temperature_str_dot << fixed << setprecision(precision) << value;//thermometer.temperature(); 00068 std::string temperature_str_comma(temperature_str_dot.str()); 00069 if (dotToComma) std::replace( temperature_str_comma.begin(), temperature_str_comma.end(), '.', ','); // replace all 'x' to 'y' 00070 return temperature_str_comma; 00071 // end of temperature 00072 } 00073 string intToString(int value, int fillWithZeros = 0) 00074 { 00075 std::ostringstream ss; 00076 if (fillWithZeros > 0) ss << setfill('0') << setw(fillWithZeros); 00077 ss << value; 00078 return ss.str(); 00079 } 00080 bool write_with_progress_bar(FileHandle* file, const void * buffer, size_t len, void (*everytick)(char) = NULL) 00081 { 00082 char parts=4; 00083 char * write_buffer = new char[len]; 00084 for (unsigned int i = 0; i < len; i++) 00085 write_buffer[i] = ((char*)buffer)[i]; 00086 const size_t chunk_at_once = len/parts; 00087 unsigned int data_written = 0; 00088 char counter = 0; 00089 while (data_written < len) { 00090 data_written += file->write(write_buffer + data_written, min(len-data_written, chunk_at_once)); 00091 // pc.printf("count: %d", counter); 00092 if (everytick != NULL) 00093 (*everytick)(counter++); 00094 } 00095 delete write_buffer; 00096 if (everytick != NULL) 00097 (*everytick)(0); // success, zero it 00098 return true; 00099 } 00100 00101 void showProgress(char value) 00102 { 00103 char posX = 15, posY = 0; 00104 lcd.locate(posX, posY); 00105 char charToPut = ' '; 00106 if (value > 0) { 00107 charToPut = value-1 > 3 ? 3 : value -1; 00108 // if (value >= 8) 00109 // charToPut = 0xFF; 00110 } 00111 lcd.putc(charToPut); 00112 wait(.015); 00113 } 00114 void sdInit() 00115 { 00116 sd.crc(true); 00117 // sd.large_frames(true); 00118 sd.write_validation(false); 00119 } 00120 00121 void thermometerInit() 00122 { 00123 thermometer.search_ROM_setup(); 00124 thermometer.search_ROM(); 00125 thermometer.set_configuration_bits(12); 00126 } 00127 void lcdInit() 00128 { 00129 lcd.setCursor(TextLCD::CurOff_BlkOff); 00130 lcd.cls(); 00131 lcd.setBacklight(TextLCD::LightOn); 00132 char progress[][8] = { 00133 {0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x7}, 00134 {0x0, 0x0,0x0,0x0,0x0,0x7,0x7,0x7}, 00135 {0x0, 0x0,0x0,0x7,0x7,0x7,0x7,0x7}, 00136 {0x0, 0x7,0x7,0x7,0x7,0x7,0x7,0x7} 00137 }; 00138 for (unsigned int i=0; i <4; i++) 00139 lcd.setUDC(i, (char *) progress[i] ); 00140 00141 char microSign[] = { 0b01001, 0b01001, 0b01001, 0b01110, 0b01000, 0b01000, 0b00000, 0b00000}; 00142 lcd.setUDC(4, (char*) microSign); 00143 char gChar[] = { 0b01111, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110, 0b00000, 0b00000}; 00144 lcd.setUDC(5, (char*) gChar); 00145 char m_pow_3[] = { 0b11000, 0b00100, 0b11000, 0b00100, 0b11000, 0b00000, 0b00000, 0b00000}; 00146 lcd.setUDC(6, (char*) m_pow_3); 00147 char microSD[] = {0x1c,0x1c,0x1e,0x1c,0x1e,0x1f,0x1f}; 00148 lcd.setUDC(7, (char*) microSD); 00149 } 00150 //#define USR_POWERDOWN (0x104) 00151 //int semihost_powerdown() 00152 //{ 00153 // uint32_t arg; 00154 // return __semihost(USR_POWERDOWN, &arg); 00155 //} 00156 void oneSecondTimeoutCallback(void) 00157 { 00158 oneSecondTimeoutExpired = true; 00159 } 00160 00161 int main() 00162 { 00163 // semihost_powerdown(); 00164 sdInit(); 00165 thermometerInit(); 00166 lcdInit(); 00167 // eeprom.write(1, 0); // zero index couter 00168 unsigned short measureTime; 00169 char temp; 00170 eeprom.read(0, temp); 00171 eeprom.read(9, measureTime); 00172 measureTime <<= 8; 00173 measureTime |= temp; 00174 if (measureTime < 1) measureTime = 1; 00175 // 00176 // DS1307::Time_rtc time_now; 00177 // rtc.getTime(time_now); 00178 lcd.locate(4,1); 00179 //if (time_now.hour <= 9) 00180 // lcd.printf(" "); 00181 // else lcd.printf("%.1D", (time_now.hour/10)); 00182 // lcd.printf("%.1D:%.2D:%.2D", time_now.hour%10, time_now.min, time_now.sec); 00183 lcd.printf("RTC FAIL!"); 00184 wait(1.0); 00185 // 00186 lcd.locate(0,0); 00187 lcd.printf("karta: "); 00188 wait(.7); 00189 if (lcd_mount(sd.mount()) == 0) { //Perform a write test 00190 pc.printf("Capacity: %.1fMB\r\n", sd.disk_sectors() / 2048.0); 00191 lcd.locate(6,0); 00192 lcd.printf("%5dMB",sd.disk_sectors() / 2048); 00193 wait(.3); 00194 lcd_unmount(sd.unmount()); 00195 } else lcd.printf("!klops!"); 00196 wait(1.2); 00197 lcdBacklightTimeout.attach(&lcdBacklightOff, 2.0f); 00198 lcd.cls(); 00199 // pc.printf("hello!\r\npress button to start\r\n"); 00200 // lcd.printf("gotowy. nacisnij"); 00201 char index; 00202 wait(.1); 00203 if (eeprom.read(1, index) != 0) { 00204 eeprom.write(1, index+1); 00205 } 00206 else index = 254; 00207 std::string filename = intToString(index, 4); 00208 filename = filename.substr(1,3); 00209 filename += ".txt"; 00210 filename = "pomiary.txt"; 00211 00212 while(true) { 00213 // while(button); 00214 // rtc.setLocalTime(); // RTC fail 00215 time_t current = time(NULL); 00216 printf("Time as a basic string = %s\r\n", ctime(¤t)); 00217 // measure dust level 00218 // dust.measure(measureTime); 00219 unsigned int pm1, pm2_5 = 0; 00220 unsigned long epoch_now = time(NULL); 00221 thermometer.convert_temperature(false); 00222 // while(!dust.getMeasurement(pm1, pm2_5)) { 00223 00224 while( (signed short) (measureTime - (time(NULL) - epoch_now)) > 0) { 00225 00226 oneSecondTimeoutExpired = false; 00227 oneSecondTimeout.attach(oneSecondTimeoutCallback, 1.0f); 00228 //Ensure that we only continue the program flow here after the timeout expired. 00229 lcd.locate(15,0); 00230 lcd.printf("S"); 00231 while(!oneSecondTimeoutExpired) sleep(); 00232 lcd.locate(15,0); 00233 lcd.printf(" "); 00234 // WakeUp::set_ms(2000); 00235 // lcd.locate(15,0); 00236 // lcd.printf("S"); 00237 //Enter deepsleep, the program won't go beyond this point until it is woken up 00238 // deepsleep(); 00239 // lcd.locate(15,0); 00240 // lcd.printf(" "); 00241 00242 keypad_ADC::keys keyPress = keys.read(); // read 00243 if (keyPress != keypad_ADC::none) { 00244 lcdBacklightOn(); 00245 // printf("key: %d\r\n", keyPress); 00246 if (keyPress == keypad_ADC::right) { 00247 // edit measureTime 00248 lcd.cls(); 00249 lcd.locate(8,0); 00250 lcd.printf("%5d?", measureTime); 00251 while (keys.read() != keypad_ADC::none); 00252 keyPress = keys.read(); 00253 bool minutesNotSeconds = false; 00254 while (keyPress != keypad_ADC::right) { 00255 lcdBacklightOn(); 00256 printf("key: %d\r\n", keyPress); 00257 switch (keyPress) { 00258 case keypad_ADC::left: 00259 minutesNotSeconds = ! minutesNotSeconds; 00260 if(minutesNotSeconds) measureTime /= 60; 00261 else measureTime *= 60; 00262 lcd.locate(8,0); 00263 lcd.printf("%5d", measureTime); 00264 lcd.locate(10,1); 00265 lcd.printf("%s", (minutesNotSeconds)?"min":"sek"); 00266 while (keys.read() != keypad_ADC::none); 00267 break; 00268 case keypad_ADC::up: 00269 measureTime++; 00270 if(minutesNotSeconds && measureTime > 1091) measureTime = 0; 00271 lcd.cls(); 00272 lcd.locate(8,0); 00273 lcd.printf("%5d", measureTime); 00274 lcd.locate(10,1); 00275 lcd.printf("%s", (minutesNotSeconds)?"min":"sek"); 00276 while (keys.read() != keypad_ADC::none); 00277 break; 00278 case keypad_ADC::down: 00279 measureTime--; 00280 if(minutesNotSeconds && measureTime > 1091) measureTime = 1091; 00281 lcd.cls(); 00282 lcd.locate(8,0); 00283 lcd.printf("%5d", measureTime); 00284 lcd.locate(10,1); 00285 lcd.printf("%s", (minutesNotSeconds)?"min":"sek"); 00286 while (keys.read() != keypad_ADC::none); 00287 break; 00288 default: 00289 break; 00290 } 00291 keyPress = keys.read(); 00292 } 00293 if (minutesNotSeconds) measureTime *= 60; 00294 lcd.locate(13,0); 00295 lcd.printf(" "); 00296 eeprom.write(0, measureTime & 0xFF); 00297 eeprom.write(9, measureTime >> 8); 00298 epoch_now = time(NULL); 00299 // dust.measure(measureTime); 00300 } 00301 while (keys.read() != keypad_ADC::none); 00302 lcdBacklightTimeout.attach(&lcdBacklightOff, 2.4); 00303 } 00304 // display counter 00305 lcd.locate(8,0); 00306 lcd.printf("%5d", measureTime - (time(NULL) - epoch_now)); 00307 // print temperature 00308 lcd.locate(10,1);// 00309 lcd.printf("%s", floatToString(thermometer.temperature(), true).substr(0,4).c_str()); 00310 lcd.putc(223); // degree sign 00311 lcd.putc('C'); 00312 } 00313 lcd.locate(11,0); 00314 lcd.printf(" "); 00315 00316 double result; 00317 const unsigned short resultCounter = 100; 00318 unsigned short counterAll = 0; 00319 unsigned short counterValid = 0; 00320 double sum = 0; 00321 00322 while (counterAll++ < resultCounter) { 00323 dust.measure(); 00324 float resultInterm; 00325 while(!dust.getVoltage(resultInterm)) 00326 pc.printf("%d\r", counterAll); 00327 if (dust.convertVoltageToMg(resultInterm) > 0) { 00328 sum += resultInterm; 00329 counterValid++; 00330 } 00331 dust.tryTosetAoutAtNoDust(resultInterm); 00332 lcd.locate( ((counterAll/48)%2)?1:0 ,0); 00333 lcd.printf(" <pomiar> ", result); 00334 } 00335 pc.printf("%d/%d\r\n", counterAll, counterValid); 00336 result = sum/counterValid; 00337 result = dust.convertVoltageToMg(result); 00338 lcd.cls(); 00339 lcd.locate(0,0); 00340 lcd.printf("%s\n \x04\x05/m\x06", floatToString(result, true, 3)); 00341 // lcd.printf("pm1: %2d%%", pm1); 00342 // lcd.locate(0,1); 00343 // lcd.printf("pm2,5:%2d%%", pm2_5); 00344 00345 //Mount the filesystem 00346 if (lcd_mount(sd.mount()) == 0) { //Perform a write test 00347 printf("\r\nWriting to SD card..."); 00348 // get global index from eeprom 00349 FileHandle* file = sd.open(filename.c_str(), O_WRONLY | O_CREAT ); // | O_TRUNC 00350 if (file != NULL) { // write 00351 std::string toWrite = ctime(¤t); 00352 toWrite = toWrite.substr(0, toWrite.size()-1); // cut last char of ctime, because it is \r 00353 // toWrite += ", pm1:, "; 00354 // toWrite += intToString(pm1).c_str(); 00355 // toWrite += ", pm2.5:, "; 00356 // toWrite += intToString(pm2_5).c_str(); 00357 toWrite += ", "; 00358 toWrite += floatToString(result, false, 4); 00359 toWrite += ", "; 00360 toWrite += floatToString(dust.getAoutAtNoDust(), false, 5); 00361 toWrite += ", "; 00362 toWrite += floatToString(thermometer.temperature(), false, 3); 00363 toWrite += ", C, "; 00364 toWrite += intToString(measureTime); 00365 toWrite += ", "; 00366 toWrite += intToString(index); 00367 toWrite += "\r\n"; 00368 // pc.printf("tell: %d\tsize: %d\r\n", file->tell(), file->size()); 00369 pc.printf("Writing to file \"%s\": %s\r\n", filename.c_str(), toWrite.c_str()); 00370 file->seek(0, SEEK_END); 00371 write_with_progress_bar(file, toWrite.c_str(), toWrite.length(), showProgress); 00372 // file->write(toWrite.c_str(), toWrite.length()); // strlen(toWrite) 00373 file->close(); 00374 printf("success writing!\r\n"); 00375 } else { 00376 printf("failed to write!\r\n"); 00377 } 00378 //Unmount the filesystem 00379 lcd_unmount(sd.unmount()); 00380 00381 pc.printf("all done.\r\n"); 00382 } else { // unable to mount 00383 lcd.locate(0,0); 00384 lcd.printf("brak karty!"); 00385 pc.printf("unable to mount! what a failure!\r\n"); 00386 } 00387 } 00388 }
Generated on Wed Jul 20 2022 02:37:16 by 1.7.2