Forum: Mikrocontroller und Digitale Elektronik Frage zur Betriebsspannung messen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich benötige wieder mal eure Hilfe. Ich habe einen Attiny85 der mit 4 
GoldCaps a 5,5 Volt; 1,5 Farat mit Strom versorgt wird. Die Goldcaps 
werden mit Hilfe einer Solarzelle aufgeladen.

Ich möchte nun die Versorgungsspannung des Attiny85 messen und habe dazu 
folgenden Code geschrieben.
1
int adc_low, adc_high;  //Zwischenspeicher für die Ergebnisse des ADC
2
long adc_result;  //Gesamtergebnis der Messung des ADC
3
unsigned int vcc = 0;  //Versorgungsspannung
4
int h_as_int;
5
6
char daten[10];
7
int ID;
8
9
//Virtual Wire
10
#include <VirtualWire.h>
11
12
13
void setup ()
14
  {
15
  vw_setup(1000); // Bits per sec
16
  vw_set_tx_pin(3);// 
17
18
  ADMUX |= (1<<REFS0); //VCC als Referenzspannung für den AD-Wandler
19
  ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC 
20
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
21
  ADCSRA |= (1<<ADEN);   //ADC aktivieren 
22
  delay(150);
23
  }
24
25
  void loop() 
26
  {
27
  ADMUX |= (1<<REFS0); //VCC als Referenzspannung für den AD-Wandler
28
  ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC 
29
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
30
  ADCSRA |= (1<<ADEN);   //ADC aktivieren 
31
  delay(150);
32
  ID=3;  
33
  memset(daten, 0, sizeof daten); 
34
  ADCSRA |= (1<<ADSC);  //Messung starten
35
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
36
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
37
  adc_low = ADCL;
38
  adc_high = ADCH;
39
40
  adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
41
  //adc_result = adc;
42
  vcc = 1125300L / adc_result;  //Versorgungsspannung in mV berechnen (1100mV * 1023 = 1125300)
43
  delay(1000);
44
  //Virtual Wire
45
 float h = vcc;                               // Wert1 Long in Float wandeln
46
 h_as_int = h;   
47
48
 sprintf(daten, "%d,%d", ID, h_as_int);
49
   //delay(1000); 
50
   vw_send((uint8_t *)daten, strlen(daten));
51
   vw_wait_tx(); // Wait until the whole message is gone
52
53
 //Schlafen gehen
54
   for (int i=0; i<1; i++){  //Hier schläft er jetzt 8 Sekunden 450 ist eine Stunde
55
      //goToSleep ();
56
      delay(5000);
57
   }  
58
  }

Irgendwo muss sich der Fehlerteufel einschlichen haben. Ich bekomme 
folgende Werte:
adc_result = immer 1023
ADCL = immer 255
ADCH = immer 3
Endergebnis: 1.100

Die 1.100 entsprechen ja eigentlich der Referenzspannung als Eingang für 
ADC
1
 ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC

Ich bin mir nicht sicher ob insbesondere folgende Zeilen richtig sind
1
ADMUX |= (1<<REFS0); //VCC als Referenzspannung für den AD-Wandler
2
ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC

und
1
ADCSRA |= (1<<ADSC);  //Messung starten
2
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
3
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
4
  adc_low = ADCL;
5
  adc_high = ADCH;

Ich bin für jede Hilfe dankbar und bin mir sicher das ihr mir 
weiterhelfen könnt

Viele Grüße
Torsten

von Crazy H. (crazy_h)


Bewertung
0 lesenswert
nicht lesenswert
Ich hoffe doch, daß du noch einen Spannungsteiler vor dem ADC hast? 
Ansonsten ist deine Betriebsspannung immer größer die Referenzspannung 
und ist am Anschlag = 1023.

: Bearbeitet durch User
von holger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Irgendwo muss sich der Fehlerteufel einschlichen haben. Ich bekomme
>folgende Werte:
>adc_result = immer 1023

Vollausschlag bei jeder Messung. Hast du einen Spannungsteiler
an deinen ADC Eingang gelegt?

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> ADMUX |= (1<<REFS0); //VCC als Referenzspannung für den AD-Wandler

