www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Beschaltung von mehreren ADC Eingängen


Autor: Daniel H. (doomstar)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Hab mal wieder ein kleines Problem.

Bin gerade dabei mit meinem Atmega32 4 ADC werte einzulesen das klappt 
auch alles einwandfrei wenn ich immer nur 1 ADC benutze. Sobald ich aber 
mehrere benutze und die Kanäle wechsele bekomme ich sehr merkwürdige 
Werte. Hab im Anhang ein Teil meiner Platine (jedoch sind die Dioden im 
moment nur brückendrähte.

Wie im Toturial beschrieben nutze ich eine einfache variante, denn 
Spannungsteiler. Wenn ich jedoch jetzt die Kanäle ändere ist auf allen 
Kanälen +- 20 jeder wert gleich und eine änderung bring so gut wie keine 
veränderung mehr.

Jetzt die Frage:

Kann es sein das dadurch dass alle ADC Kanäle die gleiche Masse nutzen 
der Wert verfäscht wird und das ich dies durch Dioden verhindern kann?

Wie gesagt wenn ich die Kanäle nicht ändere geht alles einwandfrei nur 
wenn sie geändert werden spinnt auf einmal alles.

Ach ja bevor ich es vergesse: Selbst wenn nur an einem Kanal meine 
Spannung anliegt gibt er mir den richtigen Wert aus wenn ich nur diesen 
Messe, sobald ich jedoch mehrere (Kanal wächsele) Messen will spinnt 
wieder alles.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. wrote:
> Hi
>
> Hab mal wieder ein kleines Problem.
>
> Bin gerade dabei mit meinem Atmega32 4 ADC werte einzulesen das klappt
> auch alles einwandfrei wenn ich immer nur 1 ADC benutze. Sobald ich aber
> mehrere benutze und die Kanäle wechsele bekomme ich sehr merkwürdige
> Werte.
Es ist meist sinnvoll (auch wenn es nicht explizit im Datenblatt steht) 
nach dem Umschalten auf einen anderen Kanal eine kurze Wartezeit 
einzufügen (ein paar zig µs). Versuch das mal.

> Hab im Anhang ein Teil meiner Platine (jedoch sind die Dioden im
> moment nur brückendrähte.
Es gibt in EAGLE die Möglichkeit, sogenannte Junctions an den 
Verbindungspunkten von Signalen zu platzieren, damit man sehen kann, 
dass an der Stelle tatsächlich eine Verbindung vorliegt und keine 
Kreuzung. Bei Dir ist überhaupt nicht erkennbar, wo da Verbindungen sind 
und wo nicht. Kleiner Tip: Ziehe die Signale im Schaltplan nicht mit 
Wire sondern mit Net. Dann werden die Junctions automatisch gemacht.

> Wie im Toturial beschrieben nutze ich eine einfache variante, denn
> Spannungsteiler. Wenn ich jedoch jetzt die Kanäle ändere ist auf allen
> Kanälen +- 20 jeder wert gleich und eine änderung bring so gut wie keine
> veränderung mehr.
>
> Jetzt die Frage:
>
> Kann es sein das dadurch dass alle ADC Kanäle die gleiche Masse nutzen
> der Wert verfäscht wird und das ich dies durch Dioden verhindern kann?
Nein, wenn die "Masse" die selbe Masse wie das AGND des Controllers ist, 
dann kann das eigentlich nicht sein und die Dioden werden da auch nichts 
bewirken. Aber auch das ist dem Schaltplanschnipsel nicht zu 
entnehmen...

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schonmal Danke für den Eagle Tip. Werde ich gleich mal Testen. Also 
Brauche ich die Dioden doch nicht.

Warte Zeit hab ich schon ca 300 Ms da er die Werte über den selben lcd 
Ausgeben soll. Kann das ja nicht so schnell machen sonnst kann mann es 
ja nicht lesen.

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist echt ziemlich komisch. Wenn ich zum Beispiel 2 Messungen 
durchführe beide auf ADC 0 kein Prob alles geht oder 2 Messungen auf ADC 
1 ebenfalls kein Prob. Sobald ich aber eine auf ADC 0 mache und die 
andere auf ADC 1 dann simmt nichts mehr.

jemand nee Idee?

Gruß
Daniel

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. wrote:
> Das ist echt ziemlich komisch. Wenn ich zum Beispiel 2 Messungen
> durchführe beide auf ADC 0 kein Prob alles geht oder 2 Messungen auf ADC
> 1 ebenfalls kein Prob. Sobald ich aber eine auf ADC 0 mache und die
> andere auf ADC 1 dann simmt nichts mehr.
>
> jemand nee Idee?

Wie sieht denn Deine Messung softwaremäßig aus? Könnte ja sein, dass da 
der Hase im Pfeffer liegt...

...

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die oben angesprochene Wartezeit (von ca. 120µs) MUSS zwischen 
Umschalten des MUX oder der Betriebsart (single-ended oder 
differentiell) eingehalten werden. Also erst MUX umschalten, dann die 
Displayausgabe, dann messen. Dann sollte es funktionieren.

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok es gibt schon wieder neuigkeiten.

Also wegen den Pausen hab da ein delay von 250ms drinne darann denke ich 
kann es nicht liegen.

Code kann ich Posten ist aber schon ein Stücken (300 Zeilen).

Ich Schalte jetzt nach jeder Messung den ADC ab und jetzt sieht man 
wenigstens einen deutlichen unterschied. Jedoch beeinflussen sich die 
beiden Messungen doch irgendwie. Wenn ich die Spannung an ADC0 verändere 
dann steigt ADC1 mitjedoch nicht gleich sondern nur im verhältnis.

Alle Messschaltungen (Sensor + Teilerwiederstand) nutzen eine gemeinsame 
Masse und Spannungsversorgung wie in der Zeichnung dargestellt.

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast aber nicht immer nur einen Eingang beschaltet und alle Anderen 
Eingänge sind offen? Das würde einiges erklären ...

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im moment sind nur 2 mit Sensoren bestückt der Rest nicht die liegen 
brach was bedeutet das keine externen Sensoren dran hängen.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. wrote:
> Im moment sind nur 2 mit Sensoren bestückt der Rest nicht die liegen
> brach was bedeutet das keine externen Sensoren dran hängen.

Dann solltest Du die nicht benutzten Eingänge auf definiertes Potential 
(z.B. GND) legen.

...

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Hannes

Hab ich doch gemacht. Aber leider bringt das auch nichts. Wenn ich ein 
Sensor komplett weglasse geht es einwandfrei.

Kennt jemand eine schaltung mit mehreren Sensoren aus dem Kopf die hier 
im Netz rumschwebt wo ich einfach mal nachgucken könnte?#

MFG
Daniel

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. wrote:
> @ Hannes
>
> Hab ich doch gemacht. Aber leider bringt das auch nichts. Wenn ich ein
> Sensor komplett weglasse geht es einwandfrei.

Irgendwie verstehe ich nicht, wie Du das meinst. Was verstehst Du unter 
"weglassen"? Wenn ein Eingang abgefragt ist, sollte er auch beschaltet 
sein. Ansonsten wird Müll eingelesen.

>
> Kennt jemand eine schaltung mit mehreren Sensoren aus dem Kopf die hier
> im Netz rumschwebt wo ich einfach mal nachgucken könnte?#

Was für Sensoren??
Wenn Potis zwischen GND und AVCC auch (im weitesten Sinne) als sensoren 
akzeptiert werden, dann kenne ich eine Schaltung samt Software:
http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html
Bei der sind die eingelesenen ADC-Werte recht stabil, obwohl weder 
Oversampling noch Mittelwertberechnung angewendet wird.

...

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
wenn gar nicht anders verwende nur einen AD-Kanal und einen externen 
Multiplexer, welchen du über Portpins ansteuerst.

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also als sensoren meine im moment PT100 oder Poti (ein veränderbaren 
Wiederstand). Mit weglassen ist gemeint: immer 2 Kontakte an x2, x3 ,x4 
gehören zusammen. Versorgungsspannung wird über die Leiste rausgegeben 
durch z.B.PT100 durchgeleitet und dann an den ADC eingang 
weitergeleitet. Gleichzeitig wird mit jeweils einem Wiederstand ein 
Spannungsteiler aufgebaut um einen Spannungsteiler aufzubauen (PT100 + 
Wiederstand). Die Dioden auf meinem Bild werden ja nich benötigt und 
sind somit durch Brückendraht ersetzt worden und verbinden den 
Spannungsteiler somit an meine Masse.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. wrote:

> Code kann ich Posten ist aber schon ein Stücken (300 Zeilen).

abspecken, abspecken.
Um 2 ADC abzufragen reichen 20 Zeilen ebenfalls.
Die LCD Routinen kannst du beim Posten weglassen,
wir glauben dir auch so, dass die funktionieren.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PT100 (mit Widerstand als Spannungsteiler) direkt am AVR-ADC-Eingang?

Auf diese Idee wäre ich nie gekommen. Ich habe den PT100 zwar noch nicht 
benutzt, gehe aber davon aus, dass seine temperaturabhängige 
Widerstandsänderung zwar sehr linear, aber recht klein ist. Ich 
vermutete also, dass der Aufwand der Signalaufbereitung den Nutzen 
übersteigt.

In einem Temperatur-Regler für einen alten E-Boiler nutze ich als Sensor 
einen Heißleiter, ist zwar nicht ganz linear, aber für den Zweck gut 
genug. Ist aber nur eine Mess-Stelle, auch kein Mega32 (ich mag nicht 
immer gleich mit Kanonen auf Spatzen schießen), sondern nur ein Mega48 
mit LCD 2x16 und 4 Tasten.

...

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die übliche PT100-Anwendung wäre: Konstantstrom (1mA) über den Fühler 
und den Spannungsabfall über dem Sensor messen (Vierleitertechnik). Das 
(mV-) Messsignal verstärken und einen Offset abziehen (Bereich auf 0..5V 
anpassen), dann ist es vernünftig mit einem AVR zu messen. Die 
Linearisierung (falls nötig) ist mit µC auch kein Problem, z.B. mit 
Look-up-Tabelle.

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ja nur ein Beispiel. Im moment betreibe ich 2 Potentiometer um 
veränderbare Wiederstande zu simulieren.

Den Code Poste ich gleich mal in abgespeckter fassung. Ist ja nicht 
alles wichtig für den ADC

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Code:

void adc_init (void) { // ADC init
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0); // ADC aktiviert, 
Prescaler auf 32, ADC Interrupt enabled

         ADMUX = (1<<MUX1) | (1<<MUX0); // ADC Channel 3
  ADMUX |= (1<<REFS0); // AVCC als Referenzspannung nutzen


  ADCSRA |= (1<<ADSC); // erste Wandlung Starten zum justieren
    while ( ADCSRA & (1<<ADSC)); // Warten bis die Wandelung 
abgeschlossen ist

  int tata = ADCW;

}
int adc (int mux) { // ADC Wert auslesen

  adc_init();

  int result=0;
  ADMUX |= mux; // Channel wählen

  for( int i=0; i<6; i++ ) {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) {
      ;   // auf Abschluss der Konvertierung warten
  }
    result += ADCW;        // Wandlungsergebnisse aufaddieren
  }

  result = result / 6;                     // Summe durch sechs teilen = 
arithm. Mittelwert

  ADCSRA = 0;

  return result;

}

