Thermoelementauswertung mit integriertem Differenzverstärker
Kürzlich brauchte ich einen Temperaturschalter, der 400 °C aushalten musste. Ein Thermoelement schafft das leicht, erzeugt aber leider nur unschön kleine Spannungen. Es zeigt sich allerdings, dass der integrierte Differenzverstärker eines ATTiny216A für eine grobe Messung absolut ausreicht, und damit auf alle Fälle für eine Entscheidung, ob „heiß oder nicht“.
Hier sind zwei Thermoelemente mit 3 ADC-Eingängen verbunden, wobei ADC1 als Referenzpunkt für die differenziellen Messungen dient. Die beiden Widerstände sorgen für eine Vorspannung, damit der Differenzverstärker nicht um 0 V herum arbeiten muss. Da sich die interne Referenzspannung nicht nach außen führen lässt, ist dieser Spannungsteiler nötig.
Der Offset kann kompensiert werden, indem zuerst eine Wandlung durchgeführt wird, bei der beide Differenzverstärkereingänge mit demselben Pin verbunden sind, deren Ergebnis später abgezogen wird. Mit einer Verstärkung von 32 und etwas Überabtastung ergibt sich eine brauchbare Messung. Noch einmal, besonders viel Genauigkeit kann man nicht erwarten (man bemerke zudem die Fehlende Kaltstellenkompensation).
int16_t readadc10s(void)
{
int16_t buf = 0;
int16_t temp = 0;
for(uint8_t i = 0; i < 16; i++)
{
ADCSRA |= (1 << ADSC);
while(ADCSRA & (1 << ADSC));
temp = ADCL;
temp |= ADCH << 8;
if(temp & 0x0200)
{
temp |= 0xfc00;
}
buf += temp;
}
return buf / 4;
}
void dummyconversion(uint8_t ct)
{
while(ct > 0)
{
ADCSRA |= (1 << ADSC);
while(ADCSRA & (1 << ADSC));
ct--;
}
}
int16_t readtemp(uint8_t channel)
{
int16_t temp = 0;
ADCSRA &= ~(1 << ADEN);
ADCSRB = (1 << BIN) | (1 << GSEL) | (1 << MUX5);
ADMUX = (1 << REFS1) | (1 << MUX4) | (1 << MUX3) | (1 << MUX1); // measure offset
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);
dummyconversion(2);
temp = -readadc10s();
if(channel == 0)
{
ADMUX = (1 << REFS1);
}
else
{
ADMUX = (1 << REFS1) | (1 << MUX2) | (1 << MUX1);
}
dummyconversion(2);
temp += readadc10s();
return temp;
}