Forum: Mikrocontroller und Digitale Elektronik ADC Wandlung funktoniert nicht wenn verschiedene Analogeingänge benutzt werden (AVR)


von Johannes (Gast)


Lesenswert?

Ich schicke die 8 Bit des ADCH weiter über den PORTC. Wenn nur ein 
Analogeingang benutzt wird, also z.B. immer ADMUX = 0x62, funktioniert 
alles ohne Probleme und der genaue Wert wird übertragen (ohne 
Schwankungen). Das selbe gilt wenn ich nur die Phase oder nur den Strom 
messe. Wenn ich allerdings alle drei Werte nacheinander messe und dann 
übergeben will, springen die Werte von Spannung, ebenso der Wert der 
Phase. Der Wert des Stromes passt komischerweise aber nach wie vor.

Hier wär das Programm dazu:

Ich benutze einen ATMEGA32 und programmiere in Atmel Studio fals das 
wichtig ist.
1
#define F_CPU 2000000UL
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
6
// Makro zum setzen bestimmter Bits
7
#define sbi(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
8
9
int i = 0;
10
11
uint8_t ADC_read(uint8_t kanalNr){
12
13
  //Messung starten
14
  sbi(ADCSRA,ADSC); 
15
  //Warten bis Messung vorbei ist
16
  while(bit_is_set(ADCSRA,ADSC));
17
  return (ADCH); //die 8 höchstwertigen bits zurückgeben
18
}
19
20
// führt 100 Messungen durch und ermittelt den höchstwert.
21
// Scheteilpunkt Messung des sinus förmigen Verlaufes
22
uint8_t getADCmax(uint8_t kanalNr){
23
24
    //Kanal des Multiplexers wählen:
25
    //ADLAR um die höchsten 8 Bits auf ADCH zu schreiben, REFS0 für interne Refrenz von 5 V
26
27
    if(kanalNr == 1){
28
      //ADMUX |= (1 << MUX1) | (1 << REFS0) | (1 << ADLAR);
29
      ADMUX = 0x62;
30
    }
31
    //ADC03 für die strom
32
    if(kanalNr == 2){
33
      //ADMUX |= (1 << MUX1) | (1 << MUX0) | (1 << REFS0)  | (1 << ADLAR);
34
      ADMUX = 0x63;
35
    }
36
    //ADC04 für die phase
37
    if(kanalNr == 3){
38
      //ADMUX |= (1 << MUX2) | (1 << REFS0) | (1 << ADLAR);
39
      ADMUX = 0x64;
40
    }
41
42
  //erste Messung nach wechseln des Kanals verwerfen
43
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
44
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der Konvertierung warten
45
  }
46
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
47
    Wandlung nicht übernommen. */
48
  (void) ADCW;
49
  
50
  //Peak speichern
51
  uint8_t peak=0;
52
  uint8_t tmpPeak;
53
  for(int i=0; i<190; i++){
54
    tmpPeak = ADC_read(kanalNr);
55
    if(tmpPeak > peak ){
56
      peak = tmpPeak;
57
    }  
58
  }
59
  //peak zurückgeben
60
  return peak;
61
}
62
63
int main(void)
64
{
65
    // Port C als ausgang & JTAG-Schnitstelle in Fuses deaktiviert um PortC ohne Probleme benutzen zu können
66
    DDRC = 0xFF;
67
  DDRB = 0xFF;
68
  DDRA = 0x00;
69
  
70
    // ADC initialisieren
71
    //ADSCRA Enablen und Teilungsfaktor von 16 ( da 2MHz/200kHz = 10)
72
  sbi(ADCSRA,ADEN);   //ADC aktivieren
73
  sbi(ADCSRA,ADPS2);
74
  
75
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
76
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der Konvertierung warten
77
  }
78
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
79
    Wandlung nicht übernommen. */
80
  (void) ADCW;
81
  
82
    while(1)
83
    {
84
  
85
    //Phase ausgeben
86
    PORTC = 0x00;
87
    PORTC = getADCmax(3);    
88
    _delay_ms(7);  
89
    PORTB = 0x08;
90
    for(i = 0; i < 200; i++) _delay_ms(1);
91
    
92
    //Strom ausgeben
93
    PORTC = 0x00;
94
    PORTC = getADCmax(2);
95
    _delay_ms(7);
96
    PORTB = 0x04;
97
    for(i = 0; i < 200; i++) _delay_ms(1);
98
        
99
    //Spannung Ausgeben    
100
    PORTC = 0x00;
101
    PORTC = getADCmax(1);
102
    _delay_ms(7);
103
    PORTB = 0x00;
104
    for(i = 0; i < 200; i++) _delay_ms(1);
105
    
106
107
            
108
    }
109
}

Kann mir da jemand weiterhelfen?

Grüße

Johannes

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Johannes schrieb:
> //erste Messung nach wechseln des Kanals verwerfen
Das ist unnötig. Es muss nur eine ausreichende Zeit zwischen dem 
Umschalten und dem Wandlungsstart vergehen. Wäre ja Murks, wenn man 
immer doppelt so oft wie nötig wandeln müsste. Die Doku hilft weiter...

>   /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>    Wandlung nicht übernommen. */
>   (void) ADCW;
Wie bitte? Was macht diese Zeile? Genau gar nichts...
Und was passiert deshalb, wenn dein Kommentar richtig ist?

: Bearbeitet durch Moderator
von Karl H. (kbuchegg)


Lesenswert?

Wie hast du die Messgroessen an die jeweiligen ADC Pins angeschlossen.
Wenn du da zu hochohmig gearbeitet hast, koennte es sein, das du der 
Sample und Hold Stufe des ADC nicht genug Zeit zum umladen gibst.

Das Programm ist zwar recht unuebersichtlich, aber offensichtlichen 
Fehler sehe ich auch keinen. Ich haette halt die bewaehrten Routinen aus 
dem AVR-GCC-Tutorial genommen.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:
> Wie hast du die Messgroessen an die jeweiligen ADC Pins angeschlossen.
> Wenn du da zu hochohmig gearbeitet hast, koennte es sein, das du der
> Sample und Hold Stufe des ADC nicht genug Zeit zum umladen gibst.

Obwohl, ist eigentlich auch Quatsch. Nach 190 Messungen, von denen du 
den Maximalwert nimmst, müsste die S&H Stufe längst umgeladen sein. So 
hochohmig kannst du gar nicht gearbeitet haben.

von Thomas (kosmos)


Lesenswert?

Im Datenblatt steht eine Empfehlung zwecks Widerstand der Quelle. Hab 
mir den Code nicht angesehen. Ein Anfängerfehler ist wenn man ADMUX 
einfach hochzählen lässt.

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.