Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab bei meiner Heizungssteuerung genau diese Aufgabe so gelöst:
Hier lasse ich genau 0.88mA durch den KTY-81 und kann damit exakt sagen, nach Tabelle, welcher Widerstand anliegt. Der µC hat im EEPROM eine Stützpunkttabelle welche R auf Temperatur abbildet (aus dem Datenblatt abgetippt). Liegt die Spannung zwischen 2 Stützpunkten wird linear interpoliert. So komme ich mit einem MAX1270 (ok, teuer *hust* aber 12 Bit) auf unter 1°C Genauigkeit. Mit dem eingebauten ADC geht das ganze auch aber die Auflösung ist etwas schlechter.
Anhang 30708
Code:
const sensorvalues_flash t_kt81_110[] PROGMEM =
{ // r t
{ 490, -55},
{ 515, -50},
{ 567, -40},
{ 624, -30},
{ 684, -20},
{ 747, -10},
{ 815, 0},
{ 886, 10},
{ 961, 20},
{ 1000, 25},
{ 1040, 30},
{ 1122, 40},
{ 1209, 50},
{ 1299, 60},
{ 1392, 70},
{ 1490, 80},
{ 1591, 90},
{ 1696, 100},
{ 1805, 110},
{ 1915, 120},
{ 2023, 130},
{ 2124, 140},
{ 2211, 150},
};
const sensorvalues_flash t_kt81_210[] PROGMEM =
{ // r t
{ 1383, -20},
{ 1408, -18},
{ 1434, -16},
{ 1459, -14},
{ 1485, -12},
{ 1511, -10},
{ 1537, -8},
{ 1563, -6},
{ 1590, -4},
{ 1617, -2},
{ 1644, 0},
{ 1671, 2},
{ 1699, 4},
{ 1727, 6},
{ 1755, 8},
{ 1783, 10},
{ 1812, 12},
{ 1840, 14},
{ 1869, 16},
{ 1898, 18},
{ 1928, 20},
{ 2002, 25},
{ 2078, 30},
{ 2155, 35},
{ 2234, 40},
{ 2314, 45},
{ 2395, 50},
{ 2478, 55},
{ 2563, 60},
{ 2648, 65},
{ 2735, 70},
{ 2824, 75},
{ 2914, 80},
{ 3005, 85},
{ 3098, 90},
{ 3192, 95},
{ 3287, 100},
};
Um den langsammen Zugriff auf den Flash zu reduzieren, nutze ich eine binäre Suche, so brauche ich nur log(n)/log(2) zugriffe statt n:
Das bedeutet, statt 37 Versuchen beim kt81_210 brauche ich nur log(37)/log(2) = 6.
Code:
avr::units::temperature
convert(sensor_t s, avr::units::resistor r)
{
sensorvalues t1, t2;
const sensorvalues_flash* current = &t_kt81_210[0];
switch (s)
{
case kt81_210: current = &t_kt81_210[0]; break;
case kt81_110: current = &t_kt81_110[0]; break;
}
// binary search without recursion
unsigned char st = 0;
unsigned char en;
unsigned char m;
switch (s)
{
case kt81_210: en = sizeof(t_kt81_210)/sizeof(sensorvalues_flash)-2; break;
case kt81_110: en = sizeof(t_kt81_110)/sizeof(sensorvalues_flash)-2; break;
default:
return 0.0_celcius;
}
sensorvalues_flash tmp;
while (en-st>1)
{
m = st + (en-st)/2;
memcpy_P(&tmp, ¤t[m], sizeof(sensorvalues_flash)); t1 = tmp;
if (r > t1.r) // if we use at sometime a NTC, we need to adjust this
{
// right side
st = m;
}
else
{
// left side
en = m;
}
}
// read the best matching lines
memcpy_P(&tmp, ¤t[st+0], sizeof(sensorvalues_flash)); t1 = tmp;
memcpy_P(&tmp, ¤t[st+1], sizeof(sensorvalues_flash)); t2 = tmp;
// interpolate
resistor dr = t2.r-t1.r;
float f = static_cast<float>((r-t1.r)/dr);
return t1.t+(t2.t-t1.t)*f;
}
Hier wird eingelesen. vom ADC wird dann in Volt gewandelt. Über R=V/I wird dann R berechnet, welcher dann über die obige convert Funktion in Temperatur umgewandelt wird.
sys.configuration.adc_constant_current[avr::free_7-active_adc] enthält den exakt gemessenen Konstantstrom welcher über das Menü angepasst werden kann. (Messung per Scopemeter)
Code:
tmp = (uint16_t(in[0]) << 8) | uint16_t(in[1]);
tmp = tmp >> 4; // shift the last 4 zero bits out
sys.max1270_select.on();
// fill the sensor structure
sys.sensor.dt = sys.dt;
using namespace avr::units;
voltage v((float(tmp)/(1<<12))*5.0f);
resistor r = v/sys.configuration.adc_constant_current[avr::free_7-active_adc];
// prevent short spikes
if (abs(tmp-sys.sensor.raw[avr::free_7-active_adc]) < 10 || first[active_adc])
{
first[active_adc] = false;
sys.sensor.raw[avr::free_7-active_adc] = tmp;
sys.sensor.temperature[avr::free_7-active_adc] =
convert(sys.configuration.adc_sensor_type[avr::free_7-active_adc],r);
}