139 lines
5.7 KiB
C
139 lines
5.7 KiB
C
/*----------------------------------------------------------------------------*/
|
|
/* 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__
|