Forum: Mikrocontroller und Digitale Elektronik ADC GCC STK500 ATMEGA16


von Herbert K. (herbii)


Lesenswert?

Hallo liebe Leute,
das Forum hat mir schon sehr weiter geholfen, aber nun stehe ich vor 
einem eigentlich wohl relativ einfachen Problem, krieg es aber nicht 
hin, weil ich wohl zu blöd bin bzw. mir einfach die Kenntnisse fehlen .. 
:)
Ich habe ein STK500 Evo Board und benutze den ATMEGA16 und möchte mit 
dem internen ADC eine Spannung vergleichen die ab einem Schwellwert 
(interne 2,56V) einen Port auf High schaltet, also ganz einfach 
eigentlich..
Im Forum wird dieser Teil auch sehr gut beschrieben nur den 
Grundlegenden Programmteil bekomme ich nicht hin..genauso wie ich es 
nicht verstehe, wie ich den Frequenzvorteiler einstellen soll und auf 
welche Frequenz er sich bezieht (CPU oder Quarz?) Ich benutze einen 
externen Quarz mit 10Mhz..
Auszug aus Tutorial:
 http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe:
1
void ADC_Init(void) {
2
 
3
  uint16_t result;
4
 
5
6
  ADMUX = (1<<REFS1) | (1<<REFS0);      // interne Referenzspannung nutzen
7
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
8
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
9
 
10
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
11
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
12
 
13
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
14
  while (ADCSRA & (1<<ADSC) ) {}        // auf Abschluss der Konvertierung warten
15
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
16
     Wandlung nicht übernommen. */
17
  result = ADCW;
18
}
19
 
20
/* ADC Einzelmessung */
21
uint16_t ADC_Read( uint8_t channel )
22
{
23
  // Kanal waehlen, ohne andere Bits zu beeinflußen
24
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
25
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
26
  while (ADCSRA & (1<<ADSC) ) {}  // auf Abschluss der Konvertierung warten
27
  return ADCW;                    // ADC auslesen und zurückgeben
28
}
29
 
30
/* ADC Mehrfachmessung mit Mittelwertbbildung */
31
uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
32
{
33
  uint32_t result = 0;
34
 
35
  for (uint8_t i = 0; i < average; ++i )
36
    result += ADC_Read( channel );
37
 
38
  return (uint16_t)( result / average );
39
}
40
41
/* Beispielaufrufe: */
42
 
43
int main()
44
{
45
  uint16_t adcval;
46
  ADC_Init();
47
 
48
  while( 1 ) {
49
    adcval = ADC_Read(0);  // Kanal 0
50
    // mach was mit adcval
51
 
52
    adcval = ADC_Read_Avg(2, 4);  // Kanal 2, Mittelwert aus 4 Messungen
53
    // mach was mit adcval...

Die Grundlegenden Einstellung des ADC`s und der Register habe ich nun 
verstanden aber danach weiss ich nicht weiter..
Nochmal zusammengefasst:
Mein Modul misst über den PA0 eine anliegende veränderbare Spannung max 
5V, unterschreitet die Spannung den Schwellwert (die interne refspannung 
2,56V) dann schaltet das Modul den Pin PB0 auf High bzw. alle Pins von 
Port B! Gestartet wird die Messung mittels Reset-Taster..Also nach 
drücken des Tasters misst der ADC so lange, bis die Spannung unter den 
Schwellwert absinkt!
Eigentlich wohl nicht schwer, meine C programmierkenntnisse sind leider 
mangelhaft :)

Grüße Herbi und schonmal Danke für eure bemühungen..

PS: Muss ich das eigentlich alles über den ADC machen oder reicht auch 
sonst der Analog Comparator? Ich mein ich hab ja nur eine Spannung die 
mit der internen Referzenspannung verglichen werden soll..

von Karl H. (kbuchegg)


Lesenswert?

Herbert K. schrieb:

> Mein Modul misst über den PA0 eine anliegende veränderbare Spannung

also den ADC Kanal 0

> Eigentlich wohl nicht schwer, meine C programmierkenntnisse sind leider
> mangelhaft :)

mangelhaft ist ein Hilfsausdruck.
Einem Baby den Schnuller klauen ist dagegen relativ schwer.

Was musst du machen:

erst mal den ADC initialisieren.
Dann musst du den Port, an dem die LED sitzt auf Ausgang schalten. 
Sollte logisch sein.

Damit ist die Initialisierung abgeschlossen.
Ab dann geht es ständig in der Hauptschleife. Was ist dort zu tun?
Eine Messung vornehmen. Mit dem Schwellwert vergleichen und abängig vom 
Ergebnis (kleiner/größer) die LED entweder ein oder ausschalten

Also
Das grundsätzliche Gerüst sieht so aus
1
....
2
3
int main()
4
{
5
  Initialisierungen
6
7
  while( 1 ) {    // Hauptschleife
8
 
9
    Programmlogik
10
11
  }
12
}

Was muss alles bei den Initialisierungen passieren?
Na, der ADC muss initialisiert werden - dazu hast du eine fertige 
Funktion, brauchst du nur aufrufen. Vorher aber in der FUnktion die 
Variante auswählen, die deiner gewünschten Referenzspannung entspricht.
Und der Port mit der Led muss auf Ausgang gestellt werden.

Was haben wir bisher
1
...
2
int main()
3
{
4
  POrt auf Ausgang stellen
5
  ADC_Init();
6
7
  while( 1 ) {
8
9
    ADC abfragen
10
    mit SChwellwert vergleichen
11
12
    größer -> LED einschalten
13
    kleiner -> LED ausschalten
14
  }
15
}

gut. Die Portinitialisierung für die LED musst du alleine hinkriegen.

Was ist mit "ADC abfragen".
Auch dafür hast du bereits eine fertige Funktion, die du nur noch 
verwenden musst. Und wie die Demo zeigt, brauchst du eine Variable, in 
der du das Ergebnis der Abfrage bekommst.
Also
1
...
2
int main()
3
{
4
  uint16_t adcWert;
5
6
  POrt auf Ausgang stellen
7
  ADC_Init();
8
9
  while( 1 ) {
10
11
    adcWert = ADC_Read(0);
12
13
    mit SChwellwert vergleichen
14
    größer -> LED einschalten
15
    kleiner -> LED ausschalten
16
  }
17
}

Wie vergleicht man Werte?
Na mit einem if!
1
...
2
int main()
3
{
4
  uint16_t adcWert;
5
6
  POrt auf Ausgang stellen
7
  ADC_Init();
8
9
  while( 1 ) {
10
11
    adcWert = ADC_Read(0);
12
13
    if( adcWert > 512 )
14
       LED einschalten
15
    else
16
       LED ausschalten
17
  }
18
}


Den Rest musst du alleine hinbekommen.

> PS: Muss ich das eigentlich alles über den ADC machen oder reicht auch
> sonst der Analog Comparator? Ich mein ich hab ja nur eine Spannung die
> mit der internen Referzenspannung verglichen werden soll..

Nimm erst mal das, wofür du fertige Funktionen hast und was banal 
einsetzbar ist. OK? So wie das aussieht, ist das schon schwer genug für 
dich.

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.