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.
![]()
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: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}, };
Das bedeutet, statt 37 Versuchen beim kt81_210 brauche ich nur log(37)/log(2) = 6.
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.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; }
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); }







Zitieren
Lesezeichen