Subversion Repositories Arduino.arduino

Rev

Rev 37 | Blame | Compare with Previous | Last modification | View Log | Download

#include <TimedAction.h>
void ta_NTCtemperature();
TimedAction readNTC = TimedAction(2500,ta_NTCtemperature);

/**
The circuit used in this example has more explanation here:
https://www.northstarsensors.com/blog/temperature-from-thermistor-arduino-circuit
Basically a voltage divider is formed with a 10 kΩ thermistor at 25 °C going from ground to pin A0, and a 10 kΩ resistor going from pin A0 to pin A1. 
There is a 0.1 μF capacitor from ground to A0 for noise reduction on the ADC input.
Pin A1 is used as a voltage output, and A0 is used as an ADC input.
https://www.northstarsensors.com/blog/temperature-from-thermistor-arduino-code
**/
/** 
Define all our pins as constants that do not change.
We are attempting to isolate the analog and digital sides of the Arduino Nano/Uno. 
(As a design principle, we don't want other noisy pins and thermistor analog read pin physically next to each other to get the cleanest analog readings possible.)
**/ 
//#define thermistor_current_pin A1
//;#define thermistor_analog_read_pin A0
struct ntc_sensor {
  byte ntc_current_pin     = A1;
  byte ntc_analog_read_pin = A0;

  double ntc_resistance = 50000.0;
  float ntc_temperature_kelvin = 0.0;
  float ntc_temperature_celsius = 0.0;
  float ntc_temperature_fahrenheit = 0.0;
};

struct ntc_sensor ntc;
void charge_input_capacitor(unsigned long charge_time);

// A voltage divider is used with the thermistor to be able to sense the voltage of the thermistor in comparason to the full scale voltage when taking an analog reading

void setup() {

    // Initialize serial port as we will be printing temperature data to it.
    Serial.begin(9600);
    
    // Setup how our pins are used
    pinMode(ntc.ntc_current_pin, OUTPUT);
    pinMode(ntc.ntc_analog_read_pin, INPUT);
} // End setup

void loop() {
  

    // This delay here is a temporary placeholder
    //delay(4500);

    readNTC.check();
} // End main loop

void ta_NTCtemperature() {

  charge_input_capacitor( 50);
    
  int raw_thermistor_reading = read_thermistor_data();
  // Serial.print(raw_thermistor_reading);
  // Serial.print("; ");
    
  double unfiltered_resistance = calculate_resistance_from_analog_read(raw_thermistor_reading);
  //Serial.println(unfiltered_resistance);
  //Serial.print("; ");
    
  ntc.ntc_resistance = filter_resistance_reading(unfiltered_resistance);
  //Serial.print(filtered_resistance);
  //Serial.print("; ");

  ntc.ntc_temperature_kelvin = calculate_temperature_from_resistance(ntc.ntc_resistance);

  ntc.ntc_temperature_celsius = ntc.ntc_temperature_kelvin - 273.15;
  ntc.ntc_temperature_fahrenheit = ((ntc.ntc_temperature_kelvin*9)/5.0) + 32.0;

  Serial.print("Resistance:");
  Serial.print(ntc.ntc_resistance);
  Serial.print(",");
  Serial.print("Kelvin:");
  Serial.print(ntc.ntc_temperature_kelvin);
  Serial.print(",");
  Serial.print("Celsius:");
  Serial.println(ntc.ntc_temperature_celsius);
}

// This function charges up the ADC input capacitor
// and does not continue until it is charged
void charge_input_capacitor(unsigned long charge_time = 100) {
  
      // Start by charging up the capacitor on the input pin
    digitalWrite(ntc.ntc_current_pin, HIGH);
    
    // Wait 100 milliseconds for the input capacitor to fully charge.
    // Currently delay() is used as a placeholder.
    // For most applications we will want to use a non-blocking timer function.
    delay(charge_time);
} // End charge_input_capacitor function


