mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADC komische Werte am Eingang


Autor: Roman (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen

Mein uP macht nicht das was er eignetlich tun sollte! Ich benutze den 
AT90USB1287(16MHz) und möchte 8 ADC Werte auf dem Bildschrim anzeigen 
lassen (via USART). Leider stimmen nur die Werte ADC0 und ADC1, die 
Anderen sind dauernd auf 1023, also auf dem Maximum.

ADC0 = 479
ADC1 = 7
ADC2 = 1023
ADC3 = 1023
ADC4 = 1023
ADC5 = 1023
ADC6 = 1023
ADC7 = 1023

Wenn ich die Spannung am Ausgang messe, erhalte ich immer 3.6V (bei 5V 
Speisung) ausser bei ADC0 und ADC1. Kann es sein, dass nur einige Ports 
kaputt sind? Habe ich einen Initialisierungsfehler gemacht?

Danke für Eure Hilfe

Gruss Roman


(Datenblatt: 
http://www.atmel.com/dyn/resources/prod_documents/...)

Hier noch mein Code:
#include "Usart.h"
#include <util/delay.h>
#include <avr/io.h>
#include <inttypes.h>

/*************************************************************************
* Analog zu Digital Wandlung (www.mikrocontroller.net)
**************************************************************************/
uint16_t ReadChannel(uint8_t mux)
{
  uint8_t i;
  uint16_t result;
 
  // setzen auf 8 (1) und ADC aktivieren (1)
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);   
                              
  // Kanal waehlen
  ADMUX = mux;    
 

    ADMUX |= (1<<REFS1) | (1<<REFS0); 
  // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
  // also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen"
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) )
  {
     ;     // auf Abschluss der Konvertierung warten
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.
 
  // Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen /
  result = 0;
  for( i=0; i<5; i++ )
  {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) )
    {
      ;   // auf Abschluss der Konvertierung warten
    }
    result += ADCW;            // Wandlungsergebnisse aufaddieren
  }
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
 
  result /= 5;                     // Summe durch vier teilen = arithm. Mittelwert

  return result;
  //return 1024;
}

/**************************************************************
* MAIN
***************************************************************/
int main(void)
{
    USART_INIT(100);

    uint16_t adc;

    while(1){

  adc = ReadChannel(0);
  usart_write("ADC0 = %i\n\r",adc);

  adc = ReadChannel(1);
  usart_write("ADC1 = %i\n\r",adc);

  adc = ReadChannel(2);
  usart_write("ADC2 = %i\n\r",adc);

  adc = ReadChannel(3);
  usart_write("ADC3 = %i\n\r",adc);

  adc = ReadChannel(4);
  usart_write("ADC4 = %i\n\r",adc);

  adc = ReadChannel(5);
  usart_write("ADC5 = %i\n\r",adc);

  adc = ReadChannel(6);
  usart_write("ADC6 = %i\n\r",adc);

  adc = ReadChannel(7);
  usart_write("ADC7 = %i\n\r\n\r",adc);

  _delay_ms(100);

    }
    return 0;
}


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

Bewertung
0 lesenswert
nicht lesenswert
Wo ist die I/O-Initialisierung? Übrigens funktioniert _delay_ms(100) nur 
bei CPU-Taktfrequenzen unter 2,6 MHz...

Autor: reiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sind die adc-inputs auch als solche definiert? ich kenn mich jetz nicht 
mit deinem atmel direkt aus, aber irgendwie fehlt mir sowas wie eine 
port_definition (port_init, o.ä.)...

außerdem solltest du deine kommentare nochmal überdenken... ;)

>>  result /= 5;   // Summe durch vier teilen = arithm. Mittelwert

mfg reiner

Autor: Thilo M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sollte es nicht
 while ( !(ADCSRA & (1<<ADSC)) )
heißen?

Puulups an PORTA ausgeschalltet? Alle auf Eingang?

Autor: Thilo M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Puh, meine Tastatur prellt! ;)
Wieso deaktivierst du den ADC?
Und mach eine kleine Pause nach dem Umschalten des MUX (ca. 40µs).

Autor: Thilo M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch was:
vor

#include <util/delay.h>

muss die SYSCLCK angegeben werden.

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

Bewertung
0 lesenswert
nicht lesenswert
Das ist die readChanel Funktion aus dem Tutorial.
Die sollte grundsätzlich in Ordnung sein.

> Sollte es nicht
>  while ( !(ADCSRA & (1<<ADSC)) )
> heißen?

Nö. Man setzt das ADSC Bit um die Wandlung zu starten
und die Hardware setzt es wieder auf 0, wenn sie fertig
ist.

> Und mach eine kleine Pause nach dem Umschalten des MUX (ca. 40µs).

Er macht eine Messung, die verworfen wird. Das sollte genügen,
um eine Fehlmessung auszuschliessen.

