Forum: Mikrocontroller und Digitale Elektronik Mehrere Analoge Eingänge Auswerten


von rokit88 (Gast)


Lesenswert?

Hallo,

Ich habe bereits sämtliche Suchfunktionen genutzt und habe gerade ein 
bissen Verständnis Probleme bei dem Artikel "AVR-GCC-Tutorial/Analoge 
Ein- und Ausgabe" hier aus dem Forum.


Meine Problemstellung:
Ich möchte gerne mehrere Analoge EIngänge auswerte (ADC0-ADC4) und die 
Werte einfach in eine Variable (X1-X5) schreiben.


Fakten:
Ich verwende einen Amtega 1284P.
AREF liegt mit 100nF gegen Masse. Erwartet Eingangsspannung 0-5V.
Mein Quarts hat 14,7456MHz
Teilungsfaktor ist doch 14,7456MHz/200kHz = 73,78  // Teilungsfaktor 
64??


Frage:
Wie implementiere ich jetzt die Analogmessung.
ich kann mir gerade nicht so wirklich einen Überlick verschaffen mit dem 
Tutorial. Vlt kann mir jemand auf die Sprüng helfen und die den 
Quelltext mit anderem Komentaren versehen die den einstieg leichter 
machen.

Falls jemand sonst eine gute Anleitung/Buch kennt kann er das gerne 
erwähnen.



Mein aktueller Quelltext:
1
#define F_CPU 147456000
2
#include <util/delay.h>
3
#include <avr/io.h>          //
4
 
5
6
int main (void) {            // Hauptschleife
7
 
8
   DDRC  = 0xFF;             // Digitale Ausgänge
9
  
10
11
   int X1;
12
   int X2;
13
   int X3;
14
   int X4;
15
   
16
   ADMUX = (1<<REFS0);      // AVCC (5V) als Referenz
17
18
   ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler (64??)
19
20
   ADCSRA |= (1<<ADEN);                  // ADC aktivieren
21
22
23
    ADCSRA |= (1<<ADSC);                 // eine ADC-Wandlung 
24
    while (ADCSRA & (1<<ADSC) ) {  // auf Abschluss der Konvertierung warten
25
    }
26
    /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
27
     Wandlung nicht übernommen. */
28
29
 (void) ADCW;
30
  }
31
32
33
34
   while(1) 
35
   {                
36
37
   }                         
38
 
39
40
   return 0;                
41
}

: Verschoben durch Moderator
von Oliver R. (orb)


Lesenswert?

Wirf mal einen Blick ins Datenblatt und schau Dir das ADMUX-Register an. 
Da wird nicht nur die Referenz gesetzt sondern auch der Eingang 
umgeschaltet.

von rokit88 (Gast)


Lesenswert?

Habe bisher nur im Datenblatt was i Download bei R...t hinterlegt war 
geguckt.

Bei AVR gibts noch ein größeres:
http://www.atmel.com/images/Atmel-8272-8-bit-AVR-microcontroller-ATmega164A_PA-324A_PA-644A_PA-1284_P_datasheet.pdf

Meinst du zufällig das?

von npn (Gast)


Lesenswert?

rokit88 schrieb:
> i Download bei R...t

Fehlen da nicht paar Buchstaben? ;-)

von Thomas F. (igel)


Lesenswert?

rokit88 schrieb:
> Meinst du zufällig das?

Das ist es. Runterladen und gut aufheben!

Und jetzt Kapitel 23.9: Register Description.

von Karl H. (kbuchegg)


Lesenswert?

rokit88 schrieb:

> Ich habe bereits sämtliche Suchfunktionen genutzt und habe gerade ein
> bissen Verständnis Probleme bei dem Artikel "AVR-GCC-Tutorial/Analoge
> Ein- und Ausgabe" hier aus dem Forum.

?
Wobei hapert es denn?

> Meine Problemstellung:
> Ich möchte gerne mehrere Analoge EIngänge auswerte (ADC0-ADC4) und die
> Werte einfach in eine Variable (X1-X5) schreiben.

OK. Mit den Funktionen aus dem Tutorial:
1
   X1 = ADC_Read( 0 );
2
   X2 = ADC_Read( 1 );
3
   X3 = ADC_Read( 2 );
4
   X4 = ADC_Read( 3 );
5
   X5 = ADC_Read( 4 );

wo ist da jetzt das Problem?


> int main (void) {            // Hauptschleife
>
>    DDRC  = 0xFF;             // Digitale Ausgänge
>
>
>    int X1;
>    int X2;
>    int X3;
>    int X4;
>
>    ADMUX = (1<<REFS0);      // AVCC (5V) als Referenz
>
>    ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler (64??)
>
>    ADCSRA |= (1<<ADEN);                  // ADC aktivieren
>
>
>     ADCSRA |= (1<<ADSC);                 // eine ADC-Wandlung
>     while (ADCSRA & (1<<ADSC) ) {  // auf Abschluss der Konvertierung
> warten
>     }
>     /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
>      Wandlung nicht übernommen. */
>
>  (void) ADCW;
>   }


