Skip to content

Quickstart

Read a temperature from your MCU: wire three pins, write a small ADC adapter, call two driver functions.

1. Wire it

MCP9700 MCU Notes
VDD 3.3 V (2.3 V to 5.5 V) 0.1 µF to 1 µF ceramic capacitor to GND, close to the pins
GND GND Common with the ADC ground
VOUT ADC input 100 mV to 1.75 V; the ADC range must reach 1.75 V

Pin numbers depend on the package: SOT-23-3 and TO-92-3 are VDD 1, VOUT 2, GND 3. The Hardware page has the SC70-5 pinout, the output limits and the ADC settings.

2. Add the driver

Add the repository as a submodule and link the hf::mcp9700 CMake target (or include inc/ and the generated version header, with C++17). Installation covers CMake and ESP-IDF.

git submodule add https://github.com/hardfoc/hf-mcp9700-driver.git external/hf-mcp9700-driver

3. Write the adapter

The adapter is the only platform code. It brings the ADC up and returns the voltage at VOUT in volts. Replace the two platform_* calls with your SDK's.

my_adc.hpp
class MyAdc {
public:
  // Bring the ADC up. The driver calls this from Initialize(); return true when it is ready.
  bool EnsureInitialized() noexcept {
    if (!ready_) {
      ready_ = platform_adc_init();
    }
    return ready_;
  }

  // Volts at the MCP9700 VOUT pin. Return 0 on success, any other value on failure.
  int ReadChannelV(uint8_t channel, float* voltage_v) noexcept {
    int32_t mv = 0;
    if (!ready_ || !platform_adc_read_mv(channel, &mv)) {
      return 1;
    }
    *voltage_v = static_cast<float>(mv) / 1000.0F;
    return 0;
  }

private:
  bool ready_ = false;
};

Return the voltage at the sensor pin, after your ADC's calibration and after undoing any divider or attenuator in front of it. Porting explains each method.

4. Read the temperature

main.cpp
#include "mcp9700_thermistor.hpp"

int print_board_temperature(MyAdc& adc) {
  hf::mcp9700::Mcp9700Thermistor<MyAdc> sensor(&adc, /*adc_channel=*/0);  // 500 mV at 0 °C, 10 mV/°C

  if (!sensor.Initialize()) {                     // 1. brings the ADC up
    return -1;                                    // adapter failed: ADC unit, channel, pin
  }

  float celsius = 0.0F;
  if (!sensor.ReadTemperatureCelsius(&celsius)) { // 2. one ADC read, (V - 0.5 V) / 0.01 V/°C
    return -2;                                    // ADC error, or VOUT outside the sensor's range
  }
  std::printf("Board temperature: %.1f C\n", static_cast<double>(celsius));
  return 0;
}

What each step does:

  1. The constructor stores the adapter pointer, the channel and the default coefficients (500 mV at 0 °C, 10 mV/°C). It does not touch the ADC.
  2. Initialize() calls your adapter's EnsureInitialized(). Reads fail until it has returned true.
  3. ReadTemperatureCelsius() calls ReadChannelV() once and returns (V − 0.5) / 0.01. A reading of 0.75 V is 25 °C. A result outside −40 °C to +125 °C by more than 8 °C (an open, grounded or shorted input) fails instead.

This example is built by the host CI, so it compiles against the current headers.

If it does not work

Symptom First thing to check
Initialize() returns false Your EnsureInitialized(): ADC unit, channel, pin
Reads fail, LastError() is Error::kOutOfRange VOUT at 0 V (open wire, sensor unpowered, wrong ADC channel), at the supply, or the adapter returns millivolts
Reads too high or too low by a fixed factor ADC full scale, attenuation or a divider not undone
Off by a few degrees Sensor grade and the ADC's own error (Transfer function)

Next

  • API guide: calibration, averaging, error handling.
  • Hardware: output characteristics, ADC resolution, layout.
  • Examples: the ESP32-C6 application.