PM2.5 dust sensor : How to set it up correctly?

Hi. I have bought a GP2Y1014AU particulate sensor and connected it to an ESP8266 board. I have used several code templates, like the one I have pasted below, but they all return a reading value equal or close to 0. Does anyone know if dust sensors, to work correctly, need to be placed in an environment without any light sources? Is something missing in the code that prevents to display a correct value?

#define dustPin A0 // Black wire
#define ledPin 2  // White wire

#define ANALOG_VOLTAGE 3.3 // analog top of range

void setup()
{
  Serial.begin(115200);
  while (!Serial) delay(100);
  
  Serial.println("GP2Y1010AU0F Sensor demo");
  pinMode(ledPin, OUTPUT);
}
 
 
void loop()
{
  float output_voltage, dust_density;
  
  digitalWrite(ledPin, LOW); // power on the LED
  delayMicroseconds(280); // Wait 0.28ms according to DS
  // take analog reading
  output_voltage = analogRead(dustPin); 
  delay(1);
  
  digitalWrite(ledPin, HIGH); // turn the LED off

  output_voltage = (output_voltage / 1023) * ANALOG_VOLTAGE;
  dust_density = (0.18 * output_voltage) - 0.1;

  Serial.print("Voltage = ");
  Serial.print(output_voltage);
  Serial.print(",\tDust Density = ");
  Serial.print(dust_density);
  Serial.println(" mg/m3");
  delay(1000);
}

I use small fan over the dust sensor. Made a difference for me in getting anything else but 0's.

I notice you are setting the dust sensor LED to LOW to take a reading. I use HIGH.

Here is how I coded the dust sensor.

void fDoParticleDetector( void * parameter )
{
  /*
    ug/m3     AQI                 Lvl AQ (Air Quality)
    (air Quality Index)
    0-35     0-50                1   Excellent
    35-75    51-100              2   Average
    75-115   101-150             3   Light pollution
    115-150  151-200             4   moderate
    150-250  201-300             5   heavy
    250-500  >=300               6   serious
  */
  float ADbits = 4095.0f;
  float uPvolts = 3.3f;
  float adcValue = 0.0f;
  float dustDensity = 0.0f;
  float Voc = 0.6f; // Set the typical output voltage, when there is zero dust.
  const float K = 0.5f; // Use the typical sensitivity in units of V per 100ug/m3.
  xEventGroupWaitBits (eg, evtWaitForBME, pdTRUE, pdTRUE, portMAX_DELAY );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 100; //delay for mS
  for (;;)
  {
    //enable sensor led
    gpio_set_level( GPIO_NUM_4, HIGH ); // set gpio 4 to high to turn on sensor internal led for measurement
    esp_timer_start_once( oneshot_timer, 280 ); // trigger one shot timer for a 280uS timeout, warm up time.
    xEventGroupWaitBits (eg, evtDoParticleRead, pdTRUE, pdTRUE, portMAX_DELAY ); // event will be triggered by the timer expiring, wait here for the 280uS
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading from the dust sensor
    gpio_set_level( GPIO_NUM_4, LOW );//Shut off the sensor LED
    adcValue = ( adcValue * uPvolts ) / ADbits; //calculate voltage
    dustDensity = (adcValue / K) * 100.0; //convert volts to dust density
    if ( dustDensity < 0.0f )
    {
      dustDensity = 0.00f; // make negative values a 0
    }
    if ( xSemaphoreTake( sema_PublishPM, 0 ) == pdTRUE )  // don't wait for semaphore to be available
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
      //log_i( "ADC volts %f Dust Density = %ug / m3 ", adcValue, dustDensity ); // print the calculated voltage and dustdensity
      MQTTclient.publish( topicInsidePM, String(dustDensity).c_str() );
      xSemaphoreGive( sema_MQTT_KeepAlive );
      x_eData.PM2 = dustDensity;
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( " high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}// end fDoParticleDetector()

If it helps

No idea.

Not difficult to check though ?

Do you get similar readings when its night time and all the lights are off ?

What happens to the readings if you put the sensor in a light proof bag ?

Etc.

Thanks for the tip. I'll definitely try to put a fan next to it. I have also used your code and it seems to return normal readings already. The sensor instructions also said to connect it to the 5V pin, so I changed that in the code too.

void loop()
{

  float ADbits = 4095.0f;
  float uPvolts = 5.0f;
  float adcRawValue = 0.0f;
  float dustDensity = 0.0f;
  const float K = 0.5f;
  
  digitalWrite(ledPin, HIGH); // power on the LED
  delayMicroseconds(280); // Wait 0.28ms according to DS
  // take analog reading
  adcRawValue = analogRead(dustPin); 
  delay(1);
  
  digitalWrite(ledPin, LOW); // turn the LED off

  adcRawValue = ( adcRawValue * uPvolts ) / ADbits;
  dustDensity = (adcRawValue / K) * 100.0;

  if ( dustDensity < 0.0f )
    {
      dustDensity = 0.00f; // make negative values a 0
    }

  Serial.print("Voltage = ");
  Serial.print(adcRawValue);
  Serial.print(",\tDust Density = ");
  Serial.print(dustDensity);
  Serial.println(" mg/m3");
  delay(1000);
}
1 Like

I'd move those out of loop.

  float ADbits = 4095.0f;
  float uPvolts = 5.0f;
  float adcRawValue = 0.0f;
  float dustDensity = 0.0f;
  const float K = 0.5f;

unsigned long readingInterval= 1000;
unsigned long timePast=millis();

void loop()
{

if( (millis()-timePast) >= readingInterval )
{
  
  digitalWrite(ledPin, HIGH); // power on the LED
  delayMicroseconds(280); // Wait 0.28ms according to DS
  // take analog reading
  adcRawValue = analogRead(dustPin); 
  delay(1);
  
  digitalWrite(ledPin, LOW); // turn the LED off

  adcRawValue = ( adcRawValue * uPvolts ) / ADbits;
  dustDensity = (adcRawValue / K) * 100.0;

  if ( dustDensity < 0.0f )
    {
      dustDensity = 0.00f; // make negative values a 0
    }

  Serial.print("Voltage = ");
  Serial.print(adcRawValue);
  Serial.print(",\tDust Density = ");
  Serial.print(dustDensity);
  Serial.println(" mg/m3");
timePast=millis();
} 
// delay(1000);
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.