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

The device has no upload capabilities. It logs data onto local SD card if one is present. It displays current measurement nevertheless.

/media/uploads/amateusz/screenshot_20180131_132347.png

I used some libraries: some purpose-made, rest forked public libraries. main.cpp file contains the program. First it initializes modules (EEPROM, RTC, thermometer, dust sensor, LCD, SDcard), then enters endless loop of following sequence:

  • take a measurement
  • display measurement and save it to the SD card
  • enter sleep for *sleep* period
  • repeat

Files at this revision

API Documentation at this revision

Comitter:
amateusz
Date:
Wed Jan 31 12:13:30 2018 +0000
Commit message:
last working version the program.; RTC broke before deployment, so it is non functional in program

Changed in this revision

DS1307.lib Show annotated file Show diff for this revision Revisions of this file
DS1820.lib Show annotated file Show diff for this revision Revisions of this file
DSM501.lib Show annotated file Show diff for this revision Revisions of this file
GP2Y1010AU0F.lib Show annotated file Show diff for this revision Revisions of this file
I2CEeprom.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show annotated file Show diff for this revision Revisions of this file
WakeUp.lib Show annotated file Show diff for this revision Revisions of this file
keypad_ADC.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 41f9e684d87e DS1307.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DS1307.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/DS1307/#8c0c306cee03
diff -r 000000000000 -r 41f9e684d87e DS1820.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DS1820.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/DS1820/#1020ba9ab5d2
diff -r 000000000000 -r 41f9e684d87e DSM501.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DSM501.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/DSM501/#2501a0385c68
diff -r 000000000000 -r 41f9e684d87e GP2Y1010AU0F.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GP2Y1010AU0F.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/GP2Y1010AU0F/#f4e3a6f03b9c
diff -r 000000000000 -r 41f9e684d87e I2CEeprom.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2CEeprom.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/I2CEeprom/#b7877755371e
diff -r 000000000000 -r 41f9e684d87e SDFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/SDFileSystem/#aac017a027c0
diff -r 000000000000 -r 41f9e684d87e TextLCD.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/TextLCD_YWROBOT/#6c5cf2a0d238
diff -r 000000000000 -r 41f9e684d87e WakeUp.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WakeUp.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/Sissors/code/WakeUp/#65c04a02ad45
diff -r 000000000000 -r 41f9e684d87e keypad_ADC.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keypad_ADC.lib	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/amateusz/code/keypad_ADC/#9b7cc7ebdffd
diff -r 000000000000 -r 41f9e684d87e main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,388 @@
+#include "mbed.h"
+//#include <errno.h>
+//#include <stdio.h>
+#include "SDFileSystem.h" // sd card
+#include "I2CEeprom.h" // eeprom present on the tinyRTC module
+#include "DS1307.h"
+#include "DS1820.h" // thermometer present on the tinyRTC module
+#include "TextLCD.h" // D1 robot LCD & keypad shield
+#include <string>
+#include <iomanip> // setprecision
+#include <sstream> // stringstream
+#include <algorithm> // replace
+//#include "DSM501.cpp" // dust sensor
+#include "GP2Y1010AU0F.cpp"
+#include "keypad_ADC.cpp" // keys on the shield
+#include "WakeUp.h"
+
+LowPowerTimeout oneSecondTimeout;
+bool oneSecondTimeoutExpired = false;
+
+DS1820 thermometer(PC_9); // rom: wlutowany w płytkę z RTC 0x28ff2b0586160356
+Serial pc(USBTX, USBRX, 57600); // tx, rx  for debug and usb pc comunications
+I2C i2c(PB_9, PB_8);
+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
+//DS1307 rtc(&i2c); // start DS1307 class and give it pins for connections of the DS1307 device
+TextLCD lcd(D8, D9, D4, D5, D6, D7, TextLCD::LCD16x2, D10);
+SDFileSystem sd(PC_12, PC_11, PC_10, PD_2, "sd", NC, SDFileSystem::SWITCH_NONE, 5000000);
+//DSM501 dust(PC_1, PC_0); // vout2, vout1 | blue , yellow od góry
+GP2Y1010AU0F dust(A1, PA_4);
+DigitalOut led(LED1);
+keypad_ADC keys(A0);
+DigitalIn button(USER_BUTTON, PullUp);
+LowPowerTimeout lcdBacklightTimeout;
+
+int lcd_mount(int passthrough)
+{
+    if (passthrough == 0) {
+        lcd.locate(14,0);
+        lcd.putc(7);
+        led = 1;
+    }
+    return passthrough;
+}
+
+int lcd_unmount(int passthrough)
+{
+    if (passthrough == 0) {
+        lcd.locate(14,0);
+        lcd.putc(' ');
+        led = 0;
+    }
+    return passthrough;
+}
+
+void lcdBacklightOff()
+{
+    lcd.setBacklight(TextLCD::LightOff);
+}
+void lcdBacklightOn()
+{
+    lcd.setBacklight(TextLCD::LightOn);
+}
+string floatToString(float value, bool dotToComma, char precision = 2)
+{
+// nice temperature foramting
+    std::ostringstream temperature_str_dot;
+    temperature_str_dot << fixed << setprecision(precision) << value;//thermometer.temperature();
+    std::string temperature_str_comma(temperature_str_dot.str());
+    if (dotToComma) std::replace( temperature_str_comma.begin(), temperature_str_comma.end(), '.', ','); // replace all 'x' to 'y'
+    return temperature_str_comma;
+    // end of temperature
+}
+string intToString(int value, int fillWithZeros = 0)
+{
+    std::ostringstream ss;
+    if (fillWithZeros > 0) ss << setfill('0') << setw(fillWithZeros);
+    ss << value;
+    return ss.str();
+}
+bool write_with_progress_bar(FileHandle* file, const void * buffer, size_t len, void (*everytick)(char) = NULL)
+{
+    char parts=4;
+    char * write_buffer = new char[len];
+    for (unsigned int i = 0; i < len; i++)
+        write_buffer[i] = ((char*)buffer)[i];
+    const size_t chunk_at_once = len/parts;
+    unsigned int data_written = 0;
+    char counter = 0;
+    while (data_written < len) {
+        data_written += file->write(write_buffer + data_written, min(len-data_written, chunk_at_once));
+//        pc.printf("count: %d", counter);
+        if (everytick != NULL)
+            (*everytick)(counter++);
+    }
+    delete write_buffer;
+    if (everytick != NULL)
+        (*everytick)(0); // success, zero it
+    return true;
+}
+
+void showProgress(char value)
+{
+    char posX = 15, posY = 0;
+    lcd.locate(posX, posY);
+    char charToPut = ' ';
+    if (value > 0) {
+        charToPut = value-1 > 3 ? 3 : value -1;
+        // if (value >= 8)
+//            charToPut = 0xFF;
+    }
+    lcd.putc(charToPut);
+    wait(.015);
+}
+void sdInit()
+{
+    sd.crc(true);
+//    sd.large_frames(true);
+    sd.write_validation(false);
+}
+
+void  thermometerInit()
+{
+    thermometer.search_ROM_setup();
+    thermometer.search_ROM();
+    thermometer.set_configuration_bits(12);
+}
+void lcdInit()
+{
+    lcd.setCursor(TextLCD::CurOff_BlkOff);
+    lcd.cls();
+    lcd.setBacklight(TextLCD::LightOn);
+    char progress[][8] = {
+        {0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x7},
+        {0x0, 0x0,0x0,0x0,0x0,0x7,0x7,0x7},
+        {0x0, 0x0,0x0,0x7,0x7,0x7,0x7,0x7},
+        {0x0, 0x7,0x7,0x7,0x7,0x7,0x7,0x7}
+    };
+    for (unsigned int i=0; i <4; i++)
+        lcd.setUDC(i, (char *) progress[i] );
+
+    char microSign[] = {     0b01001,    0b01001,    0b01001,    0b01110,    0b01000,    0b01000, 0b00000,    0b00000};
+    lcd.setUDC(4, (char*) microSign);
+    char gChar[] = {    0b01111,    0b10001,    0b10001,    0b01111,    0b00001,    0b01110, 0b00000,    0b00000};
+    lcd.setUDC(5, (char*) gChar);
+    char m_pow_3[] = {    0b11000,    0b00100,    0b11000,    0b00100,    0b11000,    0b00000,    0b00000,    0b00000};
+    lcd.setUDC(6, (char*) m_pow_3);
+    char microSD[] = {0x1c,0x1c,0x1e,0x1c,0x1e,0x1f,0x1f};
+    lcd.setUDC(7, (char*) microSD);
+}
+//#define USR_POWERDOWN    (0x104)
+//int semihost_powerdown()
+//{
+//    uint32_t arg;
+//    return __semihost(USR_POWERDOWN, &arg);
+//}
+void oneSecondTimeoutCallback(void)
+{
+    oneSecondTimeoutExpired = true;
+}
+
+int main()
+{
+//    semihost_powerdown();
+    sdInit();
+    thermometerInit();
+    lcdInit();
+//    eeprom.write(1, 0); // zero index couter
+    unsigned short measureTime;
+    char temp;
+    eeprom.read(0, temp);
+    eeprom.read(9, measureTime);
+    measureTime <<= 8;
+    measureTime |= temp;
+    if (measureTime < 1) measureTime = 1;
+    //
+//    DS1307::Time_rtc time_now;
+//    rtc.getTime(time_now);
+    lcd.locate(4,1);
+    //if (time_now.hour <= 9)
+//        lcd.printf(" ");
+//    else lcd.printf("%.1D", (time_now.hour/10));
+//    lcd.printf("%.1D:%.2D:%.2D", time_now.hour%10, time_now.min, time_now.sec);
+    lcd.printf("RTC FAIL!");
+    wait(1.0);
+    //
+    lcd.locate(0,0);
+    lcd.printf("karta: ");
+    wait(.7);
+    if (lcd_mount(sd.mount()) == 0) {      //Perform a write test
+        pc.printf("Capacity: %.1fMB\r\n", sd.disk_sectors() / 2048.0);
+        lcd.locate(6,0);
+        lcd.printf("%5dMB",sd.disk_sectors() / 2048);
+        wait(.3);
+        lcd_unmount(sd.unmount());
+    } else lcd.printf("!klops!");
+    wait(1.2);
+    lcdBacklightTimeout.attach(&lcdBacklightOff, 2.0f);
+    lcd.cls();
+//    pc.printf("hello!\r\npress button to start\r\n");
+//    lcd.printf("gotowy. nacisnij");
+    char index;
+    wait(.1);
+    if (eeprom.read(1, index) != 0) {
+        eeprom.write(1, index+1);
+    }
+    else index = 254;
+    std::string filename = intToString(index, 4);
+    filename = filename.substr(1,3);
+    filename +=  ".txt";
+    filename = "pomiary.txt";
+
+    while(true) {
+//        while(button);
+//        rtc.setLocalTime(); // RTC fail
+        time_t current = time(NULL);
+        printf("Time as a basic string = %s\r\n", ctime(&current));
+        // measure dust level
+//        dust.measure(measureTime);
+        unsigned int pm1, pm2_5 = 0;
+        unsigned long epoch_now = time(NULL);
+        thermometer.convert_temperature(false);
+//        while(!dust.getMeasurement(pm1, pm2_5)) {
+
+        while( (signed short) (measureTime - (time(NULL) - epoch_now)) > 0) {
+
+            oneSecondTimeoutExpired = false;
+            oneSecondTimeout.attach(oneSecondTimeoutCallback, 1.0f);
+            //Ensure that we only continue the program flow here after the timeout expired.
+            lcd.locate(15,0);
+            lcd.printf("S");
+            while(!oneSecondTimeoutExpired) sleep();
+            lcd.locate(15,0);
+            lcd.printf(" ");
+//            WakeUp::set_ms(2000);
+//            lcd.locate(15,0);
+//            lcd.printf("S");
+            //Enter deepsleep, the program won't go beyond this point until it is woken up
+//            deepsleep();
+//            lcd.locate(15,0);
+//            lcd.printf(" ");
+
+            keypad_ADC::keys keyPress = keys.read(); // read
+            if (keyPress != keypad_ADC::none) {
+                lcdBacklightOn();
+//                printf("key: %d\r\n", keyPress);
+                if (keyPress == keypad_ADC::right) {
+                    // edit measureTime
+                    lcd.cls();
+                    lcd.locate(8,0);
+                    lcd.printf("%5d?", measureTime);
+                    while (keys.read() != keypad_ADC::none);
+                    keyPress = keys.read();
+                    bool minutesNotSeconds = false;
+                    while (keyPress != keypad_ADC::right) {
+                        lcdBacklightOn();
+                        printf("key: %d\r\n", keyPress);
+                        switch (keyPress) {
+                            case keypad_ADC::left:
+                                minutesNotSeconds = ! minutesNotSeconds;
+                                if(minutesNotSeconds) measureTime /= 60;
+                                else measureTime *= 60;
+                                lcd.locate(8,0);
+                                lcd.printf("%5d", measureTime);
+                                lcd.locate(10,1);
+                                lcd.printf("%s", (minutesNotSeconds)?"min":"sek");
+                                while (keys.read() != keypad_ADC::none);
+                                break;
+                            case keypad_ADC::up:
+                                measureTime++;
+                                if(minutesNotSeconds && measureTime > 1091) measureTime = 0;
+                                lcd.cls();
+                                lcd.locate(8,0);
+                                lcd.printf("%5d", measureTime);
+                                lcd.locate(10,1);
+                                lcd.printf("%s", (minutesNotSeconds)?"min":"sek");
+                                while (keys.read() != keypad_ADC::none);
+                                break;
+                            case keypad_ADC::down:
+                                measureTime--;
+                                if(minutesNotSeconds && measureTime > 1091) measureTime = 1091;
+                                lcd.cls();
+                                lcd.locate(8,0);
+                                lcd.printf("%5d", measureTime);
+                                lcd.locate(10,1);
+                                lcd.printf("%s", (minutesNotSeconds)?"min":"sek");
+                                while (keys.read() != keypad_ADC::none);
+                                break;
+                            default:
+                                break;
+                        }
+                        keyPress = keys.read();
+                    }
+                    if (minutesNotSeconds) measureTime *= 60;
+                    lcd.locate(13,0);
+                    lcd.printf(" ");
+                    eeprom.write(0, measureTime & 0xFF);
+                    eeprom.write(9, measureTime >> 8);
+                    epoch_now = time(NULL);
+//                    dust.measure(measureTime);
+                }
+                while (keys.read() != keypad_ADC::none);
+                lcdBacklightTimeout.attach(&lcdBacklightOff, 2.4);
+            }
+            // display counter
+            lcd.locate(8,0);
+            lcd.printf("%5d", measureTime - (time(NULL) - epoch_now));
+            // print temperature
+            lcd.locate(10,1);//
+            lcd.printf("%s", floatToString(thermometer.temperature(), true).substr(0,4).c_str());
+            lcd.putc(223); // degree sign
+            lcd.putc('C');
+        }
+        lcd.locate(11,0);
+        lcd.printf("  ");
+
+        double result;
+        const unsigned short resultCounter = 100;
+        unsigned short counterAll = 0;
+        unsigned short counterValid = 0;
+        double sum = 0;
+
+        while (counterAll++ < resultCounter) {
+            dust.measure();
+            float resultInterm;
+            while(!dust.getVoltage(resultInterm))
+                pc.printf("%d\r", counterAll);
+            if (dust.convertVoltageToMg(resultInterm) > 0) {
+                sum += resultInterm;
+                counterValid++;
+            }
+            dust.tryTosetAoutAtNoDust(resultInterm);
+            lcd.locate( ((counterAll/48)%2)?1:0 ,0);
+            lcd.printf(" <pomiar> ", result);
+        }
+        pc.printf("%d/%d\r\n", counterAll, counterValid);
+        result = sum/counterValid;
+        result = dust.convertVoltageToMg(result);
+        lcd.cls();
+        lcd.locate(0,0);
+        lcd.printf("%s\n \x04\x05/m\x06", floatToString(result, true, 3));
+//        lcd.printf("pm1:  %2d%%", pm1);
+//        lcd.locate(0,1);
+//        lcd.printf("pm2,5:%2d%%", pm2_5);
+
+        //Mount the filesystem
+        if (lcd_mount(sd.mount()) == 0) {      //Perform a write test
+            printf("\r\nWriting to SD card...");
+            // get global index from eeprom
+            FileHandle* file = sd.open(filename.c_str(), O_WRONLY | O_CREAT ); // | O_TRUNC
+            if (file != NULL) { // write
+                std::string toWrite = ctime(&current);
+                toWrite = toWrite.substr(0, toWrite.size()-1); // cut last char of ctime, because it is \r
+//                toWrite += ", pm1:, ";
+//                toWrite += intToString(pm1).c_str();
+//                toWrite += ", pm2.5:, ";
+//                toWrite += intToString(pm2_5).c_str();
+                toWrite += ", ";
+                toWrite += floatToString(result, false, 4);
+                toWrite += ", ";
+                toWrite += floatToString(dust.getAoutAtNoDust(), false, 5);
+                toWrite += ", ";
+                toWrite += floatToString(thermometer.temperature(), false, 3);
+                toWrite += ", C, ";
+                toWrite += intToString(measureTime);
+                toWrite += ", ";
+                toWrite += intToString(index);
+                toWrite += "\r\n";
+//                pc.printf("tell: %d\tsize: %d\r\n", file->tell(), file->size());
+                pc.printf("Writing to file \"%s\": %s\r\n", filename.c_str(), toWrite.c_str());
+                file->seek(0, SEEK_END);
+                write_with_progress_bar(file, toWrite.c_str(), toWrite.length(), showProgress);
+//            file->write(toWrite.c_str(), toWrite.length()); // strlen(toWrite)
+                file->close();
+                printf("success writing!\r\n");
+            } else {
+                printf("failed to write!\r\n");
+            }
+            //Unmount the filesystem
+            lcd_unmount(sd.unmount());
+
+            pc.printf("all done.\r\n");
+        } else { // unable to mount
+            lcd.locate(0,0);
+            lcd.printf("brak karty!");
+            pc.printf("unable to mount! what a failure!\r\n");
+        }
+    }
+}
diff -r 000000000000 -r 41f9e684d87e mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jan 31 12:13:30 2018 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/mbed_official/code/mbed/builds/a330f0fddbec
\ No newline at end of file