Ohne mir den Rest angeschaut zu haben, im Datenblatt lese ich "External 
Voltage Reference at PB0 (AREF) pin, Internal Voltage Reference turned 
off."

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jetzt bin ich irritiert, reden wir wirklich vom ATtiny85?
> ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1); ...
Dafür finde ich im Datenblatt nur "N/A".

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Ja Attiny 85 ist richtig. Ich habe mir den Code von mehreren Webseiten 
"zusammen gebastelt" deswegen war ich mir auch bei der Zeile nicht 
sicher ob dies stimmt.

Ich hatte immer gedacht ich brauche keinen Spannungsteiler da ich mit 
den internen 1,1 Volt arbeite als Referenzspannung.

S. Landolt schrieb:
> Ohne mir den Rest angeschaut zu haben, im Datenblatt lese ich "External
> Voltage Reference at PB0 (AREF) pin, Internal Voltage Reference turned
> off."

Das habe ich leider nicht gesehen... So langsam habe ich das Gefühl 3 
Tage Google waren für die Katze :-(

Wie mache ich es richtig wenn ich die Versorgungsspannung des Attiny85 
messen will?

Danke für eure Hilfe ich weiß das sehr zu schätzen.

Gruß
Torsten

von Erwin D. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Torsten W. schrieb:
> Wie mache ich es richtig wenn ich die Versorgungsspannung des Attiny85
> messen will?

Spannungsteiler an den Eingang und interne Referenz nutzen.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wobei der Spannungsteiler vermutlich stromsparend sein sollte, also 
hochohmig, und folglich noch einen Kondensator benötigt. Dieses Thema 
hatten wir vor kurzem schon einmal.

von S. Landolt (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Das Problem ist, dass man beim ATtiny85 den ADC-Eingang nicht auf die 
eigene Referenz schalten kann wie zum Beispiel beim ATmega328 (auf 
diesen würden obige ADMUX-Einstellungen passen).

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Das Problem ist, dass man beim ATtiny85 den ADC-Eingang nicht auf die
> eigene Referenz schalten kann wie zum Beispiel beim ATmega328 (auf
> diesen würden obige ADMUX-Einstellungen passen).

Okay also diese Zeile dann raus
1
ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC

Erwin D. schrieb:
> Spannungsteiler an den Eingang und interne Referenz nutzen.

Den Spannungsteiler lege ich dann an PB0 an, richtig? Die interne 
Referenz aktiviere ich mit
1
ADMUX |= (1<<REFS1);
Ist das so weit alles richtig?

Gruß
Torsten

S. Landolt schrieb:
> Wobei der Spannungsteiler vermutlich stromsparend sein sollte,
> also
> hochohmig, und folglich noch einen Kondensator benötigt. Dieses Thema
> hatten wir vor kurzem schon einmal.

Ja richtig es soll sehr stromsparend sein. Würde ein 10µF Kondensator 
ausreichen? Der wäre ja schnell wieder aufgeladen oder wie groß sollte 
er sein?

Im Moment habe ich nur 10kOhm und 1KOhm Wiederstände da. die würden für 
den Anfang denke ich erst mal genügen, oder?

Danke für die wertvollen Tipps

Gruß
Torsten

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Zum Probieren reichen diese Widerstände, aber sie ziehen bei z.B. 5.0 V 
rund 450 uA, das ist enorm viel im Hinblick auf die Goldcaps. Wenn noch 
ein Pin frei ist, könnte man den Spannungsteiler schaltbar machen.
  Bei diesen 10k + 1 k ist kein Kondensator nötig, die sind hinreichend 
niederohmig für den ADC-Eingang.

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Hallo noch mal,

vielen Dank erst mal für die Hilfe. Ich habe jetzt den Spannungsteiler 
mit 10KOhm und 1Kohm an PB0 gelegt. Die Werte ändern sich nun auch 
allerdings habe ich bei einer Spannung von 4,92 Volt (kommt vom Arduino 
mit Multimeter nachgemessen) ein Ergebnis von nur 3,90 Volt also ein 
Volt niedriger. Ich habe zwar gelesen das es eine Schwankung von 10% 
geben kann aber 1 Volt ist dann doch ein wenig viel. Habe ich hier noch 
einen Fehler im Code?
1
void setup ()
2
  {
3
  vw_setup(1000); // Bits per sec
4
  vw_set_tx_pin(3);// 
5
6
  ADMUX |= (1<<REFS0); //VCC als Referenzspannung für den AD-Wandler
7
  ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);  //1.1V Referenzspannung als Eingang für ADC 
8
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
9
  ADCSRA |= (1<<ADEN);   //ADC aktivieren 
10
  delay(150);
11
  }
12
13
  void loop() 
14
  {
15
  ADMUX |= (1<<REFS1); //VCC als Referenzspannung für den AD-Wandler
16
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
17
  ADCSRA |= (1<<ADEN);   //ADC aktivieren 
18
  delay(150);
19
  ID=3;  
20
  memset(daten, 0, sizeof daten); 
21
  ADCSRA |= (1<<ADSC);  //Messung starten
22
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
23
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
24
  adc_low = ADCL;
25
  adc_high = ADCH;
26
27
  adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
28
  //adc_result = adc;
29
  vcc = 1125300L / adc_result;  //Versorgungsspannung in mV berechnen (1100mV * 1023 = 1125300)
30
  delay(1000);
31
  //Virtual Wire
32
 float h = vcc;                               // Wert1 Long in Float wandeln
33
 h_as_int = h;   
34
35
 sprintf(daten, "%d,%d", ID, adc_result);
36
   //delay(1000); 
37
   vw_send((uint8_t *)daten, strlen(daten));
38
   vw_wait_tx(); // Wait until the whole message is gone
39
40
 //Schlafen gehen
41
   for (int i=0; i<1; i++){  //Hier schläft er jetzt 8 Sekunden 450 ist eine Stunde
42
      //goToSleep ();
43
      delay(5000);
44
   }  
45
  }

Danke und Gruß
Torsten

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Bei diesem Programm verstehe ich nicht mehr viel, mag aber auch daran 
liegen, dass ich kein C kann (und noch keinen Kaffee hatte). Ich finde 
kein main, wo wird setup aufgerufen?

> ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1);
ist undefiniert beim ATtiny85, hatten wir doch schon.

