ADC Kanäle in einer For - Schleife ATMega 32

OP #1142099
Hallo zusammen,

Ich habe eine ADC Funktion geschrieben, welche die ADC Kanäle 0 bis 5 
auslesen soll. Mein Problem ist nun, dass wenn ich den Laufindex der 
For- Schleife gleichzeitig als ADMUX Adressen verwenden möchte, kein ADC 
Wert gelesen wird. Beim Eintragen von z.B. ADMUX = 1 funktioniert 
folgendes Programm.
1
#define F_CPU 16000000UL
2

3
#include <util/delay.h>
4
#include <avr/io.h>
5

6
#define photo_u werte[1]
7

8
void init_adc(void)
9
{
10

11
  //Einschalten von ADC, Datenblatt S.216
12
  ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
13

14
}
15

16

17
void messung(unsigned int *z_adc, float *z_werte, unsigned char *z_adcl, unsigned char *z_adch){
18

19
    unsigned char n, c;
20

21
      
22
    for (n=0; n<7; n++)
23
    {
24
    
25
      ADMUX = n; 
26
      
27
      //Starten von ADC
28
      ADCSRA|=(1<<ADSC);
29
    
30
      //Warten bis Umwandlung startet
31
      while((ADCSRA & (1<<ADSC)) == 0){}
32
      
33
      z_adcl[n] = ADCL;
34
      z_adch[n] = ADCH;
35

36
      z_adc[n] = ADCW;
37

38
      ADCSRA&=~(1<<ADSC);
39

40
      z_werte[1]= 0.021505 * z_adc[1]; //Spannung Photozelle
41
      z_werte[2]= 0.014663 * z_adc[2]; //Spannung Akku
42
      z_werte[3]= 0.039100 * z_adc[3]; //Spannung Generator
43

44
      for (c=4; b<7; c++) z_werte[c]= 0.04878 * z_adc[c] - 24.97536; 
45
      
46
        //3: Strom Photozelle
47
        //4: Strom Generator
48
        //5: strom Akku
49
      
50
    }
51

52
    if (n==6) n=0; //Rücksetzen des For-Schleifen-Zählers 
53
    if (c==6) c=0; //siehen Oben
54

55
    
56

57
  
58
}
59

60

61

62

63

64

65
int main(void){
66

67
  float werte[7];
68

69
  unsigned char adcl[6], adch[6], n, b;
70

71
  unsigned int  adc[7];
72

73
  DDRB=0xff;
74
  init_adc();
75

76
  
77

78
  
79
  
80
  for(;;)
81
  {
82
  
83
    
84
    messung(adc, werte, adcl, adch);
85

86

87
      if (photo_u > 15.00) 
88
      {
89
        PORTB|=(1<<PB0);  
90
      }
91
      else
92
      {
93
         PORTB&=~(1<<PB0);
94
      }
95
      
96
  }
97

98

99
}

Ich habe auch schon versucht in Abhängigkeit von n den ADMUX die 
entsprechende Adresse über den case-Befehl zuzuweisen.
Kann mir vielleicht jemand einen Tipp geben, wo die Ursache sein könnte?

Stephan
> for (c=4; b<7; c++)
Was hat es denn mit der Durchlaufbedingung der Schleife auf sich? Eine 
Variable b gibt es da nicht! Das müsste zumindest mal ne Fehlermeldung 
geben.

Und was soll das doppelte Auslesen der ADC-Datenregister? Und bist Du 
sicher, dass Du wirklich GLeitkommaberechnungen brauchst? Meist ist 
Festkommaarithmetik sinnvoller...

Und noch was:
> while((ADCSRA & (1<<ADSC)) == 0){}
Überlege mal, was in dieser Zeile passiert! Kleiner Tip: Solange die 
Wandlung läuft, ist ADSC gesetzt...
Gast
das 'b<7' soll sicher 'c<7' heissen. Und die Float Skalierungen mit den 
festen Indizes gehören nicht in die for Schleife, da wird 8mal das 
Gleiche berechnet.
Und wozu das merkwürdige Rücksetzen der Schleifenzähler?
JojoS wrote:
> das 'b<7' soll sicher 'c<7' heissen. Und die Float Skalierungen mit den
> festen Indizes gehören nicht in die for Schleife, da wird 8mal das
> Gleiche berechnet.
> Und wozu das merkwürdige Rücksetzen der Schleifenzähler?
Na, so tief in die Details bin ich noch gar nicht gegangen. Solange er 
nicht auf das Ende der Wandlung wartet, bevor er das Ergebnis ausliest, 
kann da nix Sinnvolles rauskommen...
OP
Habe die angesprochene Variable "b" in "c" geändert, weil das Forum mir 
eine Spammeldung gebracht hat. Das mit dem Berechnen in der Schleife ist 
ein Fehler, das stimmt.
Das doppelte Auslesen dient, dazu das ADCL und ADCH über den SPI 
übertragen werden sollen.
Gast
ein bischen wird ja gewartet:
      //Warten bis Umwandlung startet
      while((ADCSRA & (1<<ADSC)) == 0){}
man muss natürlich auf das Ende der Wandlung warten. Ob das mit dieser 
Abfrage gemacht wird, weiss ich nicht, bin zu faul nachzusehen. Aber den 
Teil würde ich auch dem Tutorial abschreiben.
Und die Schleife wird 7mal durchlaufen, nicht 8mal wie ich erst schrieb. 
+/- 1, altes Informatikerproblem :-)
OP
Der Grund, weshlab ich nicht die Routine aus dem Tutorial benutzte ist, 
dass ich zu jedem Aufruf der Funktion alle Kanäle benötige. Ich möchte 
also nicht jedesmal den zu lesenden Kanal übertragen.

Der Ablauf in der Main Routine dient nur zu Testzwecken. Im eigentlichen 
Programm wird die Funktion "Messung" mehrmals aufgerufen.
Gast
ein Fehler ist die mehrfache Berechnung nicht, nur eine lange 
Warteschleife weil float Mathe nicht die Stärke eines AVR ist :-)
Aber der Fehler dürfte doch in der Abfrage auf das Wandlungsende liegen, 
du fragst auf ==0 ab, aber lt. Tutorial wird das Bit bei Wandlungsende 
gelöscht.
Die Mittelwertbildung für die Wandlung ist auch zu empfehlen.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#ADC_.28Analog_Digital_Converter.29

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.