void testmode (void) { // Test Mode zum testen der Signale

  int save = 0;

  sei(); // Global Interrupt enabled

  while(1) //Endlos schleife
  {

  lcd_clrscr();
  lcd_gotoxy(0,0);
  lcd_puts("Wert 1:");
  lcd_gotoxy(0,1);
  lcd_puts("Wert 2:");

  save = adc(3); // Wert 1 holen

         lcd_gotoxy(11,0);
  lcd_puts("      ");
  lcd_gotoxy(11,0);
  itoa (save, buffer, 10);
  lcd_puts(buffer);

  pause (1000);

  save = adc(2); // Wert 2 holen
  lcd_gotoxy(11,1);
  lcd_puts("      ");
  lcd_gotoxy(11,1);
  itoa (save, buffer, 10);
  lcd_puts(buffer);

  pause (1000);

}
}


void powerup (void) { // Start Sequenz

  lcd_init(LCD_DISP_ON); // Display Initalisierung
  DDRC = 0x00; // PORT C als Eingang deklariert
  PORTC = 0x00; // Pull up Wiederstand aus
  lcd_clrscr(); // LCD Komplett Löschen

  timer_init(); // Timer starten
  adc_init(); // ADC starten

         testmode();
}
int main(void){ // Main
  powerup();
  while(1)
  {
  }

  return 1;
}