> ADMUX |= (1<<REFS0);
> ADMUX |= (1<<REFS1);
nacheinander ausgeführt ergibt '(1<<REFS0) | (1<<REFS1)', auch dies ist 
"reserved", also undefiniert.

Wo sind die angegebenen 3.9 V ersichtlich?
Bei der 1.1 V-Referenz ist zu beachten, dass sie mit 1.0 .. 1.2 V 
spezifiziert ist.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Spannungsteiler mit 10KOhm und 1Kohm an PB0 gelegt
PB0 lässt sich doch gar nicht als ADC-Eingang schalten.

So ungefähr:
Mitte des Spannungsteilers an PB4 (==ADC2)
ADMUX = (1<<REFS1) | (1<<MUX1)
Wandlung (irgendwas mit ADCSRA)
Ergebnis = ADC * 1.1/1024 * 11

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Sorry, da ist gestern wohl einiges beim Kopieren schief gelaufen...

Hier noch mal richtig:
1
void setup ()
2
  {
3
  vw_setup(1000); // Bits per sec
4
  vw_set_tx_pin(3);// 
5
  }
6
7
  void loop() 
8
  {
9
  ADMUX |= (1<<REFS1); 
10
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
11
  ADCSRA |= (1<<ADEN);   //ADC aktivieren 
12
  delay(150);
13
  ID=3;  
14
  memset(daten, 0, sizeof daten); 
15
  ADCSRA |= (1<<ADSC);  //Messung starten
16
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
17
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
18
  adc_low = ADCL;
19
  adc_high = ADCH;
20
21
  adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
22
  //adc_result = adc;
23
  vcc = 1125300L / adc_result;  //Versorgungsspannung in mV berechnen (1100mV * 1023 = 1125300)
24
  delay(1000);
25
  //Virtual Wire
26
 float h = vcc;                               // Wert1 Long in Float wandeln
27
 h_as_int = h;   
28
29
 sprintf(daten, "%d,%d", ID, adc_result);
30
   //delay(1000); 
31
   vw_send((uint8_t *)daten, strlen(daten));
32
   vw_wait_tx(); // Wait until the whole message is gone
33
34
 //Schlafen gehen
35
   for (int i=0; i<1; i++){  //Hier schläft er jetzt 8 Sekunden 450 ist eine Stunde
36
      //goToSleep ();
37
      delay(5000);
38
   }  
39
  }

S. Landolt schrieb:
> Ich finde
> kein main, wo wird setup aufgerufen?

