ADC komische Werte am Eingang

Gast #718729
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
}
Gast #718735
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
#718748
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.
Gast #718750
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...
#718782
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.
Gast #718784
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
#718792
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.
#719057
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!
Gast #719507
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren