In this tutorial, we learn how to interface PMS5003 PM2.5 Air Quality Sensor with Arduino. We will make a simple Arduino Code and measure the dust particle concentration in the air with size and quantity for PM1.0, PM2.5, and PM10. PMS5003 is a kind of digital and universal particle concentration sensor, which can be used to obtain the number of suspended particles in the air, i.e. the concentration of particles, and output of them in the form of digital interface.
Check the advanced version of this project here: IoT Based Air Pollution/Quality Monitoring with ESP8266
Overview
PM2.5 and PM10 refer to particulate matter with particle diameter up to 2.5 microns and 10 microns respectively and are among the most dangerous air pollutants. Due to their small size, PM2.5 particles can travel deep into the human lung and cause a variety of health issues; for instance, by triggering asthma attacks or contributing to cardiovascular disease.
High concentrations of dust or PM is a serious health concern. PM2.5 is less than 2.5 microns in diameter, and PM10 is less than 10 microns in diameter. This means a PM10 report includes PM2.5 as well. Both these particles are much smaller than a human hair, which is about 70 microns in width.
PM10: Operations such as stone crushing, coal grinding, rotary kilning in the cement industry, and dust on road stirred by moving vehicles can increase PM10 levels. PM10 limit for 24-hour average is 150µg/m3.
PM2.5: This is a result of fine particles produced from all types of combustion, including motor vehicles, thermal power plants, residential wood burning, forest fires, agricultural burning, and other industrial processes. PM2.5 limit for 24-hour average is 35µg/m3.
So for measuring the Particulate Matter size of PM1.0, PM2.5 & PM10 we are using Plantpower PMS5003 Dust Sensor. You can also use other Plantpower PMS x003 Sensor like PMS1003, PMS3003, PMS5003, PMS6003 & PMS7003.The code given below supports all these models with Arduino.
Bill of Materials
You need to purchase the following components if you want to make this project. All the components can be saily purchased from Amazon.
| S.N. | Components | Quantity | Purchase Links |
|---|---|---|---|
| 1 | Arduino UNO Board | 1 | Amazon | AliExpress |
| 2 | PMS5003 PM2.5/PM10 Sensor | 1 | Amazon | AliExpress |
| 3 | 20x4 LCD Display | 1 | Amazon | AliExpress |
| 4 | Potentiometer 10K | 1 | Amazon | AliExpress |
| 5 | Connecting Wires | 10 | Amazon | AliExpress |
| 6 | Breadboard | 1 | Amazon | AliExpress |
PMS5003 Air Quality Sensor
Overview
The Plantower PMS5003 is a low-cost laser particle counter, one of a range of sensors by Plantower that also include the PMS1003, PMS3003, and PMS7003. PMS5003 is a kind of digital and universal particle concentration sensor, which can be used to obtain the number of suspended particles in the air, i.e. the concentration of particles, and output them in the form of a digital interface. This sensor can be inserted into variable instruments related to the concentration of suspended particles in the air or other environmental improvement equipment to provide correct concentration data in time.
Working Principle
Laser scattering principle is used for such sensor, i.e. produce scattering by using a laser to radiate suspending particles in the air, then collect scattering light in a certain degree, and finally obtain the curve of scattering light change with time. In the end, equivalent particle diameter and the number of particles with different diameters per unit volume can be calculated by microprocessor-based on MIE theory.
PM5003 Pins
Some of the PM2.5 pins are numbered from left to right as 1, 2, 3……8. But in case of PM5003, the pins are named from right to left. Be careful while connecting PM5003 pins as you might connect it reversely.
| Pin | Function | Description | Remarks |
|---|---|---|---|
| 1 | VCC | Supply voltage 5V | 4.5 – 5.5V |
| 2 | GND | Ground | |
| 3 | SET | HIGH or SUSPENDED – work mode LOW – sleep mode |
3.3V logic |
| 4 | RXD | UART/TTL data recieve | 3.3V logic |
| 5 | TXD | UART/TTL data transmit | 3.3V logic |
| 6 | Reset | LOW to reset | 3.3V logic |
| 7 | NC | Not connected | |
| 8 | NC | Not connected |
Some of the PMSx003 Sensors comes with connectors like shown below:
In case if you don’t have the connector with you, then simply you can cut the connector with the scissors and solder the hard wire that can be inserted easily on Arduino Board or breadboard.
Interfacing PMS5003 PM2.5 Air Quality Sensor with Arduino
The interfacing of PMS5003 with Arduino is pretty easy. You just need 4 connections. Connect PIN1 VCC of PMS5003 to Arduino 5V Pin and PIN2 GND to GND of Arduino. The UART Pin, i.e PIN4 Rx & PIN5 Tx is connected to Arduino pin 3 & 4 respectively as shown in the figure below.
The Plantower sensors output serial data at 9600 baud that can be read by many computers and can be connected to a PC via a USB adaptor such as this USB 2.0 to TTL UART Serial Converter CP2102.
Source Code/Program
The source code for interfacing PM2.5 PMS5003 with Arduino is given below. Simply copy the code and upload to the Arduino UNO Board.
|
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 |
#include <SoftwareSerial.h> SoftwareSerial pmsSerial(2, 3); void setup() { // our debugging output Serial.begin(115200); // sensor baud rate is 9600 pmsSerial.begin(9600); } 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() { 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 > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um); Serial.println("---------------------------------------"); } } 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; } |
Once the code is uploaded, you can open the serial monitor and set the baud rate to 9600. You will see the sensor start collecting the data. The sensor will start giving the correct value after 30 Seconds as it requires to some times to get warm.
Interfacing PMS5003 PM2.5 Air Quality Sensor with Arduino & LCD Dsiplay
The interfacing of PMS5003 with Arduino and LCD Display is pretty easy. You just need 4 connections. Connect PIN1 VCC of PMS5003 to Arduino 5V Pin and PIN2 GND to GND of Arduino. The UART Pin, i.e PIN4 Rx & PIN5 Tx is connected to Arduino pin 3 & 4 respectively as shown in the figure below. For 20×4 LCD Display, connect pin 1, 3, 16 to GND & 2, 15 to VCC 5V. Connect pin 4, 6, 11, 12, 13, 14 of LCD to Arduino 13, 12, 11, 10, 9, 8 Pin. Connect 10K potentiometer at pin 3 of LCD to adjust the contrast.
Source Code/Program
The source code for interfacing PM2.5 PMS5003 Air Quality Sensor with Arduino and LCD Display is given below. Simply copy the code and upload to the Arduino UNO Board.
But before that you need to add the library for PMS5003 Sensor. So simply install the following library from the library manager.
|
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 |
#include "PMS.h" #include "SoftwareSerial.h" #include <LiquidCrystal.h> LiquidCrystal lcd(13, 12, 11, 10, 9, 8); SoftwareSerial Serial1(2, 3); // RX, TX PMS pms(Serial1); PMS::DATA data; void setup() { Serial1.begin(9600); lcd.begin(20,4); lcd.setCursor(0, 0); lcd.print("Warming up"); delay(4000); lcd.clear(); } void loop() { if (pms.read(data)) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Dust Concentration"); lcd.setCursor(0, 1); lcd.print("PM1.0 :" + String(data.PM_AE_UG_1_0) + "(ug/m3)"); lcd.setCursor(0, 2); lcd.print("PM2.5 :" + String(data.PM_AE_UG_2_5) + "(ug/m3)"); lcd.setCursor(0, 3); lcd.print("PM10 :" + String(data.PM_AE_UG_10_0) + "(ug/m3)"); delay(1000); } } |


