die main ist hier die loop() und die setup() wird einmalig beim Start 
ausgeführt danach nicht mehr.

S. Landolt schrieb:
> Wo sind die angegebenen 3.9 V ersichtlich?

Ich lasse mir den gemessenen Wert des Attiny85 per Funkübertragung auf 
einen Arduino Uno anzeigen

Was noch auffällt ist, je geringer die Spannung wird desto größer wird 
auch die Differenz zwischen dem gemessenen Wert vom Attiny85 und dem 
Wert des Multimeter. Bei 5 Volt sind es "nur" 0,5 Volt bei 2,5 Volt sind 
es schon 1,45 Volt.

Bei gleichbleibender Spannung bleibt auch der gemessene Wert des 
Attiny85 gleich.

von Holger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Torsten W. schrieb:
> Sorry, da ist gestern wohl einiges beim Kopieren schief gelaufen...

Ein Hinweis zur Lesbarkeit:
Füge bitte die c-Tags zum Code hinzu.
1
Oben [c] und unten [/c]
Danke :-)

von Holger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
So sieht es mit den Tags aus:
1
void setup ()
2
  {
3
  vw_setup(1000); // Bits per sec
4
  vw_set_tx_pin(3);// 
5
  }
6
7
  void loop() 
8
  {
9
  ADMUX |= (1<<REFS1); 
10
  delay(10);  //warten bis sich die Referenzspannung eingestellt hat
11
  ADCSRA |= (1<<ADEN);   //ADC aktivieren 
12
  delay(150);
13
  ID=3;  
14
  memset(daten, 0, sizeof daten); 
15
  ADCSRA |= (1<<ADSC);  //Messung starten
16
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
17
  //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
18
  adc_low = ADCL;
19
  adc_high = ADCH;
20
21
  adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
22
  //adc_result = adc;
23
  vcc = 1125300L / adc_result;  //Versorgungsspannung in mV berechnen (1100mV * 1023 = 1125300)
24
  delay(1000);
25
  //Virtual Wire
26
 float h = vcc;                               // Wert1 Long in Float wandeln
27
 h_as_int = h;   
28
29
 sprintf(daten, "%d,%d", ID, adc_result);
30
   //delay(1000); 
31
   vw_send((uint8_t *)daten, strlen(daten));
32
   vw_wait_tx(); // Wait until the whole message is gone
33
34
 //Schlafen gehen
35
   for (int i=0; i<1; i++){  //Hier schläft er jetzt 8 Sekunden 450 ist eine Stunde
36
      //goToSleep ();
37
      delay(5000);
38
   }  
39
  }

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> ADMUX |= (1<<REFS1);
Das heißt also, die Mitte des Spannungsteilers liegt an ADC0 == PB5.

> ADCSRA |= (1<<ADEN);
Der ADC-Takt ist systemclock/2 - das ist wohl deutlich zu schnell.

> sprintf(daten, "%d,%d", ID, adc_result);
Da verstehe ich noch nicht, wie aus adc_result die 3.9 V werden.

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
>> ADMUX |= (1<<REFS1);
> Das heißt also, die Mitte des Spannungsteilers liegt an ADC0 == PB5.

Nein, da habe ich wohl einiges durcheinander gebracht im Moment liegt er 
noch an AREF PB0 an. Werde ich aber heute Abend ändern.
1
ADMUX = (1<<REFS1) | (1<<MUX1) | (1<<MUX0);

um an PB3 also ADC3 anzuschließen.

S. Landolt schrieb:
>> ADCSRA |= (1<<ADEN);
> Der ADC-Takt ist systemclock/2 - das ist wohl deutlich zu schnell.

Okay, würde folgendes helfen:
1
ADCSRA |= (1<<ADSC) | (1<<ADPS2)
Der ADC-Takt ist nun systemclock/16 (wenn ich das Datenblatt richtig 
gelesen habe) oder ist dies immer noch zu schnell? Der Attiny85 läuft 
mit 8 MHz

S. Landolt schrieb:
>> sprintf(daten, "%d,%d", ID, adc_result);
> Da verstehe ich noch nicht, wie aus adc_result die 3.9 V werden.

Ich habe 1125300 / adc_result /1.000 mit dem Taschenrechner gerechnet 
:-| Ich will erst mal andere Fehler ausschließen