?

Du hast doch die Tutorial-Routinen!
Die stehen da ja nicht ohne Grund drinnen. Warum benutzt du die nicht 
einfach?

Die kopierst du von dort in dein Programm, passt ev. noch die 
Einstellung der Referenzspannung (und eventuell des Teilers) an und 
schreibst:
1
....
2
3
4
int main()
5
{
6
  uint16_t X1, X2, X3, X4, X5;
7
8
  ADC_Init();
9
10
  while( 1 ) {
11
    X1 = ADC_Read( 0 );
12
    X2 = ADC_Read( 1 );
13
    X3 = ADC_Read( 2 );
14
    X4 = ADC_Read( 3 );
15
    X5 = ADC_Read( 4 );
16
17
    .... dein Code zur Auswertung
18
  }
19
}
und die Sache ist gegessen. Beim ADC geht das, weil diese Baugruppe bei 
den meisten AVR ähnlich genug funktioniert.

Dann natürlich mit dem Datenblatt studieren, wie und warum die 
Funktionen genau so aufgebaut sind, wie sie sind. Aber an und für sich 
gibt es keinen Grund, die sinnvolle Aufteilung der Funktionen bzw. 
Funktionalität da jetzt anders zu gestalten.

: Bearbeitet durch User
von rokit88 (Gast)


Lesenswert?

Nur kopieren reicht mir persönlich nicht. Will gerne verstehen wieso 
weshalb warum.

Hab mir jetzt das große Datenblatt mal geladen. Da scheint wesentlich 
mehr zu stehen. Werde mich jetzt da mal einarbeiten.

Solangsam verstehe das Tutorial.


Kann mir jemand folgende Zeilen erklären:
1
ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // !!!WIE!!! stellle ich den Frequenzvorteiler auf 64
2
3
sum += ADC_Read( Input );             // ??



Mein aktuelles Programm sieht dann jetzt wie folgt aus:
1
#define F_CPU 147456000
2
#include <util/delay.h>
3
#include <avr/io.h>          //
4
 
5
6
7
// ------------------------------------------------------------
8
// Initalisiere Analog/Digital Converter
9
// ------------------------------------------------------------
10
11
12
void ADC_Init(void) {      
13
14
   
15
       ADMUX = (1<<REFS0);           // AVCC (5V) als Referenz
16
17
       ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler (64??)
18
19
       ADCSRA |= (1<<ADEN);                  // ADC aktivieren
20
21
22
23
      ADCSRA |= (1<<ADSC);                 // eine ADC-Wandlung 
24
      while (ADCSRA & (1<<ADSC) ) 
25
    {      // auf Abschluss der Konvertierung warten
26
      }
27
          /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
28
             Wandlung nicht übernommen. */
29
30
   (void) ADCW;
31
    }
32
33
34
35
// ------------------------------------------------------------
36
// ------------------------------------------------------------
37
// Hauptprogramm
38
// ------------------------------------------------------------
39
// ------------------------------------------------------------
40
41
42
int main (void) {        
43
 
44
    DDRC  = 0xFF;               // Digitale Ausgänge
45
   
46
  uint16_t x1, x2, x3, x4;    // Variable für Analoge Werte            
47
48
   
49
     
50
51
// ------------------------------------------------------------
52
// Klasse zum Lesen des Analogen Wert
53
// ------------------------------------------------------------
54
55
  uint16_t ReadAnalog( uint8_t Input, uint8_t samples )  // Lese Analogen eingang (Eingang/Anzahl der Messungen)
56
  {
57
     uint32_t sum = 0;
58
 
59
      for (uint8_t i = 0; i < samples; ++i ) {
60
      sum += ADC_Read( Input );              //
61
      }
62
 
63
    return (uint16_t)( sum / nsamples );          // 
64
  }
65
66
67
68
   while(1) 
69
   {      
70
   
71
    ADC_Init();
72
73
    X1 = ReadAnalog(0, 10);
74
    X2 = ReadAnalog(1, 10);
75
    X3 = ReadAnalog(2, 10);
76
    X4 = ReadAnalog(3, 10);
77
    X5 = ReadAnalog(4, 10);
78
79
   }                         
80
 
81
   return 0;                
82
}

von Karl H. (kbuchegg)


Lesenswert?

rokit88 schrieb:
> Nur kopieren reicht mir persönlich nicht. Will gerne verstehen wieso
> weshalb warum.

Niemand hindert dich, den Code zu analysieren und mit dem Datenblatt 
abzugleichen, was die einzelnen Bitsetzerein machen.

