Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/* For a Nano Data Logger logging data from a Plantower 5003 particle sensor
@file NanoVOC7330v1.0.ino
Plantower 5003 code based on https://learn.adafruit.com/pm25-air-quality-sensor/arduino-code
Does not use a library for the Plantower 7003
C. Fastie 11/2018
Jeffrey Yoo Warren 09/2019
*/
#include <SdFat.h> // https://github.com/greiman/SdFat/
#include <SPI.h>
#include <Wire.h>
#include <RTClib.h> // library from https://github.com/adafruit/RTClib
#include <Adafruit_Sensor.h> // https://github.com/adafruit/Adafruit_Sensor
#include <SoftwareSerial.h> // https://github.com/PaulStoffregen/SoftwareSerial
SoftwareSerial pmsSerial(2, 3);
RTC_DS1307 RTC; // The real time clock object is "RTC"
#define DS1307_I2C_ADDRESS 0x68
SdFat SD; // The SdFat object is "SD"
#define MOSIpin 11 // For SD card
#define MISOpin 12 // For SD card
const int chipSelect = 10; // CS pin for the SD card
char tmeStrng[ ] = "0000/00/00,00:00:00"; // a template for a data/time string
long utc;
int cycle = 0;
float n = 60.0; // Number of samples for each average
uint16_t p10 = 0;
uint16_t p25 = 0;
uint16_t p100 = 0;
uint16_t p10v = 0;
uint16_t p25v = 0;
uint16_t p100v = 0;
uint16_t pt03 = 0;
uint16_t pt05 = 0;
uint16_t pt10 = 0;
uint16_t pt25 = 0;
uint16_t pt50 = 0;
uint16_t pt100 = 0;
float p10a = 0.0;
float p25a = 0.0;
float p100a = 0.0;
float p10va = 0.0;
float p25va = 0.0;
float p100va = 0.0;
float pt03a = 0.0;
float pt05a = 0.0;
float pt10a = 0.0;
float pt25a = 0.0;
float pt50a = 0.0;
float pt100a = 0.0;
int led = 3; // Assign LEDPin to a pin number. An LED on this pin will blink after data is saved to SD
void setup() {
pmsSerial.begin(9600); // PMS7003 sensor baud rate is 9600
Serial.begin(9600); // Open serial communications and wait for port to open:
Wire.begin(); // initialize the I2C interface
RTC.begin(); // initialize the RTC
// Uncomment the line below and load the sketch to the Nano to set the RTC time. Then the line must
// be commented out and the sketch loaded again or the time will be wrong.
// RTC.adjust(DateTime((__DATE__), (__TIME__))); //sets the RTC to the time the sketch was compiled.
pinMode(led, OUTPUT); // for the LED on pin "led"
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// initialize and display the status of the SD card:
if (!SD.begin(chipSelect)) {
Serial.println("SD fail");
while(1);
}
Serial.println("SD initialization done.");
//print a header to the data file with column headings
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) { // if the file is available, write to it:
dataFile.println("Date,Time,UTCtime,PM1,PM.2,PM10,PM1env,PM.2env,PM10env,03um,05um,10um,25um,50um,100um");
dataFile.close();
}
struct pms7003data { // define an object for the PMS7003 data
uint16_t framelen;
uint16_t pm10, pm25, pm100;
uint16_t pm10v, pm25v, pm100v;
uint16_t pt03, pt05, pt10, pt25, pt50, pt100;
uint16_t unused;
uint16_t checksum;
};
struct pms7003data data;
void loop()
{
if (readPMSdata(&pmsSerial)) { // if the Plantower 7003 is ready
cycle = cycle + 1; // start accumulating data to compute means
p10 = p10 + data.pm10;
p25 = p25 + data.pm25;
p100 = p100 + data.pm100;
p10v = p10v + data.pm10v;
p25v = p25v + data.pm25v;
p100v = p100v + data.pm100v;
pt03 = pt03 + data.pt03;
pt05 = pt05 + data.pt05;
pt10 = pt10 + data.pt10;
pt25 = pt25 + data.pt25;
pt50 = pt50 + data.pt50;
pt100 = pt100 + data.pt100;
// debugging output to the serial monitor
// Serial.print("PM1a "); Serial.println(p10va);
Serial.println(" PM2.5 "); Serial.println(data.pm25v);
Serial.println(tmeStrng);
// } // end if
// } // end if
} // end if
if (cycle == n) { // if the desired number (n) of sensor readings have been accumulated
cycle = 0; // zero the cycle variable and compute the means
p10a = p10 / n;
p25a = p25 / n;
p100a = p100 / n;
p10va = p10v / n;
p25va = p25v / n;
p100va = p100v / n;
pt03a = pt03 / n;
pt05a = pt05 / n;
pt10a = pt10 / n;
pt25a = pt25 / n;
pt50a = pt50 / n;
pt100a = pt100 / n;
p10 = 0; // zero the variables for the next mean
p25 = 0;
p100 = 0;
p10v = 0;
p25v = 0;
p100v = 0;
pt03 = 0;
pt05 = 0;
pt10 = 0;
pt25 = 0;
pt50 = 0;
pt100 = 0;
// read the time from the RTC
DateTime now = RTC.now();
utc = (now.unixtime());
sprintf(tmeStrng, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); // [added seconds]
// write the data to the SD card:
// if the file is available, write to it:
File dataFile = SD.open("datalog.txt", FILE_WRITE);
dataFile.print(tmeStrng);dataFile.print(",");
dataFile.print(utc);dataFile.print(",");
dataFile.print(p10a);dataFile.print(",");
dataFile.print(p25a);dataFile.print(",");
dataFile.print(p100a);dataFile.print(",");
dataFile.print(p10va);dataFile.print(",");
dataFile.print(p25va);dataFile.print(",");
dataFile.print(p100va);dataFile.print(",");
dataFile.print(pt03a);dataFile.print(",");
dataFile.print(pt05a);dataFile.print(",");
dataFile.print(pt10a);dataFile.print(",");
dataFile.print(pt25a);dataFile.print(",");
dataFile.print(pt50a);dataFile.print(",");
dataFile.println(pt100a);
dataFile.flush(); // make sure SD card writing is done
dataFile.close();
// blink an LED so you don't unplug the device while it is writing to SD card
digitalWrite(led, LOW); // turn the LED on
delay(1000); // wait for a second
digitalWrite(led, HIGH); // turn the LED off
} // end if
} // end of the MAIN LOOP
// Utility code:
// This stuff is usually in a library, but this sketch does not use one
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];
}
// 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("ChkFail");
return false;
}
// success!
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment