NTC Thermistor for PID control w/ XIAO ESP32-C3

Hello!

Quite new to Arduino so forgive me for any mistakes -- I'm trying to build a driver circuit that can power a PCB trace to keep it at a constant ~35 C. I'm using a XIAO ESP32-C3 board and I've had a couple questions about my schematic and my code:

  • My serial monitor states that the voltage measured is ~0.64 V. With my voltage divider setup I was expecting a voltage drop of ~1.65 across my thermistor, so I'm not sure if I just set up my circuit terribly wrong. I'm using a thermocouple to monitor the temperature of the trace and the temperature is ~25 C, so I'm not sure why the drop is so small.
  • The specific thermistor I'm using is the NCP15WF104F03RC, which is 100k ohms at 25C and a B constant of 4250 K at 25C/50C

#include <PID_v1.h>

#define THERM_PIN A2
#define HEAT_PIN D10
#define THERM_R 100000  // thermistor resistance at 25 C
#define TEMP_NOM 25
#define NUM_SAMPLES 5
#define BETA 4250
#define SERIES_R 100000.0

//Define Variables we'll be connecting to
double Kp = 2.0, Ki = 2.0, Kd = 0.0;
// double Kp = 2.0, Ki = 5.0, Kd = 1.0;
float Rref = 100000.0;        // Value of the reference resistor in ohms
float supplyVoltage = 3.3;  // Supply voltage of ESP32 (assuming 3.3V)
float R0 = 100000.0;          // resistance of thermistor at 25 C

//Specify the links and initial tuning parameters
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int WindowSize = 500;
unsigned long windowStartTime;

void setup() {
  Serial.begin(9600);
  Setpoint = 35.0;

  // Initialize heater pin
  pinMode(HEAT_PIN, OUTPUT);
  digitalWrite(HEAT_PIN, HIGH);  // heater off

  windowStartTime = millis();

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop() {
  float average = analogRead(THERM_PIN);
  Serial.print("analog reading ");
  Serial.println(average);  // analog input from thermistor voltage divider

  float voltage = average * (3.3 / 4095.0);  // convert analog reading to voltage; Vsupply / adcMax (ADC resolution)
  Serial.print("Voltage ");
  Serial.println(voltage);  // analog input from thermistor voltage divider
  float thermistorResistance = calculateResistance(voltage);
  Serial.print("Thermistor resistance ");
  Serial.println(thermistorResistance);

  float temp = calculateTemperature(thermistorResistance);
  Serial.print("Temperature: ");
  Serial.print(temp);
  Serial.println(" C");


  Input = temp;
  myPID.Compute();

  // Adjust heater based on PID output
  analogWrite(HEAT_PIN, Output);

  // Print debug information
  Serial.print("Setpoint: ");
  Serial.print(Setpoint);
  Serial.print(" | ");
  Serial.print("Input: ");
  Serial.print(Input);
  Serial.print(" | ");
  Serial.print("Output: ");
  Serial.println(Output);

  /************************************************
     turn the output pin on/off based on pid output
   ************************************************/
  unsigned long now = millis();
  if (millis() - windowStartTime > WindowSize) {  //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if (Output > millis() - windowStartTime) digitalWrite(HEAT_PIN, HIGH);
  else digitalWrite(HEAT_PIN, LOW);

  delay(1000);
}

float calculateResistance(float voltage) {
  float Rseries = 100000.0;
  float thermistorResistance = (Rseries * voltage) / (3.3 - voltage);
  return thermistorResistance;
}

float calculateTemperature(float resistance) {
  // using Steinhart-Hart equation
  float A = 0.6400107870e-03;
  float B = 2.440533353e-04;
  float C = -0.6275337436e-07;

  float inv_T = A + B * log(resistance) + C * pow(log(resistance), 3);
  float temperature = (1.0 / inv_T) - 273.15;  // Convert to Celsius

  return temperature;

A good check is to use your multimeter to verify the resistance of the thermistor (out of the circuit), and the voltage at the divider junction.

The ESP32 ADC performance is very poor, and not very useful for such measurements. See

Thank you for the link! Just checked the resistance -- yup its not anywhere close to what my code is outputting lol. I tried to do some of the suggestions offered by the link but when I tried to upload the code with analogSetWidth(11) in the setup block, my code threw an error saying that the its not within scope.

With a DMM? What value did you get at room temperature?

I measured ~97 k ohms; I wonder if part of the issue with the voltage measurement is the lack of an op-amp? Would a connection to the voltage divider impact the measurement / I simply need to toss in a buffer to fix it?

Please use your DMM to measure and report the voltage at the divider junction, while it is connected to the powered-up ESP32.

I measured ~97 k ohms;

That is about the expected value. If the Xiao ESP32-C3 ADC input impedance is 100K or less, that would explain the low voltage measurement.

I just looked up the Espressif docs for the ESP32-C3 ADC, and it is very different than the ESP32 ADC.

Without input attenuation, it can measure only 0 to 0.75V. Unfortunately those docs do not explain how the Arduino IDE implements analogRead().

See
https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32c3/api-reference/peripherals/adc.html

Also
https://docs.espressif.com/projects/arduino-esp32/en/latest/api/adc.html

The A/D of an ESP is also the wrong type of A/D to measure a thermistor.
A digital DS18B20 is a much better solution.
Leo..

I just measured the voltage across it and got a value of ~2.8-2.9 V

That doesn't make any more sense than 0.65V. With Rth approximately equal to Rs, the voltage measured from the divider junction to GND should be about 3.3V/2.

Something is wrong with the wiring.

Yup -- resistor values in my PCB weren't right but have since fixed it! Voltage divider is working as expected; now I'm just a bit lost on the PID control aspect. I don't think I fully understand the purpose of how the PID control output (a temperature in C) is related to millis() - windowStartTime

For PID to work correctly, the sample and correction updates must be at regular, timed intervals. The theory is described in many places on line.

Use the search phrase "PID tuning" for tutorials on choosing Kp, Ki and Kd.

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