Forum: Mikrocontroller und Digitale Elektronik ADC Kanäle in einer For - Schleife ATMega 32


von Stephan M. (stmiko)


Lesenswert?

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

von Johannes M. (johnny-m)


Lesenswert?

> 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...

von Karl H. (kbuchegg)


Lesenswert?

Das ganze scheint mir nicht sehr zeitkritisch zu sein.
Gibt es einen speziellen Grund, warum du nicht die ADC Routine aus dem 
Tutorial benutzt? Die würde nämlich funktionieren.

von JojoS (Gast)


Lesenswert?

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?

von Johannes M. (johnny-m)


Lesenswert?

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...

von Stephan M. (stmiko)


Lesenswert?

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.

von JojoS (Gast)


Lesenswert?

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 :-)

von Stephan M. (stmiko)


Lesenswert?

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.

von JojoS (Gast)


Lesenswert?

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

von Stephan M. (stmiko)


Lesenswert?

@JojoS

du hattest Recht mit dem "while ( ADCSRA & (1<<ADSC)){}"! jetzt 
fnktioniert das Auslesen.
Die Mittelwertbildung und Festkommaarithmetik werde ich jetzt einmal 
anschauen!

vielen Dank

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.