So das ist er nun in abgespeckter Fassung. ICP fehlt und ein paar 
kleinigkeiten.

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielleicht eine C-Übung für mich (mache sonst nur ASM)...

int adc (int mux) { // ADC Wert auslesen

  adc_init();

  int result=0;
  ADMUX |= mux; // Channel wählen

1. Aufruf mit mux = 1 (Kanal 1), also 0b00000001

2. Aufruf mit mux = 2 (Kanal 2), also 0b00000010

ADMUX ist also 1, ADMUX |= mux; sollte also 3 ergeben, vermutlich nicht 
das, was Du erwartest.

Von ADMUX also erst alle MUX-Bits ausblenden, ADMUX = (ADMUX & 0xF0) | 
mux

Muß mal bitte ein C-User in die richtige Syntax bringen.

Gruß aus Berlin
Michael

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du musst darauf achten dass du FRÜHESTENS 40µs nach der Umschaltung des 
MUX die Wandlung einleitest (nach ändern der Betriebsart single-ended 
<=> differentiell sogar 120µs). Diese Zeit braucht der Analogschalter 
(MUX) zum Durchschalten. Andernfalls wird es immer Hausnummern geben.

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das passt aber nicht sonderlich zum Datenblatt.

MUXX und REFS werden bei Beginn der Wandlung übernommen, nur die 
Änderung von REFS versaut die erste Wandlung, die zweite ist schon ok.

Klappt bei mir auch ganz praktisch so.

Zumindest bei den gängigen ATMega 8/16/32.

Gruß aus Berlin
Michael

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit MUX steht gar nicht drin, ist aber so. Wenn du eine 
Dummy-Wandlung vorausschickst hast du nix anderes als 'ne Pause gemacht. 
;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael U. wrote:
> Von ADMUX also erst alle MUX-Bits ausblenden,
> ADMUX = (ADMUX & 0xF0) | mux;
>
> Muß mal bitte ein C-User in die richtige Syntax bringen.

Perfekt

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal eine Version von mir, auch wenn durch den _delay-Befehl Zeit 
verplempert wird: ;-)

