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
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
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.
>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?
> 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."
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
Torsten W. schrieb:> Wie mache ich es richtig wenn ich die Versorgungsspannung des Attiny85> messen will?
Spannungsteiler an den Eingang und interne Referenz nutzen.
Wobei der Spannungsteiler vermutlich stromsparend sein sollte, also
hochohmig, und folglich noch einen Kondensator benötigt. Dieses Thema
hatten wir vor kurzem schon einmal.
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).
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
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.
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
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.
> 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
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.
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.
> 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.
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
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.
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
> 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
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
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")
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
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
longadc_result;//Gesamtergebnis der Messung des ADC
18
unsignedintvcc=0;//Versorgungsspannung
19
inth_as_int;
20
21
chardaten[10];
22
intID;//Sensor ID
23
intsensorPin=A1;//zum lesen der Daten
24
constintstrom=PB1;
25
intx;
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
voidsetup()
35
{
36
vw_setup(2000);// Bits per sec
37
vw_set_tx_pin(3);
38
pinMode(strom,OUTPUT);
39
}
40
41
voidloop()
42
{
43
ID=3;
44
internespannung();
45
sensorlesen();
46
//Virtual Wire
47
floath=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,sizeofdaten);// Inhalt der Variblen (char) löschen
53
//Schlafen gehen
54
for(inti=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
voidinternespannung(){
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
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.
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();
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