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.
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) |
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);
}
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;
}
Auf der Seite Thermometer-Attiny85 gibt es eine stromsparende Variante dieses Aufbaus, die die Temperatur als Blinksequenz auf einer LED anzeigt.
zurück