double ADC_conversion(unsigned char mux, unsigned char MW) // Spannung messen (single ended)
{  
 ADMUX = mux;                 // Multiplexer-Modus einstellen
 delay_us(40);                // Pause bis Multiplexer eingestellt ist
 double Messwert = 0;
 unsigned int ADC_temp;
 unsigned char i = 1;
    
 do
   {
    ADCSRA |= (1<<ADSC);       // 'single conversion' einleiten
    while(!(ADCSRA & 0x10));   // auf ende der Wandlung warten, ADIF flag '1'
    ADC_temp = ADCL;           // ADCL Register lesen
    ADC_temp += (ADCH << 8);   // ADCH Register lesen      
    Messwert += ADC_temp;      // Ergebnisse der Messungen addieren
    i++;                       // Schleifenzähler erhöhen
   }
 while (i <= MW);              // MW Messungen für bessere Genauigkeit 
 Messwert = Messwert/MW;       // Mittelwert der Messungen der double-Variable zuweisen
  
 return (Messwert);
}

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@Power: Atmel sagt, daß der MUX vor Beginn der Wandlung gesetzt werden 
soll. Frühestens 1 ADC-Takt nach Beginn der Wandlung kann der MUX 
bereits wieder umgeschaltet werden, übernommen wird die Einstellung mit 
dem nächsten Start einer Wandlung. Das ging bisher auch immer bei mir.

Ein Dummy-Zyklus wird nur nach Ändern der Betriesart oder der 
Referenzspannung gefordert, unabhängig von Wartezeiten.
Es heißt nur, daß das erste Wandlungsergebnis nach Änderung von AREF 
ungültig sein kann und man besser verwerfen soll.

Bis jetzt haben meine AVR das Datenblatt offenbar auch gelesen. ;-)))))

Gruß aus Berlin
Michael

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael U. wrote:
> Bis jetzt haben meine AVR das Datenblatt offenbar auch gelesen. ;-)))))

Meine auch, meist besser als ich...

8-)

...

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK

hab mal wieder etwas Zeit gefunden um weiter zu machen.

Michael U. du hast recht zusammen mit Karl Heinz Buchegger. Hat an der 
einen kleinen Zeile gelegen.

Das einzigste was mir noch fehlt ist das mir einer mal kurz erklärt was 
eigentlich in der Zeile passiert:

ADMUX = (ADMUX & 0xF0) | mux;

Ich dachte immer wenn ich ADMUX |= mux eingebe dan ändert er nur die 
Bits dessen Wert mux hat?

Gruß und nochmals Danke
Daniel

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich dachte immer wenn ich ADMUX |= mux eingebe dan ändert er nur die
> Bits dessen Wert mux hat?

Richtig. Aber Du löschst nicht die vorher anders gesetzten Bits. Damit 
bleiben alle jemals gesetzten Bits gesetzt.

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

> Ich dachte immer wenn ich ADMUX |= mux eingebe dan ändert er nur die
> Bits dessen Wert mux hat?

Einfach unpräzise ausgedrückt und sicher auch gedacht. ;)

Es ist eine Oder-Verknüpfung, die Veränderung besteht also darin, das 
die Bits in MUX einzeln mit den Bits in ADMUX OR-Verknüpft werden. Das 
heißt aber ja letztlich: es sind hinterher alle Bits in ADMUX gesetzt, 
die vorher bereiits gesetzt waren ODER die in mux gesetzt sind.

   0000 0001   ADMUX
OR 0000 0010   mux
-------------
   0000 0011   ADMUX hinterher...

Gruß aus Berlin
Michael

Autor: Daniel H. (doomstar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super danke für die erklärung.

Damit hab ich es jetzt verstanden und wünsche allen ein erholsames WE.

Gruß
Daniel

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.