// LCD libraries #include // used for LCD screen (SDA/SCL) #include // The shield uses the I2C SCL and SDA pins. On classic Arduinos // this is Analog 4 and 5 so you can't use those for analogRead() anymore // However, you can connect other I2C sensors to the I2C bus and share // the I2C bus. Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield(); // Serial communications for GPS and air quality monitor #include // serial peripheral interface used for serial communications bewteen MEGA and // GPS (Serial1), air quality monitor (Serial2) // Data logger library #include // used by datalogger #include "RTClib.h" // used by datalogger // Serial connection for air quality monitor #define pmsSerial Serial2 // green wire from PMS5003 goes to pin 17 on Mega // purple goes to 5V // orange goes to negative // Time and tracking on SD card RTC_DS1307 rtc; // char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; const int chipSelect = 53; //for MEGA; use 10 for Arduino UNO File dataFile; void setup() { // our debugging output Serial.begin(9600); // sensor baud rate is 9600 pmsSerial.begin(9600); // set up the LCD's number of columns and rows: lcd.begin(16, 2); lcd.print("Hello World"); delay(1000); Serial.print("Initializing SD card..."); // make sure that the default chip select pin is set to // output, even if you don't use it: pinMode(chipSelect, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { Serial.println("Card failed, or not present"); // don't do anything more: while (1) ; } Serial.println("card initialized."); // Open up the file we're going to log to! dataFile = SD.open("datalog.txt", FILE_WRITE); // will create the file if it doesn't exist if (! dataFile) { Serial.println("error opening datalog.txt"); // Wait forever since we can't write data while (1) ; } if (! rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); // Wait forever since we can't log timestamp } } //////////////////////// struct pms5003data { uint16_t framelen; uint16_t pm10_standard, pm25_standard, pm100_standard; uint16_t pm10_env, pm25_env, pm100_env; uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um; uint16_t unused; uint16_t checksum; }; struct pms5003data data; ///////////////////////// void loop() { lcd.clear(); if (readPMSdata(&pmsSerial)) { // reading data was successful! /* Serial.println(); Serial.println("---------------------------------------"); Serial.println("Concentration Units (standard)"); Serial.print("PM 1.0: "); Serial.print(data.pm10_standard); Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard); Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard); Serial.println("---------------------------------------"); Serial.println("Concentration Units (environmental)"); Serial.print("PM 1.0: "); Serial.print(data.pm10_env); Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env); Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env); Serial.println("---------------------------------------"); Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um); Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um); Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um); Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um); Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um); Serial.print("Particles > 50 um / 0.1L air:"); Serial.println(data.particles_100um); Serial.println("---------------------------------------"); } */ // Now, for the datalogger DateTime now = rtc.now(); // make a string for assembling the data to log: String dataString = ""; // air-quality data dataString += String(data.pm100_env); dataString += String(","); dataString += String(data.pm25_env); dataString += String(","); dataString += String(data.pm10_env); lcd.print("PM10,PM2.5,PM1.0"); lcd.setCursor(0, 1); lcd.print(dataString); // date-time data /* dataString += String(now.year(), DEC); dataString += String('/'); dataString += String(now.month(), DEC); dataString += String('/'); dataString += String(now.day(), DEC); dataString += String(" ("); dataString += String(daysOfTheWeek[now.dayOfTheWeek()]); dataString += String(") "); dataString += String(","); */ dataString += String(" at : "); dataString += String(now.hour(), DEC); dataString += String(':'); dataString += String(now.minute(), DEC); dataString += String(':'); dataString += String(now.second(), DEC); dataFile.println(dataString); // dataFile.flush() will 'save' the file to the SD card after every // line of data - this will use more power and slow down how much data // you can read but it's safer! // If you want to speed up the system, remove the call to flush() and it // will save the file only every 512 bytes - every time a sector on the // SD card is filled with data. dataFile.flush(); // print our dataString to the serial port too: Serial.println(dataString); // Take 1 measurement every 5 seconds delay(5000); } } boolean readPMSdata(Stream *s) { if (! s->available()) { return false; } // Read a byte at a time until we get to the special '0x42' start-byte if (s->peek() != 0x42) { s->read(); return false; } // Now read all 32 bytes if (s->available() < 32) { return false; } uint8_t buffer[32]; uint16_t sum = 0; s->readBytes(buffer, 32); // get checksum ready for (uint8_t i=0; i<30; i++) { sum += buffer[i]; } // debugging // for (uint8_t i=2; i<32; i++) { // Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); //} // Serial.println(); // // The data comes in endian'd, this solves it so it works on all platforms uint16_t buffer_u16[15]; for (uint8_t i=0; i<15; i++) { buffer_u16[i] = buffer[2 + i*2 + 1]; buffer_u16[i] += (buffer[2 + i*2] << 8); } // put it into a nice struct :) memcpy((void *)&data, (void *)buffer_u16, 30); if (sum != data.checksum) { Serial.println("Checksum failure"); return false; } // success! return true; }