/*----------------------------------------------------------------------------*/ /* Projet: Firedrake */ /* File : therm100K.h */ /* Author: user@W500 09/20/20 */ /*----------------------------------------------------------------------------*/ /* BRIDGE PULL UP MOUNTING (Pulldown is opposite) TH_VCC Analog In: TH_PIN TH_GND | | | x----/\/\/\/\/\/\/\/\/\/\/\/\/\-----x----/\/\/\/\/\/\/\/\/\/\/\/\/\--------x Serie Resistor: TH_SERIE_R Thermistor: TH_R0, TH_T0, TH_BETA */ /*----------------------------------------------------------------------------*/ // Tested on Uno board. // Using direct computing of simplyfied Seinhart-Hart takes 330µs. // Using 30 values look up table is 3 time less time, 100µs & error less than 1°. // For the time being we do the math for each call, choice should be fixed // at setup and Th_Get_Degre() should take it in account. // TODO: all this should be in a class in a library #ifndef __THERM100K_H__ #define __THERM100K_H__ #define TH_VCC 2 // digital output for bridge supply #define TH_GND 6 // digital output for bridge ground #define TH_PIN 5 // adc pin to bridge middle pont #define TH_ADCSTEPS 1023 // analog max value 2^(adc digits)-1 // WIP: we use standard values for this kind of thermistor, // but this yield a température 4° too high // #define TH_R0 119.4 // nominal resistance in KOhm at T0°C => 4° too much at 18° #define TH_R0 103.9 // nominal resistance in KOhm at T0°C => -.2°/+.6° at 18,5° #define TH_T0 27.2 // temp at nominal resistance (mostly 25°C) #define TH_BETA 3.58 // thermistor beta coeff [3-4] Kelvin #define TH_SERIE_R 4.7 // Serie resistor #define TH_MOUNT_R PullUp // Serie mounting in "PullUp" or "PullDown" #define TH_KILO 1000.0 enum T_SeriePull { PullUp, PullDown }; // discriminate serie resistor mounting float Th_Compute_Therm_R(int raw, float rSerie, T_SeriePull rPull); float Th_Compute_Simple_SH(float r_therm); #define LUT_NB 30 // Look up table count, 30 values takes 10ms to build struct { int adc; float deg; } Th_Lut[LUT_NB]; // Look up table void Th_PrLookUp() { #ifdef IHM for (int i=0; i < LUT_NB; i++) { Serial.print("LUT adc "); Serial.print(Th_Lut[i].adc); Serial.print(" => "); Serial.print(Th_Lut[i].deg); Serial.println("°C");} #endif } /* This takes 9880 µseconds for 30 values on an UNO board. */ void Th_MkLookUp(){ // builds a look up table adc <=> deg float r_therm = 0; int adcVal = 1, astep = floor(float(TH_ADCSTEPS) /(LUT_NB-1)); for (int i=0; i < LUT_NB; i++) { Th_Lut[i].adc = adcVal; r_therm = Th_Compute_Therm_R(adcVal, TH_SERIE_R, TH_MOUNT_R); Th_Lut[i].deg = Th_Compute_Simple_SH(r_therm) ; adcVal += astep ; } } float Th_LookUpFind(int raw){ float result=0, t ; int last = LUT_NB -1, idx_out=-1; // index for out array if (raw <= Th_Lut[0].adc) idx_out = 0; else if (raw >= Th_Lut[last].adc) idx_out = last; if (idx_out >= 0) { result = float(Th_Lut[idx_out].deg) ; // out of bounds: first or last #ifdef IHM Serial.print("LUT: out of bounds at = "); Serial.println(idx_out); #endif } else { int pos = 1; // [0] allready tested while(raw > Th_Lut[pos].adc) pos++; // looking for upper bound if (raw == Th_Lut[pos].adc) result = float(Th_Lut[pos].deg); // exact match else { // interpolate between pos-1 & pos float part = 0; part = float(raw - Th_Lut[pos-1].adc); part /= float(Th_Lut[pos].adc - Th_Lut[pos-1].adc); result = Th_Lut[pos-1].deg + part * (Th_Lut[pos].deg - Th_Lut[pos-1].deg); } } return result; } void Th_Setup() { pinMode(TH_VCC, OUTPUT); pinMode(TH_GND, OUTPUT); digitalWrite(TH_VCC, LOW); digitalWrite(TH_GND, LOW); analogReference(DEFAULT); } int Th_ReadRaw() { int raw = 0; digitalWrite(TH_VCC, HIGH); delay(500); // WIP: give some time to reach 5V ? raw = analogRead(TH_PIN); digitalWrite(TH_VCC, LOW); return raw; } /* This takes 80 µseconds on an UNO board. */ float Th_Compute_Therm_R(int raw, float rSerie, T_SeriePull rPull) { float val = 0 ; switch (rPull) { case(PullUp): val = rSerie * TH_KILO / ((float(TH_ADCSTEPS) / raw) - 1); break; case(PullDown): val = rSerie * TH_KILO * ((float(TH_ADCSTEPS) / raw) - 1); break; #ifdef IHM default: Serial.println(); Serial.println( "BUG in Th_Compute_Therm_R" ); Serial.println(); #endif } return val; } /* This is computed using the simplified Steinhart-Hart formula and takes 250 to 270 µseconds on an UNO board. If more speed is needed, you may load a look up table and interpolate the ADC reading. */ float Th_Compute_Simple_SH(float r_therm) { float s_h = 0; s_h = r_therm / (TH_R0 * TH_KILO); // R/R0 s_h = log(s_h); // ln(R/R0 ) s_h /= TH_BETA * 1000.0; // 1/B * ln(R/R0 ) s_h += 1.0 / (25.0 + 273.15 ); // + 1/T0 in Kelvin s_h = 1.0 / s_h ; // invert s_h = s_h - 273.15; // in Celsius return s_h; } float Th_Get_Degre () { int raw = Th_ReadRaw(); float r_therm = Th_Compute_Therm_R(raw, TH_SERIE_R, TH_MOUNT_R); return Th_Compute_Simple_SH(r_therm); } #endif // __THERM100K_H__