PMS5003 dust monitor on an Arduino Uno
A PMS5003 laser particle sensor sends PM1.0, PM2.5 and PM10 as serial frames, and the Uno shows them on an LCD with an air quality grade. Drag the dust sliders. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 15 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $46. On Mokxi they're free.
What you'll learn
- Sensors
- Using the Air quality sensor
- Using the Character LCD with I2C backpack
- Difficulty: Intermediate
- Time: About 15 minutes
- Board: Arduino Uno R3
- Parts: 4
How it works
A PMS5003 laser particle sensor sends PM1.0, PM2.5 and PM10 as serial frames, and the Uno shows them on an LCD with an air quality grade. Drag the dust sliders.
Arduino Uno R3 runs the sketch below. The circuit around it: Air quality sensor, PMS5003, Character LCD with I2C backpack. Serial.begin opens the serial port at 115200 baud.
Parts list
4 parts, plus the jumper wires. They retail for about $46; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Air quality sensor, PMS5003
- 1 × Power, 5 V
- 1 × Character LCD with I2C backpackIn Claw Machine Kit, Vending Machine Kit, Rhythm Game Kit.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Air quality sensor, PMS5003 pin GND | Arduino Uno R3 pin GND |
| Air quality sensor, PMS5003 pin RX | Arduino Uno R3 pin 3 |
| Air quality sensor, PMS5003 pin TX | Arduino Uno R3 pin 2 |
| Air quality sensor, PMS5003 pin VCC | Arduino Uno R3 pin 5V |
| Character LCD with I2C backpack pin GND | Arduino Uno R3 pin GND |
| Character LCD with I2C backpack pin SDA | Arduino Uno R3 pin A4 |
| Character LCD with I2C backpack pin SCL | Arduino Uno R3 pin A5 |
| Character LCD with I2C backpack pin VCC | 5 V |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Dust monitor: a Plantower PMS5003 laser particle sensor and a 16x2 I2C LCD.
//
// PMS5003 TX -> pin 2 PMS5003 RX <- pin 3 VCC -> 5 V GND -> GND
// LCD SDA -> A4 SCL -> A5 VCC -> 5 V GND -> GND
//
// The sensor sends a 32 byte frame at 9600 baud about every two seconds: PM1.0,
// PM2.5 and PM10 in micrograms per cubic meter. The PMS library takes the
// frame one byte per read() call, so loop() calls it as often as it can and
// does the printing only when a whole frame has arrived.
//
// The second line grades the PM2.5 with the US EPA's 24 hour bands: Good up to
// 12, Moderate up to 35, "Unhealthy SG" (sensitive groups) up to 55, Unhealthy
// over that. A real room needs the 30 seconds the sensor asks for after power
// on before its numbers settle; here the first frame is already right.
//
// Drag the PM2.5 slider on the sensor and watch the grade change.
#include <LiquidCrystal_I2C.h>
#include <PMS.h>
#include <SoftwareSerial.h>
SoftwareSerial pmsSerial(2, 3); // RX (the sensor's TX), TX (the sensor's RX)
PMS pms(pmsSerial);
PMS::DATA data;
LiquidCrystal_I2C lcd(0x27, 16, 2);
const char *grade(uint16_t pm25) {
if (pm25 <= 12) return "Good";
if (pm25 <= 35) return "Moderate";
if (pm25 <= 55) return "Unhealthy SG";
return "Unhealthy";
}
void setup() {
Serial.begin(115200);
pmsSerial.begin(PMS::BAUD_RATE);
lcd.init();
lcd.backlight();
lcd.print("Waiting for PMS");
Serial.println("PMS5003 dust monitor");
}
void loop() {
if (!pms.read(data)) return;
Serial.print("PM1.0 "); Serial.print(data.PM_AE_UG_1_0);
Serial.print(" PM2.5 "); Serial.print(data.PM_AE_UG_2_5);
Serial.print(" PM10 "); Serial.println(data.PM_AE_UG_10_0);
lcd.clear();
lcd.print("PM2.5 ");
lcd.print(data.PM_AE_UG_2_5);
lcd.print(" PM10 ");
lcd.print(data.PM_AE_UG_10_0);
lcd.setCursor(0, 1);
lcd.print(grade(data.PM_AE_UG_2_5));
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
Runs once when the board starts. It gets the pins and libraries ready.
void setup() {
Serial.begin(115200);
pmsSerial.begin(PMS::BAUD_RATE);
lcd.init();
lcd.backlight();
lcd.print("Waiting for PMS");
Serial.println("PMS5003 dust monitor");
}loop sketch.ino
Runs over and over for as long as the board has power. This is where the project does its work.
void loop() {
if (!pms.read(data)) return;
Serial.print("PM1.0 "); Serial.print(data.PM_AE_UG_1_0);
Serial.print(" PM2.5 "); Serial.print(data.PM_AE_UG_2_5);
Serial.print(" PM10 "); Serial.println(data.PM_AE_UG_10_0);
lcd.clear();
lcd.print("PM2.5 ");
lcd.print(data.PM_AE_UG_2_5);
lcd.print(" PM10 ");
lcd.print(data.PM_AE_UG_10_0);
lcd.setCursor(0, 1);
lcd.print(grade(data.PM_AE_UG_2_5));
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The screen stays blank or shows only a row of blocks. Character LCD with I2C backpack
The I2C address is usually 0x27 or 0x3F. Run an I2C scanner to find yours. Then turn the contrast trimmer on the backpack slowly until text appears. - The backlight is on but there is no text, or text is garbled. Character LCD with I2C backpack
Wire SDA and SCL to the right pins (A4 and A5 on an Uno), power it from 5 V, and call lcd.init() and the backlight call in setup. - Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected. - Pins misbehave or the board resets when you power motors or servos from it. Arduino Uno R3
Each I/O pin gives about 20 mA, 40 mA max. Power motors and servos from their own supply and join its ground to the Uno's GND.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.