I have a PM10 sensor that I'd like to get the values from.

Here's the official documentation from the sensor:  Sensor documentation

I've looked as serial communication, but how do i process byte by byte of information if it's coming in byte at a time?

I'm looking at this example:

void setup() {
  Serial.println("<Arduino is ready>");

void loop() {

void recvOneChar() {
  if (Serial.available() > 0) {
    receivedChar = Serial.read();
    newData = true;

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    newData = false;

Ideally, i'd like to get the PM2 and PM10 values and print them out.

1 Answer 1


The proper method of receiving this kind of data is to use a sliding window. That is you visualise the stream of bytes as just that - a stream of bytes (think letters on paper tape). You then have a conceptual "window" on that data which is the width of the packet (10 bytes in this case). As the data passes behind the window you see just 10 bytes of it. When that 10 bytes is in the "right" format (that is, it starts with 0xAA, ends with 0xAB and the checksum is valid) then you have a valid packet and can read the values from it.

The simplest method of implementing that is with a 10-byte array. As a byte arrives on the serial port you shuffle all the bytes down the array to make room for the new byte at the top of the array. Once 10 bytes have arrived that first byte should now have made its way to the bottom of the array.

For instance:

uint8_t window[10];

void setup() {

void loop() {
    if (Serial.available()) {
        // Slide the window
        for (uint8_t i = 0; i < 9; i++) {
            window[i] = window[i + 1];
        // Add the new character
        window[9] = Serial.read();

        // Output the current window data for debugging

        // Check the framing characters
        if ((window[0] == 0xAA) && (window[9] == 0xAC)) {
            // Calculate the checksum
            uint8_t cs = 0;
            for (uint8_t i = 2; i < 8; i++) {
                cs += window[i];
            // If the checksum matches...
            if (cs == window[8]) {
                // ...we have a valid packet!

void dumpWin() {
    for (int i = 0; i < 10; i++) {
        Serial.print(window[i], HEX);
        Serial.print(" ");

Getting the data out of the valid packet is now a case of combining bytes into 16-bit integers then dividing them into floats. For instance the PM2.5 would be:

uint16_t pm25i = (window[3] << 8) | window[2];
float pm25 = (float)pm25i / 10.0;

The PM10 would be the same but with window[5] and window[4] of course.

Since you can't really use the hardware UART for both communication with your sensor and communication with the PC you may want to investigate the use of SoftwareSerial instead of the hardware UART pins for communicating with the sensor.

  • Amazing stuff! Great work!
    – R0b0tn1k
    Commented Jan 22, 2016 at 18:22
  • However, i'm having an issue, it never reached the IF condition, so i did some debugging: Serial.print(window[0]); Serial.print("="); Serial.print(window[9]); Serial.println(); And it's returning some weird results: 0=170 0=192 0=85 0=1 0=115 0=1 Shouldnt the first number be a byte? Shouldnt the second one be static as well? Why is the second number changing for each row?
    – R0b0tn1k
    Commented Jan 22, 2016 at 18:24
  • You might be better off dumping the whole window each time. I'll add a little function to do that.
    – Majenko
    Commented Jan 22, 2016 at 19:00
  • 1
    @R0b0tn1k By the way, 170 is 0xAA - the first number in the = will change to 170 when it finally reaches the bottom of the window (10 characters have been received).
    – Majenko
    Commented Jan 22, 2016 at 19:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.