47 Comments
Hello,
I’m trying to use this tutorial with a similar sensor ( YEETC CP-15-A4-CG ) and I2C-LCD screen. The problem is that the values are always down to 0, do you know if there is any other similar tutorial for my specific sensor. I’ve tried looking for it on the internet but didn’t found it …
I can send you the computer code, the components, and how i connect the components if you think you will be able to directly help me.
Yours sincerely
Make sure your sensor is getting 5V power supply. The sensor requires high current too.
I suggest you to check once by giving 5V supply from external adapter.
Hi Alex, tried this with newer PMS7003 sensor and getting strange results, most are 10X over values from PM5003. I have adjusted pins to match 5003 and software is the same. Do you have any experience with the 7003? Thanks!
Send me 1 sample of pms7003 to india if you have multiple sensor. I will do the coding and let you know.
Can you tell me what are the differences between standard and environment values
and what does “Particles > 2.5um / 0.1L air: xx” mean?
thank you
Hi,
When I run this code by itself, it works fine. However, when I combine this code with other sensors and breakout boards (e.g. BME280, SD card etc.) I have a checksum failure approx. every 5 seconds. Please could you suggest any problems with this?
Many thanks.
Please remove the delay if you are using any delay function in the code. I was having the same issue.
How can we check if the sensor is connected? If not I would like to print message on LCD.
For the concentration values, it states that they are standard and environmental. Is there a specific unit for the concentration values? Thanks.
micro gram per centimeter cube. You are measuring the PM concentration per unit volume.
i have the same problem, ill add external 5v and values on my arduino leonardo are zeros :/
I get a checksum error, any suggestions?
Can anyone provide a more in-depth explanation of connecting and interfacing the LCD + Breadboard + Arduino. It is very hard to follow the provided picture and the video glances over that part of the process.
Thank you in advance.
I have a problem with the code. It can’t run.
“‘data’ was not declared in this scope”
Hello,
Thank you for the project; actually, I am new to arduino, so I don’t understand most of the part related to “Checksum”. But, I was able to use your code and acquire data from the Plantower sensor.
But, I would like to also connect another PM sensor: Shinyei PD42NS along with the Plantower, to my Arduino. When I am trying to do this I am not able to acquire data from Plantower. Can you kindly help me with this.
Thanks
Vineeth R
Hey bro,
Your project looks very good. I have gone through it and I didn’t understand how you converted the number of suspended particles to weight. Can you please explain that. Did you multiply it with density considering all the particles are in spherical shape.?
thanks in advance bro.
hello , pleaze!!I im noob, and don’t understand this at all, can you tell me how to make 1 relay turn on when 70-100 ppm particles are detected, and the second relay turns on at 100-150 ppm?
Hi,
Your code works very nice with an Arduino Uno or Nano. But on a Mega it doesn’t work. Do you have a solution for the Mega? Thanks for your time
When I open the serial monitor, all I see is a bunch of random looking symbols. They look like this:
K⸮⸮X[-⸮dT[⸮⸮⸮⸮⸮l⸮⸮ڣ⸮(|⸮⸮XG⸮Λ⸮,⸮⸮⸮=df4VhD@T⸮⸮⸮K⸮l⸮⸮(ۛ⸮4>⸮Q⸮A⸮⸮k⸮⸮\’
7⸮p⸮ۛ⸮Kٛi⸮A ⸮ۛX5=I(⸮K⸮K⸮⸮⸮ ⸮[F⸮⸮⸮⸮,⸮⸮l[-⸮dT[⸮⸮⸮⸮⸮l⸮⸮ڣ⸮(|⸮⸮XG⸮Λ⸮,⸮⸮⸮=df4VhD@T⸮⸮⸮K⸮l⸮⸮(ۛ⸮4>⸮Q⸮A⸮⸮k⸮⸮\’
7⸮p⸮ۛ⸮Kٛi⸮A ⸮ۛX5=I(⸮K⸮K⸮⸮⸮ ⸮[F⸮⸮⸮⸮,⸮⸮llқڣel⸮⸮X⸮Cl⸮⸮T⸮dZ;
⸮!ЂDD⸮ٛ⸮K⸮⸮\ ؛⸮⸮⸮=P(⸮K⸮K⸮⸮⸮ ⸮[F⸮⸮⸮⸮⸮,⸮⸮l⸮K⸮⸮⸮H⸮⸮⸮l⸮.IZ⸮⸮k*ɂ\”⸮⸮⸮Z⸮p⸮ۛ⸮⸮⸮l5⸮J)⸮ٛH8Z⸮⸮)⸮ۛ4⸮⸮fb!⸮d⸮⸮!@Lۛ⸮l⸮⸮$⸮”X
Can you help me? What is happing?
Check the baud rate.
it also works on Mega but on different PINs. Have a closer look on SoftwareSerial-Library. I’m using A10 and A11, and it works fine for me.
I guess the difference between standard and environment is that standard is a normed value like ICAO standard atmosphere (15°C, 1013,25 hPa, …) Standard value is interesting because you can compare two or more values on different places.
Any clue on why arduino is not getting any data from the sensor? I can hear the sensor running, but it doesn’t communicate any data to the arduino
Is there any way to save the data in a csv instead of just printing it?
Hello Allam,
Thank you very much for this project, I am trying to build a multi sensor air quality meter, I used your example and now it is desplaying only 0, Other sensors SCD30 and BMP80 are working correctly
Im a a newbie on Arduiino so your help is much appreciated, here is my code:
// SCD30 + bmp280 + pms
#include <Adafruit_SCD30.h>
#include <SoftwareSerial.h>
SoftwareSerial pmsSerial(2,3);
Adafruit_SCD30 scd30;
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BMP280.h>
#define BMP_SCK (13)
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS (10;)
Adafruit_BMP280 bmp;// I2C
void setup(void) {
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println(“Adafruit SCD30, BMP280 Y pms”);
// Try to initialize!
if (!bmp.begin()) {
Serial.println(F(“Could not find a valid BMP280 sensor, check wiring!”));
while (1);
}
if (!scd30.begin()) {
Serial.println(“Failed to find SCD30 chip”);
while (1) {
delay(10);
}
if (!scd30.startContinuousMeasurement()) {
Serial.println(“Failed to set ambient pressure offset”);
while (1) {
delay(10);
}
}
Serial.print(“Ambient pressure offset: “);
Serial.print(scd30.getAmbientPressureOffset());
Serial.println(” mBar”);
}
Serial.println(“SCD30 Found!”);
// if (!scd30.setMeasurementInterval(10)){
// Serial.println(“Failed to set measurement interval”);
// while(1){ delay(10);}
// }
Serial.print(“Measurement Interval: “);
Serial.print(scd30.getMeasurementInterval());
Serial.println(” seconds”);
};
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() {
if (scd30.dataReady()) {
Serial.println(“Data available!”);
scd30.startContinuousMeasurement(bmp.readPressure()/100);
}
}
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 + i2 + 1];
buffer_u16[i] += (buffer[2 + i2] << 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;
delay(2000);
};/*
*/
Heres is what the monitor is showing:
21:29:07.706 -> Data available!
21:29:07.706 -> —————————————
21:29:07.706 -> SCD30Temperature: 25.69 degrees C
21:29:07.706 -> BMP280Temperature = 24.28 *C
21:29:07.706 -> Relative Humidity: 29.17 %
21:29:07.706 -> Pressure = 782.88 mBar
21:29:07.706 -> CO2: 1237.405 ppm
21:29:07.706 -> Approx altitude = 2123.39 m
21:29:07.706 -> 782 mBar
21:29:07.706 -> Concentration Units (standard)
21:29:07.706 -> PM 1.0: 0 PM 2.5: 0 PM 10: 0
21:29:07.706 -> Concentration Units (environmental)
21:29:07.706 -> PM 1.0: 0 PM 2.5: 0 PM 10: 0
21:29:07.706 -> Particles > 0.3um / 0.1L air:0
21:29:07.706 -> Particles > 0.5um / 0.1L air:0
21:29:07.753 -> Particles > 1.0um / 0.1L air:0
21:29:07.753 -> Particles > 2.5um / 0.1L air:0
21:29:07.753 -> Particles > 5.0um / 0.1L air:0
21:29:07.753 -> Particles > 10.0 um / 0.1L air:0
21:29:07.753 -> —————————————
I had the same problem. You have to put 115200 baud like in the screenshot and NOT 9600.
Hi. Did you just change it in the code here?
#include <SoftwareSerial.h>
SoftwareSerial pmsSerial(2, 3);
void setup() {
// our debugging output
Serial.begin(115200);
// sensor baud rate is 9600
pmsSerial.begin(9600);
}
Sir I am trying the same code using same sensor and same pin connection but i couldn’t seen any value or any thing on screen I also change bode plot rate but couldn’t get any value
Sir i used A10 A11 but couldn’t seen any value for Arduino mega also use digital but same problem what i could do
Not all the pins of Arduino mega can be used as software serial. You can only use those pins which accepts interrupt. Check the Arduino Mega documentation to find out which pin supports Software Serial command.
could someone send me the code with the i2c please
Thanks for the tutorial. super simple and easy to follow.
I use the EXP8266 and like many others, got nothing……
what I ASSUMED is to use TX/DX of the microcontroller and not regular digital output pins.
then, I got that X[-⸮dT[⸮⸮⸮⸮⸮l⸮⸮ڣ⸮(|⸮ nonsense……
changed the baud rate on the terminal to 112500, and it worked perfectly !
as a note, II am using the 5v output of the ESP8266, but I do not know if that has enough power to do that safely.
I changed to : SoftwareSerial pmsSerial(D5, D6);
Thank you again for the great tutorial
I was successful in following this tutorial. thanks, it was very well done and easy to follow.
I do have a couple of questions.
there are three sections in the serial display
data.pm10_standard
and
data.pm10_en
and
data.particles_10um
each outputs a different value. I don’t understand the differences and why they are all different.
hi ,this S K from west bengal
sir i am using this code form my project on my PMSA003-C Plantower Sensor it showing nothing please help me
hi ,this S K from west bengal
sir i am using this code form my project on my PMSA003-C Plantower Sensor it showing nothing please help me
Hi Mr: Alam how can i find the libaries for your codes?
Could you share your code, please it doesn’t work for me!!
Did you find the solution of this problem . If yes could you share with me your code (I have the same problem) ?
did you find out whats the difference?
Thank you, your code help me a lot. It was hard to understand it from datasheet in clear way.
You state “Once the code is uploaded, you can open the serial monitor and set the baud rate to 9600”, but i think that is wrong. The connection to the sensor is 9600 baud but the connection to the serial monitor is 115200 baud.
Also, is there any specific reason why in one program you use a pms library and in the other you dont
Buenas
Quisiera saber si quiero guardar la información en un Micro SD con un modulo Micro SD, así como la hora con un Modulo de hora en la cual fue tomada los datos, cual seria el código que colocaría
Gracias de antemano
Bendiciones
Doesnt work. checked & double checked everything. PMS5003 is putting out data, as checked with a scope. The program is just not displaying any readings.
Suddenly started working now 🙂
Hello, thanks for this code.
When I copy pasted this and try to compile, I get this:
“Downloading index: package_index_tar.bz2”
What is this?
– thank you!
(scratch last comment – cancelled the process and started again – compiled and upload)
For a very quick instant, I saw some data, but went to gibberish.
set to 9600 baud
Before I even got anything close to being legible, it was all gibbered before I commented out this setup() line:
// our debugging output
Serial.begin(115200);
What can be happening?
Here’s what I saw…
18:12:43.314 ->
18:12:43.314 -> ———————————-icles > 10.0 um / 0.1L air:0
18:12:43.314 -> —————————————
18:12:43.314 -> 2.5um / 0.1L air:0
18:12:43.314 -> Particles > 5.0um / 0.1L air:0
18:12:43.314 -> Particles > 10.0 um / 0.1L air:0
18:12:43.314 -> —————————————
18:12:45.301 -> 6�_,� �ʛ�9�� ؛�d8L; 0���x�54����ɒK�L�I���̛6��lI�!Ђ3� 3�HFY�l�
18:12:54.840 -> �DP�ћl�Kٛ�,�
…and now I see nothing…