Sorry für die Fragen aber ich bin absoluter Anfänger was das angeht... 
Aber so langsam kommt Licht ins dunkel auch was das lesen des Datenblatt 
angeht.

Gruß
Torsten

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Zum ADC-Takt: "between 50 kHz and 200 kHz to get maximum resolution"
Für höhere Geschwindigkeit (bei geringerer Auflösung) kann man bis 1 MHz 
gehen, ist hier ja aber nicht sinnvoll, also wäre
ADCSRA |= (1<<ADSC) | (1<<ADPS2) | (1<<ADPS1)
für 125 kHz = 8 MHz /64 angebracht.

Die Berechnung mit dem Taschenrechner ist mir unklar, ich halte
Ergebnis = ADC * 1.1/1024 * 11
(wie bereits geschrieben) für richtig.

> Aber so langsam kommt Licht ins dunkel
Das sehe ich auch so; angefangen haben wir alle einmal, und zum 
Autodidakten geeignet sind nur wenige.

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Super vielen lieben Dank jetzt funktioniert alles wie es soll und ich 
habe nur eine Abweichung von 0.04 Volt gegenüber meinem Multimeter.

Eine letzte Frage habe ich allerdings noch (nur damit ich weiß was ich 
da mache :-))

S. Landolt schrieb:
> Ergebnis = ADC * 1.1/1024 * 11

Warum * 11?

ADC ist der Wert von ADCL und ADCH
1.1 ist wohl die Referenzspannung
1024 ist wohl 0 - 1023

aber was bedeuten die 11?

Viele Grüße
Torsten

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Der Spannungsteiler 10 k + 1 k untersetzt 11:1.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> nur eine Abweichung von 0.04 Volt
So viel Glück hatte ich nicht, die mir vorliegende, schon etwas ältere 
Charge brachte bei 8 MHz deutliche Abweichungen, besser wurde es erst 
mit 1 MHz oder dem Noise-Reduction-Mode; vielleicht lag es aber auch am 
Steckbrettaufbau.

Nun wünsche ich viel Erfolg bei der nächsten Stufe, dem Stromsparen, und 
möchte mich für diesmal verabschieden.

Gruß aus dem Südwesten

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Deine Hilfe war wirklich super!! Besten Dank dafür

Viele Grüße
Torsten

von spess53 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

S. Landolt (Gast) schrieb

>Das Problem ist, dass man beim ATtiny85 den ADC-Eingang nicht auf die
>eigene Referenz schalten kann wie zum Beispiel beim ATmega328 (auf
>diesen würden obige ADMUX-Einstellungen passen).

Was ist mit

MUX[3:0]   Single Ended
               Input

 1100          VBG  ?

MfG Spess

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
an Spess:
Sie haben vollkommen Recht, meine Güte keine Ahnung, wie mir das 
entgehen konnte; danke für den Hinweis.

an Torsten Wegmann:
War die Hilfe doch nicht so besonders, Entschuldigung. Ihr erster Ansatz 
war also sehr wohl zielführend, und um meinen Fehler halbwegs wieder 
gutzumachen, hier ein kurzer Abriss zum Vorgehen (in der Hoffnung, dass 
es diesmal stimmt):

also, nix Spannungsteiler
ADMUX = (1<<MUX3) | (1<<MUX2)  // Vcc als Referenz, Eingang auf Vbg
ADSCRA wie gehabt
Ergebnis = Vbg * 1024/ADC   // mit Vbg = 1.1 V  (1.0 .. 1.2 V)


