Forum: Mikrocontroller und Digitale Elektronik ADC komische Werte am Eingang


von Roman (Gast)


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/doc7593.pdf)

Hier noch mein Code:
1
#include "Usart.h"
2
#include <util/delay.h>
3
#include <avr/io.h>
4
#include <inttypes.h>
5
6
/*************************************************************************
7
* Analog zu Digital Wandlung (www.mikrocontroller.net)
8
**************************************************************************/
9
uint16_t ReadChannel(uint8_t mux)
10
{
11
  uint8_t i;
12
  uint16_t result;
13
 
14
  // setzen auf 8 (1) und ADC aktivieren (1)
15
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);   
16
                              
17
  // Kanal waehlen
18
  ADMUX = mux;    
19
 
20
21
    ADMUX |= (1<<REFS1) | (1<<REFS0); 
22
  // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
23
  // also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen"
24
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
25
  while ( ADCSRA & (1<<ADSC) )
26
  {
27
     ;     // auf Abschluss der Konvertierung warten
28
  }
29
  result = ADCW;  // ADCW muss einmal gelesen werden,
30
                  // sonst wird Ergebnis der nächsten Wandlung
31
                  // nicht übernommen.
32
 
33
  // Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen /
34
  result = 0;
35
  for( i=0; i<5; i++ )
36
  {
37
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
38
    while ( ADCSRA & (1<<ADSC) )
39
    {
40
      ;   // auf Abschluss der Konvertierung warten
41
    }
42
    result += ADCW;            // Wandlungsergebnisse aufaddieren
43
  }
44
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
45
 
46
  result /= 5;                     // Summe durch vier teilen = arithm. Mittelwert
47
48
  return result;
49
  //return 1024;
50
}
51
52
/**************************************************************
53
* MAIN
54
***************************************************************/
55
int main(void)
56
{
57
    USART_INIT(100);
58
59
    uint16_t adc;
60
61
    while(1){
62
63
  adc = ReadChannel(0);
64
  usart_write("ADC0 = %i\n\r",adc);
65
66
  adc = ReadChannel(1);
67
  usart_write("ADC1 = %i\n\r",adc);
68
69
  adc = ReadChannel(2);
70
  usart_write("ADC2 = %i\n\r",adc);
71
72
  adc = ReadChannel(3);
73
  usart_write("ADC3 = %i\n\r",adc);
74
75
  adc = ReadChannel(4);
76
  usart_write("ADC4 = %i\n\r",adc);
77
78
  adc = ReadChannel(5);
79
  usart_write("ADC5 = %i\n\r",adc);
80
81
  adc = ReadChannel(6);
82
  usart_write("ADC6 = %i\n\r",adc);
83
84
  adc = ReadChannel(7);
85
  usart_write("ADC7 = %i\n\r\n\r",adc);
86
87
  _delay_ms(100);
88
89
    }
90
    return 0;
91
}

von Johannes M. (johnny-m)


Lesenswert?

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

von reiner (Gast)


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

von Thilo M. (Gast)


Lesenswert?

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

Puulups an PORTA ausgeschalltet? Alle auf Eingang?

von Thilo M. (Gast)


Lesenswert?

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

von Thilo M. (Gast)


Lesenswert?

Noch was:
vor

#include <util/delay.h>

muss die SYSCLCK angegeben werden.

von Karl H. (kbuchegg)


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.

von Roman (Gast)


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.
1
  DDRF  = 0b00000000; // Eingaenge 
2
  PORTF = 0b00000000; // Pullup inaktiv


@Thilo

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

von Johannes M. (johnny-m)


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.
>
>
1
>   DDRF  = 0b00000000; // Eingaenge
2
>   PORTF = 0b00000000; // Pullup inaktiv
3
>
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.

von jOsI (Gast)


Lesenswert?

Hi,

was mich ein wenig irritiert ist diese Zeile:
1
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:
1
#define Adc_get_8_bits_result()         ((unsigned char)(ADCH))
2
#define Adc_get_10_bits_result()         ( (unsigned short)((ADCL>>6) + ((unsigned short)(ADCH<<2))) )

mfg

von Johannes M. (johnny-m)


Lesenswert?

jOsI wrote:
> Hi,
>
> was mich ein wenig irritiert ist diese Zeile:
>
1
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:
>
1
> #define Adc_get_8_bits_result()         ((unsigned char)(ADCH))
2
> #define Adc_get_10_bits_result()         ( (unsigned short)((ADCL>>6) + ((unsigned short)(ADCH<<2))) )
3
>
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.

von Branko Golubovic (Gast)


Lesenswert?

Pull-Down Widerstände vergessen?

von Johannes M. (johnny-m)


Lesenswert?

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

von Branko Golubovic (Gast)


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.

von Johannes M. (johnny-m)


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!

von Branko Golubovic (Gast)


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.

von Roman (Gast)


Lesenswert?

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

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.