>
1
> ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // !!!WIE!!! stellle ich den 
2
> Frequenzvorteiler auf 64
3
> 
4
> sum += ADC_Read( Input );             // ??
5
>

Was steht denn im Datenblatt, welche Bits in welchem Register zu setzen 
sind, um den Vorteiler auf 64 zu kriegen? (Hab nicht nachgesehen)

Und dann natürlich etwas, was du vor gefühlten 15 anderen Vorprojekten 
eigentlich schon beherrschen solltest: Bits in eiem Register setzen, 
Bits in einem Register löschen. Sozusagen das kleine Ein-mal-Eins der 
µC-Programmierung. Nur das es dort Bits in einem Portregister waren, die 
dann eben eine LED zum aufleuchten gebracht haben und hier sind es Bits 
in einem Register, die eben was einstellen. Aber der Vorgang ein (oder 
mehrere) Bits in einem Register zu manipulieren ist für dich als 
C-Programmierer programmtechnisch immer der gleiche.


> int main (void) {
>

>   uint16_t ReadAnalog( uint8_t Input, uint8_t samples )  // Lese
> Analogen eingang (Eingang/Anzahl der Messungen)
>   {
>      uint32_t sum = 0;
>
>       for (uint8_t i = 0; i < samples; ++i ) {
>       sum += ADC_Read( Input );              //
>       }
>
>     return (uint16_t)( sum / nsamples );          //
>   }


Keine Funktionen innerhalb von Funktionen.
Ja, ich weiß, der gcc frisst das. Trotzdem: programmiere nach C Standard 
wenn es keinen besonderen Grund dagegen gibt und du hast weniger 
Probleme, wenn du mal auf andere Systeme kommst.

Also nicht
1
void foo()
2
{
3
4
  void bar()
5
  {
6
   ....
7
  }
8
9
  bar();
10
}

sondern so, wie das in der Sprache vorgesehen ist
1
void bar()
2
{
3
  ...
4
}
5
6
void foo()
7
{
8
  bar();
9
}

: Bearbeitet durch User
von M.O. (Gast)


Lesenswert?

rokit88 schrieb:
> Mein aktuelles Programm sieht dann jetzt wie folgt aus:
>
> #define F_CPU 147456000

So schnell ist dein Prozessor bestimmt nicht ;-)

von rokit88 (Gast)


Lesenswert?

Ich habe den neuesten AVR den es noch nicht auf dem Markt gibt...;)
Spaß bei Seite.

Ja habe ich gerade selber bemerkt wie ich den Teilungsfaktor nochmal 
berechnen wollte. Da war eine "0" zuviel. 14,7456MHz

Vorteiler ergibt dann zwischen 73 und 294.

ADPS2   ADPS1   ADPS0   Teilungsfaktor
0   0   0   2
0   0   1   2
0   1   0   4
0   1   1   8
1   0   0   16
1   0   1   32
1   1   0   64
1   1   1   128
1
ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1  <<ADPS0);     // Frequenzvorteiler (128)


Muss ich noch am Anfang irgendwas initalisieren, da ich einen Quarz 
verwende?

von Karl H. (kbuchegg)


Lesenswert?

rokit88 schrieb:

> Muss ich noch am Anfang irgendwas initalisieren, da ich einen Quarz
> verwende?

Wenn der Quarz aktiv ist, dann ist er für den ganzen Prozessor aktiv.
D.h. speziell für den ADC gibt es da nichts Spezielles. Ausser dass du 
mit der Quarzfrequenz und dem Vorteiler ins 'Fenster' kommen sollst, 
weil sonst die Messwerte nicht mehr ganz korrekt sind.

Ist denn dein Quarz aktiv?
Nur anschliessen alleine reicht nicht. Der µC muss auch mittels der 
Fuses auf den Quarz konfiguriert sein, so dass der ihn auch verwendet.

von rokit88 (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ist denn dein Quarz aktiv?
> Nur anschliessen alleine reicht nicht. Der µC muss auch mittels der
> Fuses auf den Quarz konfiguriert sein, so dass der ihn auch verwendet.

Genau das mein ich. Da ist das Stichwort Fuses was ich gesucht habe.
Device Clocking Option CKSEL3..0
External Crystal/Ceramic Resonator   1111 - 1010
Das sollte doch ein normaler Quarz mit zwei 22pF Kerko´s sein oder?

Wie stelle ich das ein? Über "STK600 Upgrade"??

Muss ich im Programm selber am Anfang sonst noch was einfügen. Kann 
jetzt aus dem DB nicht weiter entnehmen.

Was ist mit: Clock prescaler select?

von rokit88 (Gast)


Angehängte Dateien:

Lesenswert?

Ich glaube ich habe es gefunden unter "Tools / ProgrammAVR/Connect"
Was wähle ich den unter "SUT_CKSEL" (wenn das richtig ist) aus?

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.