Forum: Mikrocontroller und Digitale Elektronik ADC: Zweiter Kanal misst nicht


von Daniel B. (scheinleistung)


Lesenswert?

Hallo zusammen,

Ich möchte am ADC Kanal 6 und Kanal 7 messen und das dann abspeichern in
variablen. Leider funktioniert es nicht mit Kanal 6, es sieht so aus als 
würde in der Variablen für Kanal 6 immer 0 drin stehen. Wo ist der 
Denkfehler?

Init:
1
//ADEN = Enable  ADIF = InterruptFlag  ADIE = InterruptEnable  ADPSx = ADC-Takt 
2
          //Teilerfaktor 128 
3
          ADCSRA |= (1<<ADEN) | (1<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
4
5
          //Auswahl des Messkanals (7) sowie Festlegung des Ref Signals (Hier 01 - AVCC)
6
          ADMUX  |= (1<<REFS0) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0);
7
  
8
          ADCSRA |= (1<<ADSC);     //Eine Dummy-Messung um den ADC zu initialisieren!

Messungen:
1
  // ADC Einzelmessungen
2
           if(convertNow == 1)
3
         {
4
        //Messe Kanal 7
5
        ADMUX  |= (1<<MUX0);          //Wechsel auf ADC Kanal 7 (111)
6
        ADCSRA |= (1<<ADSC);          //einzelne Messung
7
8
        //Messe Kanal 6
9
        ADMUX  &= ~(1<<MUX0);          //Wechsel auf ADC Kanal 6 (110)
10
        ADCSRA |= (1<<ADSC);          //einzelne Messung
11
  
12
        convertNow = 0;              //restart Counter
13
        }

Interrupt Routinen zum speichern:
1
ISR(ADC_vect)
2
{
3
  //Wenn Kanal 7 gemessen wird (111) also MUX0 = 1
4
  if(ADMUX &(1<<MUX0))
5
  {
6
    adcLevel7 = ADC;            //speichere ab
7
  }
8
  
9
  //Wenn Kanal 6 gemessen wird (110) also MUX0 = 0
10
  else if(!(ADMUX &(1<<MUX0)))
11
  {
12
    adcLevel6 = ADC;          //speichere ab
13
  }
14
15
}

von Benedikt K. (benedikt)


Lesenswert?

D. Berg schrieb:
> Wo ist der Denkfehler?

Hier:

> Messungen:
>
1
>   // ADC Einzelmessungen
2
>            if(convertNow == 1)
3
>          {
4
>         //Messe Kanal 7
5
>         ADMUX  |= (1<<MUX0);          //Wechsel auf ADC Kanal 7 (111)
6
>         ADCSRA |= (1<<ADSC);          //einzelne Messung
7
> 
8
>         //Messe Kanal 6
9
>         ADMUX  &= ~(1<<MUX0);          //Wechsel auf ADC Kanal 6 (110)
10
>         ADCSRA |= (1<<ADSC);          //einzelne Messung
11
> 
12
>         convertNow = 0;              //restart Counter
13
>         }
14
>

Du musst warten bis die erste Messung fertig ist, ehe du die zweite 
startest.

von Daniel B. (scheinleistung)


Lesenswert?

Aber ich arbeite doch mir Interrupt! Nach der ersten Messung wird der 
Interrupt gestartet und der Wert abgespeichert. Dann geht es zurück zur 
zweiten Messung und dann ebenfalls wieder nach der Messung Interrupt -> 
abspeichern.

von Benedikt K. (benedikt)


Lesenswert?

D. Berg schrieb:
> Nach der ersten Messung wird der
> Interrupt gestartet und der Wert abgespeichert.

Ja.

> Dann geht es zurück zur zweiten Messung

Da ist deine Software schon lange dran vorbei, denn nirgends steht, dass 
nach dem Start der ersten Messung gewartet werden soll, bis der 
Interrupt aktiv war.
Du könntest entweder im Interrupt die zweite Messung starten, oder du 
setzt im Interrupt eine Variable auf 1, die anzeigt dass der Interrupt 
die Ergebnisse gelesen hat.
Aber so macht der Interrupt keinen Sinn, wenn du sowieso auf das Ende 
der Messung wartest. Da kannst du auch den Interrupt weglassen, und 
stattdessen direkt auf das Ende der Messung warten und das Ergebnis 
auslesen ehe du die zweite Messung startest.

von Daniel B. (scheinleistung)


Lesenswert?

Jetzt habe ich es so probiert, ohne Interrupt mit Warteschleife:
1
  if(convertNow == 1)
