Nachdem ich schon vor einiger Zeit etwas mit Spannungsüberwachung gemacht habe, nehme ich das Thema noch einmal neu auf und erweitere die Software für mehrere Atmel AVR Prozessoren, die die interne Spannungsüberwachung unterstützen. Das sind ATMega328, ATMega2560 und ATTiny 25/45/85.
Aus den Datenblättern ergibt sich eine Unterscheidung bei der Initialisierung. Das Auslesen ist bei allen gleich. Die Varianten werden per define als Compilerschalter angelegt.
Headerfile
/****************************************************************************
* (c) 2019 softwareentwicklung-als-prozess.de
* Funktionalitaet:
* Spannungsueberwachung mit dem ADC
***************************************************************************/
#ifndef VCTL_HEADER
#define VCTL_HEADER
#define VCTL_VCCOK 5000l
#define VCTL_VCCLOW 4500l
void vctl_Setup(void);
long vctl_Measure(void);
#endif
Cpp Datei
/****************************************************************************
* (c) 2019 softwareentwicklung-als-prozess.de
* Funktionalitaet:
* interne Spannungsueberwachung mit dem ADC
***************************************************************************/
#include <arduino.h>
#include "vctl.h"
// verfuegbar fuer folgende Prozessoren - immer nur einen setzen
#define ATMEGA328
//#define ATMEGA2560
//#define ATTINY25_45_85
//#define ANDERE
#ifdef ATMEGA328
void vctl_Setup(void)
{
ADMUX |= (1 << REFS0); // VCC als Referenzspannung
ADMUX |= (1 << MUX3) | (1 << MUX2) | (1 << MUX1); // VBG als Eingang
delay(10); // warten bis sich die Referenzspannung eingestellt hat
ADCSRA |= (1 << ADEN); // ADC enable
}
#endif
#ifdef ATMEGA2560
void vctl_Setup(void)
{
ADMUX |= (1 << REFS0); // VCC als Referenzspannung
ADMUX |= (1 << MUX4) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1); // VBG als Eingang
delay(10); // warten bis sich die Referenzspannung eingestellt hat
ADCSRA |= (1 << ADEN); // ADC enable
}
#endif
#ifdef ATTINY25_45_85
void vctl_Setup(void)
{
ADMUX = 0; // VCC als Referenzspannung
ADMUX |= (1 << MUX3) | (1 << MUX2); // VBG als Eingang
delay(10); // warten bis sich die Referenzspannung eingestellt hat
ADCSRA |= (1 << ADEN); // ADC enable
}
#endif
#ifdef ANDERE
void vctl_Setup(void)
{
// je nach Prozessor - siehe Datenblatt / Datasheet
}
#endif
#if defined(ATMEGA328) || defined(ATMEGA2560) || defined(ATTINY25_45_85)
long vctl_Measure(void)
{
int adcl, adch;
long result;
vctl_Setup(); // fuer jede Messung neu
ADCSRA |= (1 << ADSC); // starten
while (bitRead(ADCSRA, ADSC)); // bis Messung beendet ist
// Wichtig: zuerst ADCL auslesen, dann ADCH
adcl = ADCL;
adch = ADCH & 0x03; // ADLAR ist standardmaessig auf 0
// also die oberen 6 bit loeschen
result = (adch << 8) | adcl;
return(1125300L / result); // Spannung in millivolt: 1100mV * 1023 = 1125300
}
#endif
#ifdef ANDERE
long vctl_Measure(void)
{
// je nach Prozessor - siehe Datenblatt / Datasheet
return(0l);
}
#endif
Test
Getestet habe ich mit einem Arduino Uno (ATMega328P) und einem Arduino Mega 2560 (ATMega2560) und einem ATTiny85 auf einem Breadboard explizit aufgebaut. Angeschlossen an ein Labornetzteil, um die Spannung verändern zu können. Der Sketch dazu ist aus „NTC Thermometer mit Korrektur“ entnommen und erweitert mit den obigen Sourcen.
Ergebnis
Die Spannungsmessung hat bei allen funktioniert. Jedenfalls solange man auf dem Display überhaupt noch etwas erkennen konnte… Diesen Wert braucht man auf jeden Fall, wenn man Sensoren einsetzt und deren Messwert in physikalische Einheiten umrechnet.
Links
Spannungsüberwachung
http://physudo.blogspot.de/2014/08/spannung-uberwachen-am-arduino-atmega.html
Spannungsüberwachung und Brown Out Erkennung
https://blog.softwareentwicklung-als-prozess.de/spannungsueberwachung-und-brown-out-erkennung
Verwaltung von Varianten einer Software
https://blog.softwareentwicklung-als-prozess.de/varianten-einer-software-verwalten
NTC Thermometer mit Korrektur
https://blog.softwareentwicklung-als-prozess.de/ntc-thermometer-mit-korrektur