("2. After switching to internal voltage reference the ADC requires a 
settling time of 1ms before measurements")

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich hab das gleiche mal auf einem Attiny25 gemacht, hier mal mein Code 
dazu.
Was noch fehlt ist die Umrechnung des ADC-Werts in eine Spannung, das 
war bei mir nicht nötig, da ich einfach nur auf zwei Stufen verglichen 
habe.

Die Tabelle gibt die gemessene Spannung für 1,0V und für 1,1V 
Referenzspannung an, da die interne Referenz +-10% Toleranz hat. (Falls 
relevant, müsste man den Fall 1,21V auch noch betrachten)
1
// Spannungen in mV
2
3
/*
4
         ADC-Wert
5
Akku          1,0V    1,1V  
6
5,0V =         204    225
7
4,2V =         243    268
8
3,4V =         301    331
9
3,1V =         330    363
10
11
3,8
12
*/
13
14
#define UNTERSPANNUNG_1    331    // nur noch geringe Helligkeit möglich
15
#define UNTERSPANNUNG_2    363    // Abschaltung
16
17
18
static void adc_init()
19
{
20
  ADCSRA |= (1<<ADPS2);  // prescaler 16 --> 125 kHz
21
  
22
  ADMUX |= (1<<MUX3) | (1<<MUX2);  // input: bandgap; reference: Vcc
23
}
24
25
26
27
#define NUMBER_SAMPLES  4
28
29
static uint16_t adc_measure()
30
{
31
  ADCSRA |= (1<<ADEN);  // enable ADC
32
  ADCSRA |= (1<<ADSC);  // start conversion
33
  while (ADCSRA & (1<<ADSC))  ;  // wait for first conversion complete
34
  
35
  uint8_t i;
36
  uint16_t adc = 0;
37
  
38
  for (i=0; i<NUMBER_SAMPLES; i++)
39
  {
40
    ADCSRA |= (1<<ADSC);  // start conversion
41
    while (ADCSRA & (1<<ADSC))  ;  // wait for conversion complete
42
    adc += ADC;
43
  }
44
  adc = adc / NUMBER_SAMPLES;
45
  
46
  ADCSRA &= ~(1<<ADEN);  // disable ADC (power reduction)
47
  
48
  return adc;
49
}
50
51
52
53
static void adc_pruefen()
54
{
55
  uint16_t adc_result;
56
  
57
  adc_result = adc_measure();
58
  
59
  if (adc_result < UNTERSPANNUNG_1)  // Akku voll
60
  {
61
    max_helligkeit = ANZAHL_STUFEN;
62
  }
63
  else if (adc_result < UNTERSPANNUNG_2)  // Akku fast leer
64
  {
65
    max_helligkeit = 0;    // nur minimale Helligkeit zulassen
66
    
67
    // PWM aktualisieren
68
    helligkeit = max_helligkeit;
69
    set_pwm(pwmtable_8B[helligkeit]);
70
  }
71
  else  // Akku leer --> ausschalten
72
  {
73
    shut_down = 0xFF;
74
  }
75
  
76
}

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> War die Hilfe doch nicht so besonders, Entschuldigung.

Doch die Hilfe war schon sehr gut... Ich konnte sehr viel lernen ;-)

S. Landolt schrieb:
> also, nix Spannungsteiler
> ADMUX = (1<<MUX3) | (1<<MUX2)  // Vcc als Referenz, Eingang auf Vbg
> ADSCRA wie gehabt
> Ergebnis = Vbg * 1024/ADC   // mit Vbg = 1.1 V  (1.0 .. 1.2 V)

Funktioniert super gut.

Ich habe nun allerdings ein anderes Problem:

Ich habe einen Analogen Sensor der die Feuchtigkeit messen soll von 
Funduino. Dieser hängt an A1 um mit analogRead(sensorPin) ausgelesen 
werden soll. Dieser zeigt mir allerdings jetzt die Spannung an (denke 
ich).

Ich habe dazu folgenden Code:
1
/*
2
 Name:    Feuchtigkeitssensor.ino
3
 Created:  16.09.2016 23:42:17
4
 Author:  torsten
5
*/
6
7
// ATMEL ATTINY 25/45/85 / ARDUINO
8
//
9
//                  +-\/-+
10
// Ain0 (D 5) PB5  1|    |8  Vcc
11
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
12
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
13
//            GND  4|    |5  PB0 (D 0) pwm0
14
//                  +----+
15
16
17
long adc_result;                      //Gesamtergebnis der Messung des ADC
18
unsigned int vcc = 0;                    //Versorgungsspannung
19
int h_as_int;
20
21
char daten[10];
22
int ID;                            //Sensor ID
23
int sensorPin = A1;                      //zum lesen der Daten
24
const int strom = PB1;
25
int x;
26
27
#include <avr/sleep.h>                    // Sleep Modes
28
#include <avr/power.h>                    // Power management
29
#include <avr/wdt.h>                    // Watchdog timer
30
//Virtual Wire
31
#include <VirtualWire.h>
32
33
34
void setup()
35
{
36
  vw_setup(2000);                      // Bits per sec
37
  vw_set_tx_pin(3); 
38
  pinMode(strom, OUTPUT);
39
}
40
41
void loop()
42
{
43
  ID = 3;
44
  internespannung();
45
  sensorlesen();
46
  //Virtual Wire
47
  float h = vcc;                      // Wert1 Long in Float wandeln
48
  h_as_int = h;
49
  sprintf(daten, "%d,%d, %d", ID, x, h_as_int);
50
  vw_send((uint8_t *)daten, strlen(daten));
51
  vw_wait_tx();                      // Wait until the whole message is gone
52
  memset(daten, 0, sizeof daten);              // Inhalt der Variblen (char) löschen
53
  //Schlafen gehen
54
  for (int i = 0; i < 1; i++) {                //Hier schläft er jetzt 8 Sekunden 450 ist eine Stunde
55
    //goToSleep ();
56
    delay(5000);
57
  }
58
}
59
  
