Temperaturmessung mit dem ATtiny85

Der ATtiny85 besitzt einen internen Temperatursensor (siehe Datenblatt Kapitel "17.12 Temperature Measurement"). Somit liegt die Idee nahe, ein digitales Thermometer mit einem OLED-Modul zu bauen. Nachteil dieses eingebauten Sensors ist natürlich, dass die Temperaturmessung verfälscht wird, wenn der Chip sich durch den Betrieb erwärmt. In der Hoffnung, dass die Rechenleistung nicht besonders ins Gewicht fällt, werden die Werte zumindest ungefähr stimmen.

Atmel ATtiny85 DIP-8
Abb.: Der Atmel ATtiny85 als DIP8-Version

Verwendete Bauteile

Anschlüsse und Aufbau

Anhand des Beitrags ATtiny können alle Anschlüsse und die Vorbereitungen für die Programmierung nachgelesen werden.
Der ATtiny85 hat auch zwei Pins für I²C (SCL + SDA), wie folgende Tabelle zeigt:

OLED ATtiny85
GND GND (Pin #4)
VCC VCC (Pin #8)
SCL PCINT2 (Pin #7)
SDA PCINT0 (Pin #5)

Programmierung

OLED mit dem ATtiny ansteuern

Mit den beiden Libraries TinyWireM und Tiny4kOLED kann das OLED-Modul leicht über die I²C-Schnittstelle angesprochen werden.

#include <TinyWireM.h>
#include <Tiny4kOLED.h>

void setup()
{
    oled.begin();
    oled.clear();
    oled.on();
    oled.setFont(FONT6X8);
}

void loop()
{
    oled.clear();
    oled.setCursor(0, 0);
    oled.print("Millis: " + String(millis()));

    // Swap which half of RAM is being written to, and which half is being displayed
    oled.switchFrame();

    delay(1000);
}

Temperatur auf dem OLED anzeigen

Auf Anne Barela's Blogseite wird beschrieben, wie man die Temperatur in °C auslesen und berechnen kann. Der folgende Sketch basiert auf diesen Berechnungen und zeigt die aktuelle Temperatur auf dem OLED-Modul an.

#include <TinyWireM.h>
#include <Tiny4kOLED.h>

#define TEMP_OFFSET 272.9
#define TEMP_COEFF 1.075

void setup()
{
  oled.begin();
  oled.clear();
  oled.on();
  oled.setFont(FONT6X8);
}

void loop()
{
  oled.clear();
  oled.setCursor(0, 0);
  oled.print("Temp.: " + String(getChipTemperatureCelsius()) + " °C");
  oled.switchFrame();
  delay(5000);
}

int getChipTemperatureCelsius()
{
  uint8_t vccIndex;
  float rawTemp, rawVcc;

  // Measure temperature
  ADCSRA |= _BV(ADEN); // Enable AD and start conversion
  ADMUX = 0xF | _BV( REFS1 ); // ADC4 (Temp Sensor) and Ref voltage = 1.1V;
  delay(100); // Settling time min 1 ms, wait 100 ms

  // use next sample as initial average
  rawTemp = (float)getADC();

  // calculate running average for 2000 measurements
  for (int i = 2; i < 2000; i++) {
    rawTemp += ((float)getADC() - rawTemp) / float(i);
  }

  ADCSRA &= ~(_BV(ADEN)); // disable ADC

  // Measure chip voltage (Vcc)
  ADCSRA |= _BV(ADEN); // Enable ADC
  ADMUX = 0x0c | _BV(REFS2); // Use Vcc as voltage reference, bandgap reference as ADC input
  delay(100); // Settling time min 1 ms, there is time so wait 100 ms

  rawVcc = (float)getADC(); // use next sample as initial average
  for (int i = 2; i < 2000; i++) { // calculate running average for 2000 measurements
    rawVcc += ((float)getADC() - rawVcc) / float(i);
  }
  ADCSRA &= ~(_BV(ADEN)); // disable ADC

  rawVcc = 1024 * 1.1f / rawVcc;
  //index 0..13 for vcc 1.7 ... 3.0
  vccIndex = min(max(17, (uint8_t)(rawVcc * 10)), 30) - 17;

  // Temperature compensation using the chip voltage
  // with 3.0 V VCC is 1 lower than measured with 1.7 V VCC
  return (int)(chipTemperature(rawTemp) + (float)vccIndex / 13);
}

float chipTemperature(float raw)
{
  return ((raw - TEMP_OFFSET) / TEMP_COEFF);
}

// Common code for both sources of an ADC conversion
int getADC()
{
  ADCSRA |= _BV(ADSC); // start conversion
  while ((ADCSRA & _BV(ADSC))); // wait until conversion is finished
  return ADC;
}
Temperatur wird auf dem OLED angezeigt
Abb.: Gemessene Temperatur des ATtiny wird auf dem OLED-Modul angezeigt.

Auf der Seite Thermometer-Attiny85 gibt es eine stromsparende Variante dieses Aufbaus, die die Temperatur als Blinksequenz auf einer LED anzeigt.

zurück