Autor: Roman (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johannes

Habe den delay entfernt, leider kein Unterschied.


@reiner

Habe die Initialisierung noch hinzugefügt. Aber auch damit ergibt es 
kein Unterschied. Die Werte sind immernoch die selben.
  DDRF  = 0b00000000; // Eingaenge 
  PORTF = 0b00000000; // Pullup inaktiv


@Thilo

Habe mit diesem Code scho etliche Male gearbeitet und bislang hat es 
einwandfrei funktioniert...

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

Bewertung
0 lesenswert
nicht lesenswert
Roman wrote:
> @Johannes
>
> Habe den delay entfernt, leider kein Unterschied.
Ich habe ja auch nicht behauptet, dass das mit dem _delay_ms etwas mit 
dem Problem an sich zu tun hat. Es war als reine Zusatzinformation 
gedacht.

> @reiner
>
> Habe die Initialisierung noch hinzugefügt. Aber auch damit ergibt es
> kein Unterschied. Die Werte sind immernoch die selben.
>
>
>   DDRF  = 0b00000000; // Eingaenge
>   PORTF = 0b00000000; // Pullup inaktiv
> 
Ist das JTAG-Interface bei den Teilen nicht auch an Port F? Mal da 
nachgesehen? Das muss auf jeden Fall deaktiviert werden (Fusebit), sonst 
geht zumindest an PF4...7 gar nichts. Was mit PF2 und 3 ist, weiß ich 
allerdings auch nicht. Die Pins haben afaik keine Sonderfunktionen außer 
als Analog-Eingänge.

Autor: jOsI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

was mich ein wenig irritiert ist diese Zeile:
result += ADCW;            // Wandlungsergebnisse aufaddieren
Welches Register ist ADCW, der AT90USB hat doch nur ADCH und ADCL in 
denen das Ergebnis abgelegt wird.
Ich hole das Ergebnis folgendermaßen ab:
#define Adc_get_8_bits_result()         ((unsigned char)(ADCH))
#define Adc_get_10_bits_result()         ( (unsigned short)((ADCL>>6) + ((unsigned short)(ADCH<<2))) )

mfg

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

Bewertung
0 lesenswert
nicht lesenswert
jOsI wrote:
> Hi,
>
> was mich ein wenig irritiert ist diese Zeile:
>
result += ADCW;            // Wandlungsergebnisse aufaddieren
> Welches Register ist ADCW, der AT90USB hat doch nur ADCH und ADCL in
> denen das Ergebnis abgelegt wird.
Jeder mir bekannte C-Compiler für AVRs (und ja, auch der AVR-GCC) bietet 
einen 16-Bit-Zugriff auf beide Register an. Das Gesamtregister heißt 
dann entweder ADC oder ADCW.

> Ich hole das Ergebnis folgendermaßen ab:
>
> #define Adc_get_8_bits_result()         ((unsigned char)(ADCH))
> #define Adc_get_10_bits_result()         ( (unsigned short)((ADCL>>6) + ((unsigned short)(ADCH<<2))) )
> 
Und genau das ist gefährlich, weil absolut nicht definiert ist, welches 
der beiden Register zuerst gelesen wird! Die Reihenfolge ist aber 
essentiell wichtig. ADCL muss zuerst gelesen werden. Und das nimmt 
einem beim 16-Bit-Zugriff mit ADC(W) der Compiler ab.

EDIT:
...Und außerdem ist das ganze mit den Schiebereien, so wie es da steht, 
blühender Unsinn. So kommt da nur Müll raus. Eine 8-Bit-Variable kannste 
noch so nach unsigned short casten, wenn Du sie um 6 Stellen nach rechts 
schiebst, fallen 6 Bit auf Nimmerwiedersehen hinten raus. Und das 
Schieben des High-Bytes um 2 Stellen nach links ist genauso unsinnig.

Autor: Branko Golubovic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pull-Down Widerstände vergessen?

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

Bewertung
0 lesenswert
nicht lesenswert
Branko Golubovic wrote:
> Pull-Down Widerstände vergessen?
Wie bitte? Pull-Down-Widerstände an Analogeingängen? Wie stellst Du Dir 
das vor?

Autor: Branko Golubovic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eifach 100kOhm bis 470kOhm zwischen Eingang und AGND.
Sonst ist Eingangwiderstand zu hoch(>100MOhm) und Eingang floated
jegendwo zwischen GND und VCC  weil kein Bezugspotential hat.

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

Bewertung
0 lesenswert
nicht lesenswert
@Branko:
Wenn da ein Signal dran ist, dann floatet gar nichts. Und wenn kein zu 
messendes Signal da wäre, dann würde er sich vermutlich nicht über 
"komische Werte" wundern... Mit einem Widerstand an der Stelle kann man 
sich nen schönen Spannungsteiler bauen, der dann das ganze Signal 
verfälscht. Bloß nicht!

Autor: Branko Golubovic (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>@Branko:
>Wenn da ein Signal dran ist, dann floatet gar nichts.

Woher wissen wir das?
I deinem  Posting schreibst du über:
>Leider stimmen nur die Werte ADC0 und ADC1, die
>Anderen sind dauernd auf 1023, also auf dem Maximum


Welche Werte? Wie hast du  die „Werte“ generiert. Mit dem Poti?
Batterie angeschlossen? Schaltung?

Dann schreibst du weiter:
>Wenn ich die Spannung am Ausgang messe, erhalte ich immer 3.6V
>(bei 5V Speisung) ausser bei ADC0 und ADC1.

Welcher Ausgang? Meinst du ADC-Eingang? Wie hast du das gemessen?
Mit dem Multimeter?
Mit deinem Erklärung ist niemand schlau geworden wie du das alles
angeschlossen und gemessen hast.

Also wen du noch Hilfe brauchst poste bitte Schaltplan von deinem 
Aufbau.
Erst danach kann man über eventuelle Fehler im Programm diskutieren.

Autor: Roman (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es lag am Chip. Habe einen neuen eingesetzt und getestet. Jetzt 
funktionieren alle ADC Eingänge wieder...

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.