Hallo in die Runde,
ich möchte gerne an zwei Kanälen jeweils eine ADC-Messung vornehmen.
1. Kanal PB2 Feuchte der Erde
2. Kanal PB4 Batteriespannung
Jede einzelne Messung für sich funktioniert super gut. Wenn ich jedoch
beide Messungen hintereinander aufrufe beeinflusst die Messung am PB2
(Feuchte der Erde) die Messung am PB4 (Batteriespannung). Die Messung am
PB2 kann unter Umständen einen sehr hohen Wert haben (bis 980). Je höher
die Messung am Kanal 1 ist je höher auch die Abweichung. Bei einem Wert
am PB2 von 0 habe ich auch keine Abweichung an PB4 also je geringer die
Messung desto geringer die Abweichung bei der zweiten Messung.
Ich habe hier schon vieles gefunden jedoch nichts was mein Problem
gelöst hat.
Ich habe mehrere delay eingebaut um zu warten bis sich der ADC wieder
eingestellt hat. Auch habe ich mehrere Messungen hintereinander
ausgeführt jedoch ohne Erfolg.
Ich vermute ich habe einen Fehler im Code und sehe vor lauter Bäumen den
Wald nicht mehr :-(
Hier mal der Code für den 1 Kanal an PB2
1
voidsensorlesen(){
2
ADC=0;
3
y=0;
4
delay(250);
5
ADMUX|=(1<<REFS0)|(1<<MUX0);
6
delay(250);
7
ADCSRA|=(1<<ADEN);
8
delay(250);
9
ADCSRA|=(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1);
10
while(bitRead(ADCSRA,ADSC));
11
adc_low=ADCL;
12
adc_high=ADCH;
13
adc_result=(adc_high<<8)|adc_low;
14
y=adc_result;
15
ADMUX&=~(1<<REFS0);
16
ADMUX&=~(1<<MUX0);
17
ADCSRA&=~(1<<ADEN);
18
19
}
und hier der Code für den 2. Kanal an PB4
1
voidextern1(){//*****geht*****
2
ADC=0;
3
delay(250);
4
ADMUX|=(1<<REFS0)|(1<<MUX1);// Referenzspannung für den AD-Wandler an PB4
5
delay(250);//warten bis sich die Referenzspannung eingestellt hat
6
ADCSRA|=(1<<ADEN);//ADC aktivieren
7
delay(250);
8
for(inti=0;i<5;i++){//Mehrfachmessung dann verwerfen
9
ADCSRA|=(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1);
10
while(bitRead(ADCSRA,ADSC));
11
adcw=ADC;
12
}
13
ADCSRA|=(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1);
14
while(bitRead(ADCSRA,ADSC));
15
adcw=ADC;
16
vcc=ADC*2.46/1024*11*1000;
17
ADMUX&=~(1<<REFS0);
18
ADMUX&=~(1<<MUX1);
19
ADCSRA&=~(1<<ADEN);
20
21
}
Hier der Aufruf in der loop()
1
voidloop()
2
{
3
ID=3;
4
digitalWrite(strom,HIGH);
5
extern1();
6
sensorlesen();
7
digitalWrite(strom,LOW);
8
//Virtual Wire
9
floath=vcc;// Wert1 Long in Float wandeln
10
h_as_int=h;
11
sprintf(daten,"%d,%d, %d",ID,adcw,h_as_int);
12
vw_send((uint8_t*)daten,strlen(daten));
13
vw_wait_tx();// Wait until the whole message is gone
14
memset(daten,0,sizeofdaten);// Inhalt der Variblen (char) löschen
15
//Schlafen gehen
16
for(inti=0;i<1;i++){//Hier schläft er jetzt 8 Sekunden 450 ist eine ca Stunde
Hallo Torsten,
verwende eine niederohmige Quelle, schließe deine Sensoren über (puffer)
OPV mit vu=1 an.
Oder warte z.b. 1µs nach dem Umschalten des ADC-Eingangs, bevor die
ADC-Messung angestoßen wird.
Auch hilft eine mehrfach Messung und anschließender Mittelwertbildung
über 2^n Werte, mit n E {2,..,|N}.
Was soll der Unsinn mit dem ständigen ADC an und aus und Ref an und aus?
Setze einfach nur den Muxer neu.
Und schreibe ne Unterfunktion, der Du den MUX-Input übergibst und die
den ADC-Wert returnt. Copy&Paste ist nur unnötig fehlerträchtig.
Die Delays hau alle raus.
mach keinen Sinn!
Dadurch wird dann nach dem Aktivieren immer eine Dummywandlung notwendig
!
Stimmt der ADC-Wandlungstakt nach dem Datenblatt ?
Warum schreibst Du da so ?
1
ADCSRA|=(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1);
Der ADC-Wandlungstakt wird ja nicht geändert und gehört zur ADC-Init.
Schreibt man die ADC-Init neu, so kann man einfach einen neue
ADC-Messung wie folgt starten:
Ist das noch der ATtiny85? Wenn ja, dann wird mit
> ADMUX |= (1 << REFS0) | (1 << MUX1);
"External Voltage Reference at PB0 (AREF) pin" benutzt, wie sieht dies
aus?
Wenn mich meine mehr als mangelhaften C-Kenntnisse nicht täuschen, kommt
der Messwert aus sensorlesen nur in loop an, weil "ADC und ADCW sind
unterschiedliche Bezeichner für das selbe Registerpaar" gilt. Dann wäre
aber
> adc_low = ADCL;> adc_high = ADCH;> adc_result = (adc_high << 8) | adc_low;> y = adc_result;
in sensorlesen komplett für die Katz und
> adcw = ADC;
in extern1 ziemlich fragwürdig.
S. Landolt schrieb:> Ist das noch der ATtiny85? Wenn ja, dann wird mit>> ADMUX |= (1 << REFS0) | (1 << MUX1);> "External Voltage Reference at PB0 (AREF) pin" benutzt, wie sieht dies> aus?
Ja richtig, es ist immer noch der Attiny85. Ich habe an PB0 einen LM336
für die Referenzspannung zum VCC habe ich einen 2,2KOhm Widerstand nun
erhalte ich 2,56 Volt. Damit habe ich nicht mehr das Problem bei
sinkender Versorgungsspannung.
Karl M. schrieb:> Stimmt der ADC-Wandlungstakt nach dem Datenblatt ?
Der Attiny85 läuft mit 8 MHz Teilungsfaktor ist 64 müsste eigentlich
stimmen
Peter D. schrieb:> Setze einfach nur den Muxer neu.> Und schreibe ne Unterfunktion, der Du den MUX-Input übergibst und die> den ADC-Wert returnt.
Okay werde das noch mal neu schreiben. Wenn ich zwischen MUX0 und MUX1
wechsle muss ich dann nicht MUX0 deaktivieren also wieder auf 0 setzen
oder habe ich dich falsch verstanden?
S. Landolt schrieb:> Wenn mich meine mehr als mangelhaften C-Kenntnisse nicht täuschen, kommt> der Messwert aus sensorlesen nur in loop an, weil "ADC und ADCW sind> unterschiedliche Bezeichner für das selbe Registerpaar" gilt. Dann wäre> aber>> adc_low = ADCL;>> adc_high = ADCH;>> adc_result = (adc_high << 8) | adc_low;>> y = adc_result;> in sensorlesen komplett für die Katz und>> adcw = ADC;> in extern1 ziemlich fragwürdig.
Sorry, das verstehe ich leider nicht. adcw ist eine Int Variable der den
Wert von ADC auslesen soll. Vielleicht bin ich hier total auf dem
Holzweg?
Gruß
Torsten
Ich interpretiere obiges Zitat auf dieser Seite
http://www.mikrocontroller.net/articles/AVR_16-Bit-Register
so, dass ADCW bereits definiert und identisch zu ADC ist, eine Zuweisung
an ADCW erscheint mir wenig sinnvoll.
Und dann ist noch die Frage offen, wie der Messwert aus sensorlesen
nach loop kommt wenn nicht durch ADCW.
S. Landolt schrieb:> dass ADCW bereits definiert und identisch zu ADC ist, eine Zuweisung> an ADCW erscheint mir wenig sinnvoll.> Und dann ist noch die Frage offen, wie der Messwert aus sensorlesen> nach loop kommt wenn nicht durch ADCW.
Sorry mein Fehler: Ich habe adcw klein geschrieben und als int
definiert.
Werde aber in der neuen Version einen anderen Namen für die Variable
nutzen. Nutze ich ADCW (also groß geschrieben)funktioniert es in der Tat
nicht.
Wenn ich zwischen MUX0 und MUX1
wechsle muss ich dann nicht MUX0 deaktivieren also wieder auf 0 setzen?
Thorsten,
hinter der Kombination der MUXn stehen die verschiedenen ADC-Kanäle.
Wir denken in Kanälen, die einem Multiplex-Eingang aka MUXn entsprechen.
Also ja, Dein C Wissen musst Du um die Bitmanipulationen erweitern.
Karl M. schrieb:> Auch hilft eine mehrfach Messung und anschließender Mittelwertbildung> über 2^n Werte, mit n E {2,..,|N}.
Das hilft gegen Rauschen, aber nicht gegen falsche Messungen.
Man kann natürlich so viele Messungen mitteln, dass der Fehler niemandem
mehr auffällt, aber besser ist es, falsche Messungen gar nicht erst zu
machen bzw. sie zu verwerfen, bevor sie das Endergebnis verfälschen
können.
Karl M. schrieb:> hinter der Kombination der MUXn stehen die verschiedenen ADC-Kanäle.> Wir denken in Kanälen, die einem Multiplex-Eingang aka MUXn entsprechen.
Okay, das habe ich hoffentlich jetzt verstanden. Die Kanäle kann ich mir
im Datenblatt unter Table 17-4. aussuchen bzw. die richtigen Bits
setzen.
Ich habe jetzt mal folgendes probiert
1
voidneu1(){
2
ADMUX|=(1<<REFS0)|(1<<MUX0);//Sensor an PB2
3
ADCSRA|=(1<<ADPS2)|(1<<ADPS1);//Teilungsfaktor 64
4
ADCSRA|=(1<<ADEN);//ADC starten
5
ADCSRA|=(1<<ADSC);//DUMMY erste Messung an PB2 starten
6
while(bitRead(ADCSRA,ADSC));//warten bis Messung beendet ist
7
for(inti=0;i<4;i++){//Mehrfachmessung starten
8
ADCSRA|=(1<<ADSC);
9
while(bitRead(ADCSRA,ADSC));
10
y+=ADC;
11
}
12
y=y/5;
13
ADMUX&=~(1<<MUX0);//MUX0 deaktivieren
14
ADMUX|=(1<<MUX1);// Spannungsteiler an PB4
15
ADCSRA|=(1<<ADSC);//Dummy zweite Messung an PB4 starten
16
while(bitRead(ADCSRA,ADSC));//warten bis Messung beendet ist
17
for(inti=0;i<4;i++){//Mehrfachmessung starten
18
ADCSRA|=(1<<ADSC);
19
while(bitRead(ADCSRA,ADSC));
20
adcwert+=ADC;
21
}
22
adcwert=adcwert/5;
23
vcc=adcwert*2.46/1024*3.3*1000;//Umrechnug
24
ADMUX&=~(1<<MUX1);//MUX1 deaktivieren
25
}
Allerdings ändert sich an meinen Problem nichts. Je höher die Messung an
MUX0 ist desto schlechter wird das Ergebnis an MUX1.
Ist der Wert der Messung an MUX0 = 0 dann stimmt die Messung an MUX1.
Ich verstehe es nicht wo der Fehler ist?
Gruß
Torsten
Hallo Torsten,
y = 0 !
und trenne die ADC-Init von der ADC-Wandlung.
Wie Peter schon schrieb, nutzen wir dazu eine Funktion mit
Parameterübergabe des ADC-Kanals und mit Rückgabewert des
Messergebnisses.
Fehler sonst: siehe meinen ersten Beitrag "OPV".
Torsten W. schrieb:> Ich verstehe es nicht wo der Fehler ist?
Sind deine Signalquellen niederohmig genug?
Da deine Signale offensichtlich eher langsam sind, hilft evtl. auch ein
Kondensator am jeweiligen Multiplexereingang, der beim Umschalten des
Mux Ladung zum Umladen parasitäerer Kapazitäten liefert, ohne das die
Spannung sich zu sehr ändert (aus Sicht des ADC).
Torsten W. schrieb:> Ich verstehe es nicht wo der Fehler ist?Karl M. schrieb:> trenne die ADC-Init von der ADC-Wandlung.
Schalte die MUX Bits bitte nicht einzeln. Wähle einen Kanal aus, indem
Du ALLE MUX Bits korrekt setzt.
Also:
In der main während der Initialisierungsphase den ADC Konfigurieren. 1
mal!
In der mainloop eine Funktion für ADC aufrufen mit Übergabe des
Parameters, welcher Kanal gewandelt werden soll.
Diese Funktion setzt MUX auf den richtigen Kanal, startet eine Messung,
verwirft diese, macht noch eine Messung und gibt diesen Wert zurück.
Gruß
Jobst
Torsten W. schrieb:
> Ich verstehe es nicht wo der Fehler ist?
Da vor einigen Tagen die Ucc-Messung per interner Referenz auch eine
unerklärliche Abweichung ergab, liegt die Vermutung nahe, dass die
Hardware, also Netzteil, Aufbau etc., Probleme bereitet.
Hallo,
vielen lieben Dank für die vielen Antworten
Karl M. schrieb:> jetzt musst du auch einen Schaltplan und einige Bilder vom Aufbau> posten..
Mein Schaltplan ist eventuell ein wenig unübersichtlich, es ist mein
erster.
S. Landolt schrieb:> a vor einigen Tagen die Ucc-Messung per interner Referenz auch eine> unerklärliche Abweichung ergab, liegt die Vermutung nahe, dass die> Hardware, also Netzteil, Aufbau etc., Probleme bereitet.
Könnte es daran liegen das PB1 den Spannungsteiler, Referenzspannung,
und den Feuchtigkeitssensor mit Strom versorgt? Ich habe dies etwas
unschöne Lösung mir ausgedacht da Die Schaltung möglichst Stromsparend
sein soll.
Jobst M. schrieb:> In der main während der Initialisierungsphase den ADC Konfigurieren. 1> mal!
Also da sollte dann wohl dieses rein:
1
ADCSRA|=(1<<ADPS2)|(1<<ADPS1);//Teilungsfaktor 64
2
ADCSRA|=(1<<ADEN);//ADC starten
3
ADMUX|=(1<<REFS0);
Jobst M. schrieb:> Schalte die MUX Bits bitte nicht einzeln. Wähle einen Kanal aus, indem> Du ALLE MUX Bits korrekt setzt.
Dies verstehe ich noch nicht. MUX0 und MUX1 kann ich doch erst in der
Funktion setzen, oder?
Viele Grüße
Torsten
Torsten W. schrieb:> Mein Schaltplan ist eventuell ein wenig unübersichtlich, es ist mein> erster.
Der wird übersichtlicher, wenn du die Versorgung überall nach oben und
Gnd überall nach unten zeichnest (R2/R3, Sender, Feuchtigkeitssensor).
Spannungsteiler zeichnet man ebenfalls so, dass das Potential von oben
nach unten abnimmt (R1/IC1 senkrecht).
Ein Kondensator parallel zu R3 täte der Signalstabilität sicher gut.
dies verstehe ich leider nicht. In der ASCII Tabelle steht 0x1F für 31.
Bezieht sich der Kanal 0 auf den ADC0 an PB5?
0x1F ist dann wohl das Register? Also bei dem Attiny85 wäre 0x07 das
ADMUX Register.
Wie kann ich auf andere ADC Kanäle umstellen?
Danke und Gruß
Torsten
Torsten hast Du denn das Datenblatt des attiny85 für den ADC mal
komplett gelesen ?
Und auch verstanden ?
Und was hatte ich zu den Kanälen schon geschrieben ?
16.13.1 ADMUX – ADC Multiplexer Selection Register
REFS1 REFS0 MUX5 MUX4 MUX3 MUX2 MUX1 MUX0
Table 16-4.
Single-Ended Input channel Selections.
ADC0 (PA0) entspricht MUX[5:0] = 000000 = 0 dezimal
:
ADC7 (PA7) entspricht MUX[5:0] = 000111 = 7 dezimal
Für den attiny85 entspricht dies dem setzen eines neuen single-endet ADC
Kanals. Die alte/ vorherige Auswahl wird dabei wieder gelöscht.
Hier musst du verstehen wir, und (&) negieren (~) und oder (|)
funktioniert.
Torsten W. schrieb:> Jobst M. schrieb:>> Diese Funktion setzt MUX auf den richtigen Kanal, startet eine Messung,>> verwirft diese, macht noch eine Messung und gibt diesen Wert zurück.>> Wie genau mache ich das? Unter> https://www.mikrocontroller.net/articles/AVR-GCC-T...> habe ich folgendes gesehen> adcval = ADC_Read(0); // Kanal 0> in der ADC_Read() // Kanal waehlen, ohne andere Bits zu beeinflußen> ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);>> dies verstehe ich leider nicht.> In der ASCII Tabelle steht 0x1F für 31.>> Bezieht sich der Kanal 0 auf den ADC0 an PB5 und was genau bedeutet> 0x1F?
Ein attiny85 hat kein PB5
> Wie kann ich auf andere ADC Kanäle umstellen?>> Danke und Gruß> Torsten
Karl M. schrieb:> ADC0 (PB5) MUX[3:0] = 0000 binär = 0 dezimal> ADC1 (PB2) MUX[3:0] = 0001 binär = 1 dezimal> ADC2 (PB4) MUX[3:0] = 0010 binär = 2 dezimal> ADC3 (PB3) MUX[3:0] = 0011 binär = 3 dezimal> #define ADC_MUX_MASK ((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0))> ADMUX = (ADMUX & ~ADC_MUX_MASK) | (channel & ADC_MUX_MASK);
Danke, genau das hat mir gefehlt.
S. Landolt schrieb:> Spannungsteiler und Referenz sind erstmal vernachlässigbar, aber welchen> Strom nimmt der Sensor auf?
Ich habe mir jetzt mal das "Datenblatt" von dem Feuchtigkeitssensor
angeschaut
(http://www.fut-electronics.com/wp-content/plugins/fe_downloads/Uploads/moisture-sensor-arduino.pdf).
Ich denke das Problem ist hier: "Output Voltage signal 0 - 4,2 Volt". Da
meine interne Referenzspannung ja nur 2,46 Volt sind, könnte die Messung
die andere Messung beeinflussen, oder? Zumindest kann die Messung an
diesem Sensor ja nicht korrekt sein.
Wenn meine Vermutung richtig ist, könnte ich dann das Problem mit einen
Spannungsteiler lösen oder welche Möglichkeiten habe ich hier noch?
Viele Grüße
Torsten
Torsten W. schrieb:> Jede einzelne Messung für sich funktioniert super gut. Wenn ich jedoch> beide Messungen hintereinander aufrufe beeinflusst die Messung am PB2> (Feuchte der Erde) die Messung am PB4 (Batteriespannung). Die Messung am> PB2 kann unter Umständen einen sehr hohen Wert haben (bis 980). Je höher> die Messung am Kanal 1 ist je höher auch die Abweichung. Bei einem Wert> am PB2 von 0 habe ich auch keine Abweichung an PB4 also je geringer die> Messung desto geringer die Abweichung bei der zweiten Messung.
Das klingt nach Übersprechen. Du hast direkt an jedem ADC-Pin einen
Kondensator (>4,7nF) vom Pin nach Masse? Direkt heisst Leitungslänge
kleiner 1 cm?
Ein ADC erfasst das Messignal, indem er es in einem internen Kondensator
zwischenspeichert. Dazu wird kurzzeitig viel Strom benötigt. Lange
Leitungen stellen Induktivitäten dar, welche die Umladung behindern.
Dann misst der ADC immer eine Art Mittelwert aus dem aktuellen und dem
vorherigen Signal. Die Stützkondensatoren an den ADC-Pins machen die
Quellen niederohmiger, was den Effekt reduziert.