Arduino Dust Sensor

Put together a Arduino-based dust sensor over the weekend using the following components:
- Arduino Mega 2560
- Shinyei PPD42NS dust sensor
- LCD Shield (16 x 2)
The codes and wiring instructions for Arduino Mega 2560 and Shinyei PPD42NS is as follow. However, I did include Serial output so you can view the sampling results using Arduino IDE’s Serial Monitor (9600 bauds).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /**********************************************/ /* Building Arduino Dust Sensor using: */ /* - Arduino Mega 2560 */ /* - Shinyei PPD42NS */ /* http://www.sca-shinyei.com/pdf/PPD42NS.pdf */ /* */ /* Author: shadowandy[dot]sg[at]gmail[dot]com */ /* Web: www.shadowandy.net */ /* */ /* Wiring Instruction: */ /* - PPD42NS Pin 1 => GND */ /* - PPD42NS Pin 2 => D51 */ /* - PPD42NS Pin 3 => 5V */ /* - PPD42NS Pin 4 => D50 */ /**********************************************/ #include <LiquidCrystal.h> LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7); byte nano[8] = {B00000,B00000,B00000,B10010,B10010,B10010,B11110,B10000}; byte pow3[8] = {B11000,B00100,B11000,B00100,B11000,B00000,B00000,B00000}; #include <avr/wdt.h> #define PM25 0 #define PM10 1 int pin[] = {50,51}; unsigned long starttime; unsigned long sampletime_ms = 30000; unsigned long triggerOn[2]; unsigned long triggerOff[2]; unsigned long lowpulseoccupancy[] = {0,0}; float ratio[] = {0,0}; float count[] = {0,0}; boolean value[] = {HIGH,HIGH}; boolean trigger[] = {false, false}; void setup() { lcd.createChar(0,nano); lcd.createChar(1,pow3); lcd.begin(16, 2); Serial.begin(9600); //Output to Serial at 9600 baud pinMode(pin[PM25],INPUT); //Listen at the designated PIN wdt_enable(WDTO_8S); starttime = millis(); //Fetching the current time } void loop() { value[PM25] = digitalRead(pin[PM25]); value[PM10] = digitalRead(pin[PM10]); if(value[PM25] == LOW && trigger[PM25] == false) { trigger[PM25] = true; triggerOn[PM25] = micros(); } if(value[PM25] == HIGH && trigger[PM25] == true) { triggerOff[PM25] = micros(); lowpulseoccupancy[PM25] += (triggerOff[PM25] - triggerOn[PM25]); trigger[PM25] = false; } if(value[PM10] == LOW && trigger[PM10] == false) { trigger[PM10] = true; triggerOn[PM10] = micros(); } if(value[PM10] == HIGH && trigger[PM10] == true) { triggerOff[PM10] = micros(); lowpulseoccupancy[PM10] += (triggerOff[PM10] - triggerOn[PM10]); trigger[PM10] = false; } wdt_reset(); if ((millis()-starttime) > sampletime_ms)//Checking if it is time to sample { ratio[PM25] = lowpulseoccupancy[PM25]/(sampletime_ms*10.0); count[PM25] = 1.1*pow(ratio[PM25],3)-3.8*pow(ratio[PM25],2)+520*ratio[PM25]+0.62; ratio[PM10] = lowpulseoccupancy[PM10]/(sampletime_ms*10.0); count[PM10] = 1.1*pow(ratio[PM10],3)-3.8*pow(ratio[PM10],2)+520*ratio[PM10]+0.62; count[PM25] -= count[PM10]; // Begin mass concentration calculation float concentration[] = {0,0}; double pi = 3.14159; double density = 1.65*pow(10,12); double K = 3531.5; // PM10 double r10 = 2.6*pow(10,-6); double vol10 = (4/3)*pi*pow(r10,3); double mass10 = density*vol10; concentration[PM10] = (count[PM10])*K*mass10; // PM2.5 double r25 = 0.44*pow(10,-6); double vol25 = (4/3)*pi*pow(r25,3); double mass25 = density*vol25; concentration[PM25] = (count[PM25])*K*mass25; // End of mass concentration calculation // Begin printing to Serial Serial.print("PM10 : "); Serial.print(concentration[PM10]); Serial.println(" ug/m3"); Serial.print("PM10 Count : "); Serial.print(count[PM10]); Serial.println(" pt/cf"); Serial.print("PM2.5 : "); Serial.print(concentration[PM25]); Serial.println(" ug/m3"); Serial.print("PM2.5 Count: "); Serial.print(count[PM25]); Serial.println(" pt/cf"); Serial.println(""); // Begin printing to LCD lcd.clear(); lcd.print("10 : "); lcd.print(concentration[PM10]); lcd.setCursor(11,0); lcd.write(byte(0)); lcd.print("g/m"); lcd.write(byte(1)); lcd.setCursor(0,1); lcd.print("2.5: "); lcd.print(concentration[PM25]); lcd.setCursor(11,1); lcd.write(byte(0)); lcd.print("g/m"); lcd.write(byte(1)); // Resetting for next sampling lowpulseoccupancy[PM25] = 0; lowpulseoccupancy[PM10] = 0; starttime = millis(); wdt_reset(); } } |
Miscellaneous

With the PM2.5 and PM10 concentration level, we can determine the respective Pollutant Standards Index (PSI) level. The above table is from this document on Calculation of Pollutant Standards Index (PSI).