Forum: Mikrocontroller und Digitale Elektronik Frage zur Spannungsmessung mit Attiny 45


von Torsten W. (toto1975)


Lesenswert?

Hallo in die Runde,

ich bin auf diesen Gebiet noch ein Anfänger und habe nun ein kleines 
Problem.

Ich möchte mit folgenden Code die Spannung messen mit der der Attiny45 
versorgt wird. Dabei ist mir eine hohe(?) Differenz zwischen meinen 
Multimeter und dem Attiny45 aufgefallen.

Hier die Daten:
Multimeter zeigt eine Spannung von 4,9 Volt an
Attiny45 jedoch nur 4,0 Volt macht eine Differenz von 0,9 Volt. Wenn ich 
den Attiny45 mit 3x AA Akkus betreiben möchte und mir anzeigen möchte 
wann die Akkus zu neige gehen habe ich bei so einer hohen Differenz ja 
fast keine Chance frühzeitig die Akkus zu wechseln.

Bei den Akkus wird nur ein sehr geringer Strom entnommen da die meiste 
Zeit der Attiny45 schläft. Welchen Wert würdet ihr nehmen? Sind 1,2 Volt 
schon zu spät (Bei der Schwankung bestimmt)?

Bei Alkalime Batterien hätte ich dieses Problem ja nicht so stark da die 
Spannung fast konstant abnimmt was jedoch bei Akkus fast nicht der Fall 
ist.

Wie kann ich meinen Code verbessern um eine genauere Messung mir 
anzeigen zu lassen?
1
int led = 1;  //Pin der LED
2
int adc_low, adc_high;  //Zwischenspeicher für die Ergebnisse des ADC
3
long adc_result;  //Gesamtergebnis der Messung des ADC
4
long vcc;  //Versorgungsspannung
5
6
void setup() {    
7
  pinMode(led, OUTPUT);  
8
9
  ADMUX |= (1<<REFS1); //VCC als Referenzspannung für den AD-Wandler
10
  ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC 
11
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
12
  ADCSRA |= (1<<ADEN);   //ADC aktivieren
13
}
14
15
// the loop routine runs over and over again forever:
16
void loop() {    
17
  ADCSRA |= (1<<ADSC);  //Messung starten
18
19
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
20
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
21
  adc_low = ADCL;
22
  adc_high = ADCH;
23
24
  adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
25
  vcc = 1125300 / adc_result;  //Versorgungsspannung in mV berechnen (1100mV * 1023 = 1125300)
26
27
  //wenn Spannung kleiner als 4V
28
  if (vcc < 4000)
29
  {
30
    digitalWrite(led, HIGH);  //schalte LED an
31
  }
32
  //wenn größer oder gleich 4V
33
  else 
34
  {
35
    digitalWrite(led, LOW);  //schalte LED aus
36
  }
37
38
  delay(500);
39
}

Danke und Gruß
Torsten

PS: Den Code habe ich aus dem Internet und nur die Werte für ADMUX laut 
Datenblatt angepasst.

von m.n. (Gast)


Lesenswert?

Torsten W. schrieb:
> ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung
> als Eingang für ADC

Das ist der falsche Eingang. 12 wäre BG!

Torsten W. schrieb:
> vcc = 1125300 / adc_result;  //Versorgungsspannung in mV berechnen
> (1100mV * 1023 = 1125300)

Hier sind +/- 10% Toleranz möglich.

von Torsten W. (toto1975)


Lesenswert?

m.n. schrieb:
> Torsten W. schrieb:
>> ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung
>> als Eingang für ADC
>
> Das ist der falsche Eingang. 12 wäre BG!
>
> Torsten W. schrieb:
>> vcc = 1125300 / adc_result;  //Versorgungsspannung in mV berechnen
>> (1100mV * 1023 = 1125300)
>
> Hier sind +/- 10% Toleranz möglich.

Danke für die schnelle Antwort.
Ich habe jetzt mal im Datenblatt (ab Seite 134) nachgeschaut muss aber 
gestehen das ich daraus nicht wirklich schlau werde. Was meinst Du mit 
"Das ist der falsche Eingang. 12 wäre BG!"

Gruß
Tortsen

von m.n. (Gast)


Lesenswert?

Du kannst natürlich auch schreiben:
ADMUX |= (1<<MUX3) | (1<<MUX2);
was bei geänderten Kanälen zu Fehlern führen wird.

Ich schreibe immer lieber die Kanalnummer (hier 12):
ADMUX = (1<<REFS1) | kanal_nr;

Und auch hier: adc_result = (adc_high<<8) | adc_low;
schreibe ich lieber: adc_result = adc;

Oder einfach als Funktion:

uint16_t lese_adc(uint8_t kanal)
{
  ADMUX =  BIT(REFS0)| kanal;  // Vcc als Vref, rechtsbuendig
  ADCSRA |= BIT(ADSC);         // starten
  while(ADCSRA & BIT(ADSC));   // warten
  return(ADC);                 // fertig
}

von m.n. (Gast)


Lesenswert?

ganz vergessen:
#define BIT(x)  (1<<x)

von Sascha W. (sascha-w)


Lesenswert?

@Thorsten,

des weiteren ist die Referenzspannungsquelle zwar recht konstant aber 
nicht besonders genau. Der Chip muss halt billig sein und da kann man 
die nicht noch kalibrieren.
Also musst du in der Software abgleichen, du kannst dir den Messwert 
ausgeben lassen wenn du schaltungstechnich die Möglichkeit hast und den 
ermittelten Wert dann in dein Programm einbauen. Oder du baust eine 
Funktion ein die dir für einen festen Spannungswert den Faktor berechnet 
und im EEProm speichert.

Sascha

von holger (Gast)


Lesenswert?

>  ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);

Laut Datenblatt ist diese Einstellung "not available".
Prescaler wurde auch keiner eingestellt.
Kein Wunder das da was komisches rauskommt.

von Holger L. (max5v)


Lesenswert?

Torsten W. schrieb:
> Sind 1,2 Volt
> schon zu spät (Bei der Schwankung bestimmt)?

In der V Variante geht es bis zu 1.8 Volt herunter, da wären 1,2 Volt 
bereits zu wenig.

Die 0,9 Volt Differenz können evtl. unter anderem auch durch den 
Spannungsteiler entstehen, Widerstände haben nicht immer den 
aufgedruckten Wert.

Da der Adc-Wert anscheinend nur zur Warnung vor zu geringer 
Betriebsspannung da zu sein scheint bietet es sich an den Wert einmal 
auszurechnen und direkt den ADC-Wert, also ohne Umrechnung, zu 
verwenden.

Übrigens gibt es noch den Brownoutdetector, ob der bei dieser Anwenung 
passt mußt du natürlich selber wissen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.