60
61
void internespannung() {
62
  //Spannung Messen start  
63
  ADMUX = (1 << MUX3) | (1 << MUX2);            //VCC als Referenzspannung für den AD-Wandler
64
  delay(10);                        //warten bis sich die Referenzspannung eingestellt hat
65
  ADCSRA |= (1 << ADEN);                  //ADC aktivieren 
66
  delay(30);
67
  ADCSRA |= (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1);  //Messung starten
68
  delay(10);
69
  while (bitRead(ADCSRA, ADSC));              //warten bis Messung beendet ist
70
                              //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
71
                              //adc_low = ADCL;
72
                              //adc_high = ADCH;
73
74
                              //adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
75
                              //adc_result = adc;
76
  ADCSRA &= ~(1 << ADEN);                    //disable ADC (power reduction)
77
  ADMUX &= ~(1 << MUX3);  //wieder zurück stellen
78
  ADMUX &= ~(1 << MUX2);  //wieder zurück stellen
79
  vcc = 1.1 * 1024 / ADC;
80
  //Spannung Messen Ende
81
}
82
83
void sensorlesen() {
84
  //Sensor Daten lessen
85
  int lauf = 3;
86
  digitalWrite(strom, HIGH);
87
  delay(150);
88
  analogRead(sensorPin);                  //Probemessung
89
  delay(100);
90
  for (int i = 0; i < lauf; i++) {
91
    delay(100);
92
    x += analogRead(sensorPin);
93
  }
94
  x = x / lauf;
95
  digitalWrite(strom, LOW);
96
}

Wenn ich die void internespannung() nicht aufrufe werden mir die 
korrekten Daten angezeigt. Ich habe auch mit
1
  ADCSRA &= ~(1 << ADEN);                    //disable ADC (power reduction)
2
  ADMUX &= ~(1 << MUX3);
3
  ADMUX &= ~(1 << MUX2);
versucht alles wieder zurück zustellen aber leider ohne Erfolg

Jemand eine Idee?

Viele Grüße
Torsten

: Bearbeitet durch User
von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Ich noch mal

ich habe jetzt versucht mit
1
 void test() {
2
  digitalWrite(strom, HIGH);
3
  delay(150);
4
  ADMUX = (1 << MUX0);                  //PB2 AIN1
5
  delay(10);
6
  ADCSRA |= (1 << ADEN);                  //ADC aktivieren
7
  ADCSRA |= (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1);  //Messung starten
8
  delay(10);
9
  while (bitRead(ADCSRA, ADSC));              //warten bis Messung beendet ist
10
  y = ADC;
11
  ADCSRA &= ~(1 << ADEN);                    //disable ADC (power reduction)
12
  digitalWrite(strom, LOW);
13
}

Die Analoge Messung zu machen was auch funktioniert allerdings 
funktioniert jetzt die Interne Messung der Spannung nicht mehr
1
void internespannung() {
2
  //Spannung Messen start  
3
  ADMUX = (1 << MUX3) | (1 << MUX2);            //VCC als Referenzspannung für den AD-Wandler
4
  delay(10);                        //warten bis sich die Referenzspannung eingestellt hat
5
  ADCSRA |= (1 << ADEN);                  //ADC aktivieren 
6
  delay(30);
7
  ADCSRA |= (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1);  //Messung starten
8
  delay(10);
9
  while (bitRead(ADCSRA, ADSC));              //warten bis Messung beendet ist
10
                              //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
11
                              //adc_low = ADCL;
12
                              //adc_high = ADCH;
13
14
                              //adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
15
                              //adc_result = adc;
16
  ADCSRA &= ~(1 << ADEN);                    //disable ADC (power reduction)
17
  ADMUX &= ~(1 << MUX3);
18
  ADMUX &= ~(1 << MUX2);
19
  vcc = 1.1 * 1024 / ADC * 100;
20
  ADC = 0;
21
  //Spannung Messen Ende
22
}

