Grove pm2.5 sensor HM3301 + SD card

Hi everybody, I’ve to record data from the sensor and record it on an SD card. Differently from other sensors i cannot do that easily using the command dataFile.print() for the variable that was printed on the serial monitor [Serial.print()] due to the codification that i don’t understand.

Sombody can help me?

Thanks very much.

We want to know, what hardware do you use to record data to the SD card? If possible, you can take a picture of the hardware connection diagram for us to see. In addition, if it is convenient, please provide the source code of the program. I would like to ask the engineer to see how to solve it.

Hi! Thanks for the response!

The hardware is an MH-SD Card Module.
I used the SPI and SD library following this tutorial :

https://randomnerdtutorials.com/guide-to-sd-card-module-with-arduino/.

The problem that i found is to identify the target variables to “print” on the dataFile into the codification of the PM2.5 sensor:

#include “Seeed_HM330X.h”

#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

HM330X sensor;
u8 buf[30];

const char *str[]={"sensor num: ","PM1.0 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
"PM2.5 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
"PM10 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
"PM1.0 concentration(Atmospheric environment,unit:ug/m3): ",
"PM2.5 concentration(Atmospheric environment,unit:ug/m3): ",
"PM10 concentration(Atmospheric environment,unit:ug/m3): ",
};

err_t print_result(const char* str,u16 value)
{
if(NULL==str)
return ERROR_PARAM;
SERIAL.print(str);
SERIAL.println(value);
return NO_ERROR;
}

/parse buf with 29 u8-data/
err_t parse_result(u8 *data)
{
u16 value=0;
err_t NO_ERROR;
if(NULL==data)
return ERROR_PARAM;
for(int i=1;i<8;i++)
{
value = (u16)data[i*2]<<8|data[i*2+1];
print_result(str[i-1],value);

}

}

err_t parse_result_value(u8 *data)
{
if(NULL==data)
return ERROR_PARAM;
for(int i=0;i<28;i++)
{
SERIAL.print(data[i],HEX);
SERIAL.print(" “);
if((0==(i)%5)||(0==i))
{
SERIAL.println(” “);
}
}
u8 sum=0;
for(int i=0;i<28;i++)
{
sum+=data[i];
}
if(sum!=data[28])
{
SERIAL.println(“wrong checkSum!!!”);
}
SERIAL.println(” “);
SERIAL.println(” ");
return NO_ERROR;
}

/30s/
void setup()
{
SERIAL.begin(115200);
delay(100);
SERIAL.println(“Serial start”);
if(sensor.init())
{
SERIAL.println(“HM330X init failed!!!”);
while(1);
}

}

void loop()
{
if(sensor.read_sensor_value(buf,29))
{
SERIAL.println(“HM330X read result failed!!!”);
}
parse_result_value(buf);
parse_result(buf);
SERIAL.println(" “);
SERIAL.println(” “);
SERIAL.println(” ");
delay(5000);
}

Hi, ALlpavia
I asked the programmer to make some modifications according to your program and requirements, but because there is no hardware on hand, there is no way to do a complete test, please try it.
I hope these programs can solve your problems.

#include <Seeed_HM330X.h>
#include <SPI.h>
#include <SD.h>

File myFile;

#ifdef  ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL_OUTPUT SerialUSB
#else
#define SERIAL_OUTPUT Serial
#endif

HM330X sensor;
uint8_t buf[30];


const char* str[] = {"sensor num: ", "PM1.0 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
                     "PM2.5 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
                     "PM10 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
                     "PM1.0 concentration(Atmospheric environment,unit:ug/m3): ",
                     "PM2.5 concentration(Atmospheric environment,unit:ug/m3): ",
                     "PM10 concentration(Atmospheric environment,unit:ug/m3): ",
                    };

HM330XErrorCode print_result(const char* str, uint16_t value) {
  if (NULL == str) {
    return ERROR_PARAM;
  }
  SERIAL_OUTPUT.print(str);
  SERIAL_OUTPUT.println(value);
  return NO_ERROR;
}

/*parse buf with 29 uint8_t-data*/
HM330XErrorCode parse_result(uint8_t* data) {
  uint16_t value = 0;
  if (NULL == data) {
    return ERROR_PARAM;
  }
  for (int i = 1; i < 8; i++) {
    value = (uint16_t) data[i * 2] << 8 | data[i * 2 + 1];
    print_result(str[i - 1], value);

  }

  return NO_ERROR;
}

HM330XErrorCode parse_result_value(uint8_t* data) {
  if (NULL == data) {
    return ERROR_PARAM;
  }
  for (int i = 0; i < 28; i++) {
    SERIAL_OUTPUT.print(data[i], HEX);
    SERIAL_OUTPUT.print("  ");
    if ((0 == (i) % 5) || (0 == i)) {
      SERIAL_OUTPUT.println("");
    }
  }
  uint8_t sum = 0;
  for (int i = 0; i < 28; i++) {
    sum += data[i];
  }
  if (sum != data[28]) {
    SERIAL_OUTPUT.println("wrong checkSum!!!!");
  }
  SERIAL_OUTPUT.println("");
  return NO_ERROR;
}


/*30s*/
void setup() {
  SERIAL_OUTPUT.begin(115200);
  delay(100);
  SERIAL_OUTPUT.println("Serial start");
  if (sensor.init()) {
    SERIAL_OUTPUT.println("HM330X init failed!!!");
    while (1);
  }

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    while (1);
  }

}


void loop() {
  File myFile = SD.open("test.txt", FILE_WRITE);
  if (myFile) {
  if (sensor.read_sensor_value(buf, 29)) {
    SERIAL_OUTPUT.println("HM330X read result failed!!!");
  }
  myFile.write(parse_result_value(buf));
  myFile.write(parse_result(buf));
  SERIAL_OUTPUT.println("");
  delay(5000);

  }
}

Hi Liu,

Unfortunatly it didn’t work. It seems to work but then nothing remains written on the text file.

The problem is figuring out what to enter here:

myFile.write(parse_result_value(buf));
myFile.write(parse_result(buf))


Thanks for the support!

Hi ALIpavia

Try this code as a reference, add the buffer data on the SDcard then.

#include <SPI.h>
#include <SD.h>

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {     //accroding you device put your SPI pin number
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File myFile = SD.open("test.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

}

void loop() {
  // nothing happens after setup
}

Best regards
fenyi