// This function records and returns an analog reading.
// It also turns off the current pin once complete
int read_thermistor_data(){
    
    // Read analog data from charged capacitor.
    int raw_thermistor_reading = analogRead(ntc.ntc_analog_read_pin);
  
    // Turn off the thermistor current pin to minimize self-heating of temperature sensor
    digitalWrite(ntc.ntc_current_pin, LOW);
    
    return raw_thermistor_reading;
} // End read_thermistor_data function


/** 
 This function calculates the rough resistance of the thermistor but does not filter the results for more accuracy. 
 That is handled in another function.
 For the math here, the full scale range of the analog read is 0 to 1023, (1024 steps) because the arduino nano has a 10bit ADC.
 2^10 = 1024
 raw_thermistor_reading / (1023.0 - raw_thermistor_reading) calculates the proportion of the voltage across the thermistor in the voltage divider comparated to the voltage acrross the constant resistor in the voltage divider.
 Once the proportion of that voltage is known, we can calulate the resistance of the thermistor by multiplying that proportion by the resitance of the constant resistor in the voltage divider.
**/ 
double calculate_resistance_from_analog_read(int raw_thermistor_reading){
  
    // The resistance of the 10 kΩ resistor in the voltage divider is included here as a local variable.
    // If you have a more precise reading of the resistor you can change it here for more accuracy 
    double voltage_divider_resistor = 51100.0;
    
    // If there is a full scale reading (1023) there is an open circuit, and we end the function early and simply return 999999 to avoid dividing by 0
    if(raw_thermistor_reading >= 1023){
      return 999999.9;
    }
  
    // See function comment for more explanation of the math
    double unfiltered_resistance = voltage_divider_resistor * (
        raw_thermistor_reading / (1023.0 - raw_thermistor_reading)
                                                                 );                                                           
    return unfiltered_resistance;
} // End calculate_resistance_from_analog_read function


/**
 This function filters the resistance reading. Filtering gives better results because no measurement system is perfect.
 In this case, measuring the voltage of the thermistor absorbs some of it's current during the read process, and slightly alters the true voltage of the thermistor. 
 This function compensates that and returns resistance readings much closer to their true value.
 **/
double filter_resistance_reading(double unfiltered_resistance){

    // These compensation values are specific to the ADC of the Arduino Nano or Uno, to the resistance of the voltage divider, capacitance at the input, and wait time between measurements. 
    // If any of those parameters change, the values will likely have to be adjusted.
    double calibration_factor = -3.27487396E-07 * unfiltered_resistance +
        8.25744292E-03;
  
    double filtered_resistance = unfiltered_resistance * (1 + calibration_factor);
  
    return filtered_resistance;
} // end filter_resistance_reading function


/**
  This function uses the 4 term Steinhart-Hart equation to determine the temperature of a thermistor from its resistance.
  Go to https://www.northstarsensors.com/calculating-temperature-from-resistance
  for more information about the Steinhart-Hart equation
**/
float calculate_temperature_from_resistance(double thermistor_resistance){
    // These constant values are for a North Star Sensors, curve 44, 10 kΩ at 25 °C thermistor.
    // They are generated from 4 data points at 0, 25, 50, and 70 °C.
    // If you are measuring outside that range, use constants specialized with data points in the range you need.
    double SH_A_constant = 1.044305137076E-03;  //1.044305137076E-03
    double SH_B_constant = 1.6012306448E-04;    //1.6012306448E-04
    double SH_C_constant = 5.898824753308E-06;  //5.898824753308E-06
    double SH_D_constant = -8.948520131542E-08; //-8.948520131542E-08
  
    // In arduino log() calculates the natural logarithm sometimes written as ln, not log base 10
    double natural_log_of_resistance = log(thermistor_resistance);
  
    // pow() is a function which rases a number to its power.
    // For example x to the power of 2, x^2, is pow(x, 2)
    float thermistor_temperature_kelvin = 1.0 / ( SH_A_constant +
                                                  SH_B_constant * natural_log_of_resistance +
                                                  SH_C_constant * pow(natural_log_of_resistance, 2) +
                                                  SH_D_constant * pow(natural_log_of_resistance, 3)
                                              );
    return thermistor_temperature_kelvin;
} // end calculate_temperature_from_resistance function