Ich rufe zu erst die test() und danach die internespannung() auf.

Was mache ich hier verkehrt?

Viele Grüße
Torsten

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich habe keine Ahnung von diesem analogRead, aber es scheint doch so, 
dass darin eine andere Einstellung für ADC-Takt und/oder 
Referenzspannung verwendet wird. Also herausfinden, welches diese 
ist/sind (ADCSRA und ADMUX nach dem ersten analogRead-Aufruf auslesen 
und anzeigen); dann kann man entsprechend voreinstellen.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vermutlich lässt sich das auch irgendwo nachlesen.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Will man es gar nicht so genau wissen, geht vermutlich auch etwas in der 
Art (für das Programm von 16:12 (dass sich seither aber auch kein 
anderer meldet!?)):

ADMUX_sensor  = ADMUX;
ADCSRA_sensor = ADCSRA;
internespannung();
ADMUX  = ADMUX_sensor;
ADCSRA = ADCSRA_sensor;
sensorlesen();

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
Ich wundere mich halt nur! Die Funktion die ich als erstes Aufrufe 
funktioniert. Rufe ich zuerst
1
 void internespannung() {
2
  //Spannung Messen start  
3
  ADMUX = (1 << MUX3) | (1 << MUX2);            //VCC als Referenzspannung für den AD-Wandler
4
  delay(10);                        //warten bis sich die Referenzspannung eingestellt hat
5
  ADCSRA |= (1 << ADEN);                  //ADC aktivieren 
6
  delay(30);
7
  ADCSRA |= (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1);  //Messung starten
8
  delay(10);
9
  while (bitRead(ADCSRA, ADSC));              //warten bis Messung beendet ist
10
                              //Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
11
                              //adc_low = ADCL;
12
                              //adc_high = ADCH;
13
14
                              //adc_result = (adc_high<<8) | adc_low; //Gesamtergebniss der ADC-Messung 
15
                              //adc_result = adc;
16
  ADCSRA &= ~(1 << ADEN);                    //disable ADC (power reduction)
17
  ADMUX &= ~(1 << MUX3);
18
  ADMUX &= ~(1 << MUX2);
19
  vcc = 1.1 * 1024 / ADC * 100;
20
  ADC = 0;
21
  //Spannung Messen Ende
22
}
 auf funktioniert diese und nur diese.

Rufe ich zuerst
1
void test() {
2
  digitalWrite(strom, HIGH);
3
  delay(150);
4
  ADMUX = (1 << MUX0);                  //PB2 AIN1
5
  delay(10);
6
  ADCSRA |= (1 << ADEN);                  //ADC aktivieren
7
  ADCSRA |= (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1);  //Messung starten
8
  delay(10);
9
  while (bitRead(ADCSRA, ADSC));              //warten bis Messung beendet ist
10
  y = ADC;
11
  ADCSRA &= ~(1 << ADEN);                    //disable ADC (power reduction)
12
  digitalWrite(strom, LOW);
13
}

dann funktioniert nur die.... aber leider nie beide zusammen.

Muss ich vor der nächsten Messung ein Reset durchführen oder irgendwas 
in der Richtung das sich alles wieder auf 0 setzt. Ich habe fast das 
Gefühl das mit ADCSRA &= ~(1 << ADEN); nicht alles gelöscht bzw. auf 
null gesetzt wird.


S. Landolt schrieb:
> Ich habe keine Ahnung von diesem analogRead,

Diese Funktion nutze ich im Moment gar nicht mehr... Ich will ja wissen 
was da passiert :-)

Viele Grüße
Torsten

von Torsten W. (toto1975)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> (für das Programm von 16:12 (dass sich seither aber auch kein
> anderer meldet!?)):

Verstehe ich nicht, was meinst du genau?

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn der Vorschlag von 19:23 nicht funktioniert, muss ich passen; dann 
muss einer der vielen Arduino-Anwender hier im Forum weiterhelfen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.