API guide¶
How to do the common jobs with the driver: construct, initialise, read, average and handle errors.
Every snippet on this page is compiled by the host CI from
tests/docs/api_tasks.cpp, with Sensor standing for
hf::mcp9700::Mcp9700Thermistor<MyAdc>. The API reference lists every member.
The shape of the API¶
One Mcp9700Thermistor<AdcType> object per sensor, in namespace hf::mcp9700.
| Member | What it does |
|---|---|
| Constructor | Stores the adapter, channel and coefficients; no ADC access |
Initialize() |
Checks the arguments, calls the adapter's EnsureInitialized() |
ReadTemperatureCelsius(float*) |
One ADC read, converted to °C and checked against the sensor's range |
ReadVoltage(float*) |
One ADC read, the raw VOUT in volts: no conversion, no range check |
SetSpecifiedRange(min, max, margin) |
The temperature range a reading must fall in (default −40 °C to +125 °C, 8 °C margin) |
LastError() |
Why the last call that can fail failed (hf::mcp9700::Error) |
Deinitialize() |
Marks the object uninitialised; reads fail until Initialize() |
VoltsAtZeroC() |
The offset in use |
VoltsPerCelsius() |
The slope in use |
HasValidCoefficients() |
true when the offset is finite and the slope is finite and above zero |
GetMcp9700DriverVersion() |
The version string (free function) |
Every call is noexcept and never throws. The calls that can fail return bool: check it.
Construct and initialise¶
Sensor board(&adc, 0); // MCP9700 / 9700A / 9700B: datasheet typicals
Sensor trimmed(&adc, 1, 0.4962F, 0.01003F); // per-unit coefficients from a calibration
return board.Initialize() && trimmed.Initialize();
The two coefficient arguments are optional. Leave them out for the MCP9700, MCP9700A and MCP9700B datasheet typicals; pass your own after a calibration (Configuration). The channel is passed to your adapter unchanged: it means whatever your adapter says it means.
Initialize() returns false when the adapter pointer is null, when the coefficients
are unusable (v_per_c zero, negative, NaN or infinite, or v_zero_c NaN or infinite), or when
EnsureInitialized() returns false. Several sensors can share one adapter; each Initialize() calls
EnsureInitialized() again, so make it safe to call twice.
Read the temperature¶
float celsius = 0.0F;
if (!sensor.ReadTemperatureCelsius(&celsius)) {
return false; // celsius is unchanged on failure
}
std::printf("%.2f C (V0 = %.4f V, Tc = %.5f V/C)\n", static_cast<double>(celsius),
static_cast<double>(sensor.VoltsAtZeroC()), static_cast<double>(sensor.VoltsPerCelsius()));
return true;
Each call is one ReadChannelV() call. The driver keeps no history and no cache.
Average several reads¶
constexpr int kSamples = 16;
float sum = 0.0F;
for (int i = 0; i < kSamples; ++i) {
float t = 0.0F;
if (!sensor.ReadTemperatureCelsius(&t)) {
return false;
}
sum += t;
}
*celsius = sum / static_cast<float>(kSamples);
return true;
The sensor's thermal response is about a second (Hardware), so averaging a burst of reads filters ADC and supply noise without hiding real temperature changes.
Handle errors¶
float t = 0.0F;
if (!sensor.ReadTemperatureCelsius(&t)) {
switch (sensor.LastError()) {
case hf::mcp9700::Error::kOutOfRange: { // open, grounded or shorted input, or wrong ADC scale
float volts = 0.0F;
if (sensor.ReadVoltage(&volts)) { // the raw VOUT, unconverted and unchecked
std::printf("VOUT %.3f V is outside the sensor's range\n", static_cast<double>(volts));
}
break;
}
case hf::mcp9700::Error::kAdcError: // ReadChannelV() returned non-zero
std::printf("ADC read failed\n");
break;
default: // not initialised or null output
break;
}
return false; // t is unchanged on failure
}
*celsius = t;
return true;
LastError() |
Meaning |
|---|---|
Error::kInvalidArgument |
Null adapter, null output pointer, or an invalid range passed to SetSpecifiedRange() |
Error::kInvalidCoefficients |
Initialize(): the slope is not a finite positive number, or the offset is not finite |
Error::kAdcError |
Your EnsureInitialized() returned false or your ReadChannelV() returned non-zero |
Error::kNotInitialized |
Read before a successful Initialize(), or after Deinitialize() |
Error::kOutOfRange |
The temperature is outside the specified range plus the margin, or not a number |
Error::kNone |
The last call succeeded |
kOutOfRange catches the faults a plain conversion would report as a temperature: VOUT at 0 V (open wire,
grounded input or unpowered sensor, which would read −50 °C), VOUT near the supply, or an adapter that returns
millivolts. A working MCP9700 outputs 100 mV to 1.75 V over −40 °C to +125 °C (datasheet Section 3.2); with the
8 °C margin the driver accepts 20 mV to 1.83 V. A floating input that happens to settle inside that window
cannot be told from a temperature. On a failed read the output value is not written. ReadVoltage() returns
the raw VOUT without the range check, to see what the pin reads.
Set the plausible range¶
// High-temperature MCP9700 / MCP9700B (SOT-23-3, SC70-5): specified to +150 C. Keep the 8 C margin.
return sensor.SetSpecifiedRange(-40.0F, 150.0F);
The default range is the MCP9700 family's specified range. Widen it to +150 °C for the high-temperature parts,
narrow it to −10 °C for the MCP9701 (Configuration). The margin (default
kDefaultRangeMarginCelsius, 8 °C) covers the sensor's worst-case accuracy limits (−4 °C / +6 °C for the
MCP9700) and some ADC error.
Re-initialise and read the version¶
sensor.Deinitialize(); // reads now fail; the ADC itself stays as it is
if (!sensor.Initialize()) { // calls EnsureInitialized() again
std::printf("ADC did not come back\n");
}
std::printf("driver %s\n", GetMcp9700DriverVersion());
Deinitialize() only changes the driver's state; shutting down the ADC is your adapter's job.
Next¶
Configuration for calibration; Porting for the adapter contract.