Dragonhead/therm100K.h

139 lines
5.7 KiB
C
Raw Normal View History

/*----------------------------------------------------------------------------*/
/* 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__