Thermocouple via Integrated Differential Amplifier
Recently, I needed a simple temperature switch which could withstand 400 °C. A thermocouple can easily manage this but its generated voltage is unpleasantly small. However, it turns out that a ATTiny216A’s integrated differential amplifier is absolutely sufficient for a, albeit not very accurate, measurement. Enough to determine if something is hot or not, at least.
Two thermocouples are connected and ADC1 serves as a reference for ADC0 and ADC2. A voltage divider adds some common mode voltage so the differential amplifier doesn’t have to work around 0 V (since the internal reference cannot be routed to the outside, this is necessary).
The differential amplifier’s offset can be compensated by connecting both of its inputs to the same pin and later subtracting the obtained conversion result. With an amplification factor of 32 and some oversampling this generated a usable indication. Again, don’t expect an accurate measurement (also note the lack of cold junction compensation).
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;
}