Skip to main content

Calibrate the zero point

What this example shows​

The library's calibrateSensor example adds your own zero offset to every reading. Run it where there is no ammonia and adjust customCalibration until the voltage after calibration is roughly 0. From then on, the same offset in your own sketch makes clean air read just about 0 ppm.

The example uses the SENSOR_NH3 preset, the library's preset for this board's cell, and passes address 0x49 with GPIO 32 as the configuration pin.

The library talks to the board's ATtiny404 bridge only when the address is from 0x30 to 0x37. Any other address, such as the 0x49 this example passes, is taken as the I2C address of an ADS1115 that the library talks to directly, with the configuration pin set low while it configures the LMP91000. On this board the ADS1115 sits on the header's SDA2/SCL2 pins, which the Qwiic connectors do not reach, so this example does not run over the Qwiic cable. Wire the controller to the header instead: 3.3 V to 3V3, GND to GND, SDA to SDA2 and SCL to SCL2. The example then runs as written, with no change to the address.

The example's comments connect LMPEN to GND or a GPIO pin. On this board, leave LMPEN unconnected: a 10 kΩ resistor already pulls it to GND, and the ATtiny404 is connected to it too.

To see the voltages you are adjusting, open the library's Electrochemical-Gas-Sensor-SOLDERED.h and remove the // in front of this line:

#define ELECTROCHEMICAL_SENSOR_DEBUG

The example code​

Select Board
calibrateSensor.ino
/**
**************************************************
*
* @file calibrateSensor.ino
* @brief See how to calibrate an electrochemical sensor
*
* To successfully run the sketch:
* - Uncomment the #define in the library header file
* - Connect LMPEN pin to GND or a GPIO pin so the breakout can be configured
* - Run the sketch and open serial monitor at 115200 baud!
*
* @authors Robert @ soldered.com
***************************************************/

// Include the required library
#include "Electrochemical-Gas-Sensor-SOLDERED.h"

// This is the custom value we set for the calibration voltage
// This value is added to the voltage read from the ADC
// In an environment with 0 of the target gas, the voltage after calibration should be
// roughly 0, adjust customCalibration to get it to that value.
const double customCalibration = 0.05;


// Create the sensor object with the according type
ElectrochemicalGasSensor sensor(SENSOR_NH3, 0x49, 32);



void setup()
{
Serial.begin(115200); // For debugging

// Initialize the breakout
if (!sensor.begin())
{
// Can't init? Notify the user and go to infinite loop
Serial.println("ERROR: Can't init the sensor! Check connections!");
while (true)
delay(100);
}

//Set the custom calibration value
sensor.setCustomZeroCalibration(customCalibration);

Serial.println("Sensor initialized successfully!");
}

void loop()
{
// Make the reading
double reading = sensor.getPPM();
// This function will also print debug messages if the #define in
// the header file of the library is uncommented
// It will print:
// - The raw voltage measurement
// - Voltage without reference value
// - Voltage after calibration
// These values can help you adjust the internal zero calibration



// Print the reading with 5 digits of precision
Serial.print("Sensor reading: ");
Serial.print(reading, 5);
Serial.println(" PPM");

// Wait a bit before reading again
delay(2500);
}

The Serial Monitor shows:

Serial MonitorAutoscrollShow timestampNewline115200 baud
Message (Enter to send message to the board)
Sensor initialized successfully!

Then a Sensor reading: line in ppm follows every 2.5 seconds. With the debug line enabled, each reading is preceded by Electrochemical gas sensor readings: and three voltages: Raw voltage measurement:, Voltage without reference value: and Voltage after calibration:, each in volts.

If begin() returns false, the example prints ERROR: Can't init the sensor! Check connections! instead and stops.

Functions used​

ElectrochemicalGasSensor(sensorType _t, uint8_t _adcAddr = DEFAULT_ADC_ADDR, int _configPin = -1)returns none

Creates the sensor object. begin() picks how to talk to the board from the address: from 0x30 to 0x37 it uses the ATtiny404 bridge; any other address is used as the ADS1115's own I2C address.

ReturnsConstructor.

Parameters

ParameterTypeDescription
_tsensorTypeThe cell preset, here SENSOR_NH3, the preset for this board's cell.
_adcAddruint8_tThe address, here 0x49. On this board the ADDRESS switch sets the bridge's address from 0x30 to 0x37.
_configPinintA GPIO the library sets low while it configures the LMP91000 when the address is outside 0x30 to 0x37, here 32. Not used from 0x30 to 0x37.
bool begin()returns bool

Starts I2C. With an address from 0x30 to 0x37 it checks that the bridge answers and sends it the ADC settings from the preset; with any other address it starts the ADS1115 on that address directly. Then it configures the LMP91000 analog front end.

Returnstrue when every step succeeded. false when the bridge did not answer OK within 500 ms or reported an error, when starting the ADS1115 failed, or when configuring the analog front end failed.

void setCustomZeroCalibration(double calibration)returns void

Sets the voltage that getPPM() adds to every reading after removing the front end's internal zero. It replaces the preset's internalZeroCalibration, which is 0 for SENSOR_NH3.

ReturnsNothing.

Parameters

ParameterTypeDescription
calibrationdoubleOffset in volts. Choose it so the voltage after calibration is about 0 with none of the target gas present.
double getPPM()returns double

Takes one reading and converts it to ppm, with your calibration offset applied. A result below zero is returned as 0.

ReturnsThe gas concentration in ppm.

Putting it together​

Find the offset once in clean air with the debug output on, then call setCustomZeroCalibration() with that value after begin() in your own sketch. Comment the debug line out again when you are done, so your sketch prints only what you ask it to.