Duty cycling mode
What this example shows
Saving power by letting the sensor measure only now and then. In duty cycling mode the BMV080 measures, sleeps for the rest of a period you set, and delivers one reading per period. This example sets a 20 second period and prints PM2.5 each time a reading arrives.
The trade-off is in the datasheet: duty cycling always uses the fast response measurement algorithm, and the precision figures for continuous mode do not apply to it. The period has to be at least 2 seconds longer than the integration time, which is 10 seconds by default.
The example code
This is DutyCycle.ino from the pinned library, without its header comment.
The sketch itself is exactly as shipped. It uses the board's default address,
0x57.
#include "BMV080-SOLDERED.h"
BMV080 bmv080; // Create an instance of the BMV080 class
#define BMV080_ADDR 0x57 // BMV080 default address
void setup()
{
Serial.begin(115200);
while (!Serial) delay(10); // Wait for Serial to become available
Wire.begin();
// Attempt to initialize the sensor via I2C
if (bmv080.begin(BMV080_ADDR, Wire) == false)
{
Serial.println("BMV080 not detected");
while (1)
;
}
Serial.println("BMV080 found!");
// Initialize the sensor
if (bmv080.init())
{
Serial.println("BMV sensor initialized");
}
else
{
Serial.println("BMV initialization failed");
while (1)
;
}
// Set the sensor Duty Cycling Period (seconds)
uint16_t duty_cycling_period = 20;
if(bmv080.setDutyCyclingPeriod(duty_cycling_period) == true)
{
Serial.println("BMV080 set to 20 second duty cycle period.");
}
else
{
Serial.println("Error setting BMV080 duty cycle period.");
}
// Set the sensor mode to Duty Cycle mode
if(bmv080.setMode(BMV080_MODE_DUTY_CYCLE) == true)
{
Serial.println("BMV080 set to Duty Cycle mode");
}
else
{
Serial.println("Error setting BMV080 mode");
}
}
void loop()
{
// Attempt to get reading
if (bmv080.readSensor())
{
float pm25 = bmv080.PM25();
Serial.print(pm25);
if (bmv080.isObstructed() == true)
{
Serial.print("\tObstructed");
}
Serial.println();
}
delay(1000);
}
Expected result, from a bench run on this board (the run did not record which controller it used):
BMV080 found!
BMV sensor initialized
BMV080 set to 20 second duty cycle period.
BMV080 set to Duty Cycle mode
7.31
7.08
6.94
After the setup lines comes one line per period, about every 20 seconds, with
the PM2.5 value in µg/m³ on its own, followed by Obstructed when the sensor's
view is blocked. Your numbers depend on the air around the sensor.
Functions used
BMV080()returns NoneCreates the sensor object. It takes no arguments: the address and the Wire port are given to begin().
ReturnsConstructor; no return value.
begin(const uint8_t address = BMV080_DEFAULT_ADDRESS, TwoWire &wirePort = Wire)returns boolSets the I2C address and Wire port the library uses and checks that the sensor answers at that address. It does not start the I2C bus, so call Wire.begin() first, as the example does.
Returnstrue when the sensor answered at the address, false otherwise.
Parameters
| Name | Type | Description |
|---|---|---|
address | uint8_t | The sensor's I2C address. Defaults to BMV080_DEFAULT_ADDRESS, which is 0x57, the board's default. |
wirePort | TwoWire & | The I2C port to use. Defaults to Wire. |
init()returns boolPrepares the sensor through the Bosch driver: reads the driver version, opens the sensor, performs a soft reset and reads the sensor's ID. Call it after begin() and before anything else.
Returnstrue when every step succeeded, false when one failed.
setDutyCyclingPeriod(uint16_t duty_cycling_period)returns boolSets how long one duty cycle lasts: the measuring time plus the sleep time. Call it before setMode(), because the sensor takes its settings when the measurement starts. The Bosch default is 30 seconds.
Returnstrue when the period was set, false otherwise.
Parameters
| Name | Type | Description |
|---|---|---|
duty_cycling_period | uint16_t | The period in seconds. It must be at least 2 seconds longer than the integration time. |
setMode(uint8_t mode)returns boolStarts measuring in the mode you choose. In duty cycling mode the library gives the Bosch driver millis() as its clock.
Returnstrue when the Bosch driver started the measurement, false otherwise.
Parameters
| Name | Type | Description |
|---|---|---|
mode | uint8_t | BMV080_MODE_DUTY_CYCLE for duty cycling, as here, or BMV080_MODE_CONTINUOUS for continuous measurement. |
readSensor(bmv080_output_t *bmv080_output = nullptr)returns boolLets the Bosch driver fetch and process data from the sensor once. When a new reading arrives, the library keeps it for PM25() and isObstructed(). In duty cycling mode the driver has to be serviced at least once a second, which the example's one-second loop does.
Returnstrue when a new reading arrived during this call, false otherwise.
Parameters
| Name | Type | Description |
|---|---|---|
bmv080_output | bmv080_output_t * | Optional. A Bosch output structure to copy the new reading into. The example leaves it out. |
PM25()returns floatReturns the PM2.5 value of the latest reading: particles 2.5 µm across or smaller.
ReturnsPM2.5 mass concentration in µg/m³.
isObstructed()returns boolReturns the obstruction flag of the latest reading. The sensor sets it when a fixed object sits in its optical path.
Returnstrue when the latest reading was obstructed, false otherwise.
Putting it together
Set the period first, then start duty cycling with setMode(). Keep calling
readSensor() at least once a second: it returns true once per period. The
sensor's interrupt output cannot trigger readings in this mode, so poll it as
the example does.