2
         {
3
        //Messe Kanal7
4
        ADMUX  |= (1<<MUX0);          //Wechsel auf ADC Kanal 7 (111)
5
        ADCSRA |= (1<<ADSC);          //einzelne Messung
6
        while ( ADCSRA & (1<<ADSC) ) 
7
        { 
8
                                  // auf Abschluss der Konvertierung warten 
9
          }
10
        adcLevel7 = ADC;
11
12
13
        //Messe Kanal6
14
        ADMUX  &= ~(1<<MUX0);          //Wechsel auf ADC Kanal 6 (110)
15
        ADCSRA |= (1<<ADSC);          //einzelne Messung
16
        while ( ADCSRA & (1<<ADSC) ) 
17
        { 
18
                                  // auf Abschluss der Konvertierung warten 
19
          }
20
        adcLevel6 = ADC;
21
  
22
        convertNow = 0;              //restart Counter
23
        }

Funktioniert aber auch nicht, Kanal 7 misst, Kanal 6 nicht!

von noips (Gast)


Lesenswert?

Ist der Pin des Kanals 6 hardwaretechnisch in Ordnung? Ich habe schon 
mal einen Eingangs-Pin eines ADC aus Versehen durch zu hohe Spannung 
kaputt gemacht und bei der Wandlung hat der auch sehr kleine Werte 
gemessen obwohl die gleiche Spannung wie an anderen Kanälen angelegen 
hat. Wenn der betroffene Pin auch eine I/O-Funktion hat, versuch mal 
eine LED mit dem blinken zu lassen. Wenn das nicht geht, dann ist der 
Pin wohl nicht mehr OK.

von Diensthabender Troll (Gast)


Lesenswert?

Vielleicht mal das Konzept überdenken?

Z.B.:

In ISR ADC-Wert auslesen und (in Array) sichern, dann Index (auf 
Ergebnis und Mess-Quelle) erhöhen, (aus zweitem Array) neuen MUX-Wert 
holen und in ADMUX schreiben. Das legt Dir im Hintergrund die ADC-Werte 
verschiedener Quellen ins Array, auf das Du im Hauptprogramm jederzeit 
zugreifen kannst. Und es spart Rechenzeit, weil Du (nach der ersten 
Mess-Runde) nirgends auf die nächste Wandlung warten musst.

von Simon K. (simon) Benutzerseite


Lesenswert?

Diensthabender Troll schrieb:
> Vielleicht mal das Konzept überdenken?
>
> Z.B.:
>
> In ISR ADC-Wert auslesen und (in Array) sichern, dann Index (auf
> Ergebnis und Mess-Quelle) erhöhen, (aus zweitem Array) neuen MUX-Wert
> holen und in ADMUX schreiben. Das legt Dir im Hintergrund die ADC-Werte
> verschiedener Quellen ins Array, auf das Du im Hauptprogramm jederzeit
> zugreifen kannst. Und es spart Rechenzeit, weil Du (nach der ersten
> Mess-Runde) nirgends auf die nächste Wandlung warten musst.

Bei 16 Bit Werten muss man aber auf Atomizität achten. Also Double 
Buffer verwenden und dann wirds wieder aufwendig.

von Michael S. (captain-stone)


Lesenswert?

D. Berg schrieb:

> Funktioniert aber auch nicht, Kanal 7 misst, Kanal 6 nicht!

Hast Du schon mal versucht zuerst Kanal 6 abzufragen. Damit kannst Du 
die Suche eingrenzen. ADC oder Software von einer zur nächsten Wandlung 
n.i.O.

Michael

von Daniel B. (scheinleistung)


Lesenswert?

Gute Idee, sieht so aus als würde ich auch mit Kanal 6 alleine nichts 
hinbekommen, da stimmt irgendwas grunsätzliches nicht oder er hat 
wirklich einen Schaden...

von Karl H. (kbuchegg)


Lesenswert?

Du kannst auch mal die ADC Funktion aus dem Tutorial benutzen und die in 
einer Schleife mit abwechselnden Kanalnummern aufrufen.

von Daniel B. (scheinleistung)


Lesenswert?

OHHHH Leute ich hab glaub ich nen dummen Fehler gemacht... Ich messe die 
Spannung vor dem Optokoppler mit Kanal 6. Wegen der galvanischen 
Trennung haben die gar keine gemeinsame Masse! Gerade messe ich die 
Spannung un er misst 0V bezogen auf die uC Masse. Riesen Denkfehler! 
Wenn ich jetzt aber die Massen verbinde ist das ganze ja nicht mehr 
galvanisch getrennt, gibt es da einen Ausweg???

von noips (Gast)


Lesenswert?

Differenzverstärker zwischenschalten.

von Daniel B. (scheinleistung)


Lesenswert?

Wenn die beiden Schaltkreise gemeinsame Masse haben, ist das ganze dann 
noch einigermaßen gut galvanisch getrennt oder wars das dann sofort mit 
der Trennung. Ich möchte sicherstellen, dass der steuernde Kreis nicht 
rückwärts von meiner Elektronik gestört werden kann. Der steuernde Kreis 
berührt meine Elektronik aber nur am Input Capture Pin zum PWM einlesen. 
Was meint Ihr? Wie relevant ist hier die galvanische Trennung?

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.