Forum: Compiler & IDEs Anfängerhilfe bei Analog Digital Converter


von Martin *. (mistermister606)


Lesenswert?

Hallo zusammen

ich benötige mal wieder eure Hilfe.
Ich nutze das rumpus board (atm168) und möchte hier gerne den Poti 
auswerten (PC5) und bei einem gewissen wert soll die LED1  (PC4) 
aufleuchten.

Ich hab das AVR-GCC-Tutorial schon zig mal gelesen aber ich will es 
einfach nicht verstehen...

Ich frage das ungern, aber kann mir jemand die paar Zeilen zukommen 
lassen, damit ich den Code dann zerlegen und lernen kann?

DANKE

von Floh (Gast)


Lesenswert?

Was hindert dich daran, die Turorialfunktion zu nehmen?

von Coder (Gast)


Lesenswert?

Gegenfrage: Was verstehst Du und was nicht. Einfacher als im Tutorial 
geht es kaum. Der Code ist ja fast Zeilenweise kommentiert.

von Martin *. (mistermister606)


Lesenswert?

Ok ich glaube es ist am besten, wenn ich den bereits kommentierten Code 
nochmals kommentiere
1
/* ADC initialisieren */
2
void ADC_Init(void) {
3
 
4
  uint16_t result;
5
  uint16_t test;  
6
7
  ADMUX = (1<<REFS1) | (1<<REFS0);      
8
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler

"Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und 
dem Eingangstakt des ADC."
ATmega48/88/168: 0 - 10MHz @ 2.7V - 5.5V, 0 - 20MHz @ 4.5V - 5.5V  steht 
im DB nur welchen Mhz wert muss ich da jetzt nehmen?


1
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
2
 
3
  ADCSRA |= (1<<ADFR);                  // eine ADC-Wandlung

wenn ich den Eingang PC5 überwachen will würde ADFR passen oder?


1
  while (ADCSRA & (1<<ADFR) ) {}        // auf Abschluss der Konvertierung warten
2
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
3
     Wandlung nicht übernommen. */
4
  result = ADCW;
5
}

Wenn ich es richtig verstanden habe sollte nun bereits der eingelesene 
Wert in result stehen?



1
/* ADC Einzelmessung */
2
uint16_t ADC_Read( uint8_t channel )
3
{
4
  // Kanal waehlen, ohne andere Bits zu beeinflußen
5
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);


Was mach ich den dann mit ADMUX das auszulesende bit hatte ich doch 
vorher mit  ADCSRA |= (1<<ADFR); bestimmt ?

1
  ADCSRA |= (1<<ADFR);            // eine Wandlung "single conversion"
2
  while (ADCSRA & (1<<ADFR) ) {}  // auf Abschluss der Konvertierung warten
3
test = ADCW;                    // ADC auslesen und zurückgeben
4
}
5
...
6
 
7
/* Beispielaufrufe: */
8
 
9
int main()
10
{
11
  uint16_t adcval;
12
  ADC_Init();
13
 
14
  while( 1 ) {
15
    adcval = ADC_Read(0);  // Kanal 0
16
    // mach was mit adcval
17
 
18
  }
19
}


Welche Auflösung habe ich nun?
Wie kann ich nun z.b. bei dem wert 4 in der Variable test die LED 1 
(PC4) einschalten?


Danke euch ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Martin *** schrieb:

> ATmega48/88/168: 0 - 10MHz @ 2.7V - 5.5V, 0 - 20MHz @ 4.5V - 5.5V  steht
> im DB

Das sind nur die zulässigen Taktfrequenzbereiche.

> nur welchen Mhz wert muss ich da jetzt nehmen?

Den Takt, den du wirklich für deine CPU ausgesucht hast.

Wenn du nichts verändert hast, dann beträgt der Takt 1 MHz (interner
RC-Oszillator mit 8 MHz, aber clock prescaler auf 1:8 voreingestellt).

>
1
>   ADCSRA |= (1<<ADEN);                  // ADC aktivieren
2
> 
3
>   ADCSRA |= (1<<ADFR);                  // eine ADC-Wandlung
4
>
>
> wenn ich den Eingang PC5 überwachen will würde ADFR passen oder?

ADFR gibt's beim ATmegaX8 gar nicht.  Das war bei den älteren AVRs der
"free running mode", bei den aktuellen heißt dieses Bit ADATE (ADC
auto-trigger enable), weil außer "free running" noch weitere
automatische Trigger möglich sind.  Der Kommentar dort passt aber gar
nicht, da steht "eine ADC-Wandlung", das würde man durch
1
ADCSRA = (1<<ADSC);

erreichen ("SC" = "start conversion")

Damit, welchen ADC-Eingang du abfragst, hat das aber alles nichts zu
tun: das wird im ADMUX festgelegt.  Das Datenblatt enthält eine
Tabelle, in der die Zuordnung der Werte aufgeführt ist.

>   while (ADCSRA & (1<<ADFR) ) {}        // auf Abschluss der
> Konvertierung warten

Siehe oben, das wäre auch wiederum ADSC.

> Wenn ich es richtig verstanden habe sollte nun bereits der eingelesene
> Wert in result stehen?

Ja.

>   ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
> [/c]
>
>
> Was mach ich den dann mit ADMUX das auszulesende bit hatte ich doch
> vorher mit  ADCSRA |= (1<<ADFR); bestimmt ?

ADMUX und ADCSRA sind zwei völlig verschiedene Dinge.

> Welche Auflösung habe ich nun?

10 Bit.

> Wie kann ich nun z.b. bei dem wert 4 in der Variable test die LED 1
> (PC4) einschalten?

Hast du überhaupt schon mal was in C auf einem Controller gemacht?

von Martin *. (mistermister606)


Lesenswert?

C ++ habe ich schon gearbeitet aber jetzt nicht als Programmierer 
sondern rein als Hobby wie auch das Microcontroller Programmieren.

Ich hab nun mal alles etwas (für mich einfacher zu verstehen) gestrickt 
und eine If hinzugefügt auch wenn ich nicht glaube, dass dies stimmt.
1
int main()
2
{
3
4
 uint16_t result;
5
 
6
7
  ADMUX = (1<<REFS1) | (1<<REFS0);      // interne Referenzspannung nutzen
8
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
9
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
10
  DDRD = (1<<PD3);
11
 
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
21
22
23
  while( 1 )
24
  {
25
////////////////////////////////////////////////////////////////////////////////
26
 
27
28
/* ADC Einzelmessung */
29
 uint16_t test; 
30
31
32
33
34
  // Kanal waehlen, ohne andere Bits zu beeinflußen
35
  ADMUX = (1<<PC5);
36
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
37
  while (ADCSRA & (1<<ADSC) ) {}  // auf Abschluss der Konvertierung warten
38
  test = ADCW;                    // ADC auslesen und zurückgeben
39
40
41
  if(test == 4) {
42
    PORTD |= (1<<PD3);  //LED2
43
  }
44
  else {
45
    PORTD &= ~(1<<PD3);  //LED2
46
}
47
/////////////////////////////////////////////////////////////////////////////////
48
  }
49
}

btw. ich nutze den atm168

von Karl H. (kbuchegg)


Lesenswert?

Martin *** schrieb:

> Ich hab nun mal alles etwas (für mich einfacher zu verstehen) gestrickt
> und eine If hinzugefügt auch wenn ich nicht glaube, dass dies stimmt.

WTF

WOZU?

Benutz doch die Tutorialroutinen so wie sie sind. Die kopierst du in 
deinen Source Code einfach rein. Das ist doch nicht so schwer

Und dein main sieht dann so aus (auch das findet sich im 
Tutorialsbeispiel mehr oder weniger)
1
int main()
2
{
3
  uint16_t wert;
4
5
  ADC_Init()
6
7
  while( 1 ) {
8
    wert = ADC_Read( 5 );    // weil du vom Kanal 5, also PC5 lesen willst
9
10
    if( wert > 4 )
11
      mach was
12
    else
13
      mach was anderes
14
  }
15
}

Ich versteh gar nicht, was da jetzt so schwer drann sein soll. Ist doch 
ohnehin alles schon vorgearbeitet. Einzig deine Referenzspannung musst 
du im ADC_Init noch richtig einstellen, wobei die Einstellung für 
'intern Vcc' wahrscheinlich sowieso passt.

Was bitte ist an deinem Code jetzt einfacher als an diesem Code.


Udnd die 4, die wirst du wahrscheinlich nicht sehen. Du kriegst Werte 
von 0 bis 1023. Eine 4 kriegst du bei ein paar Millivolt. So genau 
kannst du ein Poti gar nciht einstellen. Sinnvoller wird für erste Tests 
wohl eher
1
    if( wert > 512 )
2
      mach was
3
    else
4
      mach was anderes

sein

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Martin *** schrieb:

>   ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
>   ADCSRA |= (1<<ADEN);                  // ADC aktivieren

Es gibt keinen Grund, das auf zwei Anweisungen zu verteilen.

>   ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung

Du hast noch keinen Kanal im ADMUX gewählt, also misst du
ADC0 (alias PC0).

>   // Kanal waehlen, ohne andere Bits zu beeinflußen
>   ADMUX = (1<<PC5);

Erstens passt 'ohne andere Bits zu beeinflußen' nicht zur Aktion
(ADMUX wird komplett neu beschrieben, mit allen Bits), und
zweitens ist das vermutlich nicht, was du willst.  PC5 hat den
Wert 5, also wird hier ADMUX auf 0b00100000 gesetzt, was dir
einerseits die bereits ausgewählte ADC-Referenz wieder zunichte
macht, und andererseits ADLAR setzt.  Vermutlich willst du
aber PC5 (alias ADC5) als ADC-Eingang benutzen:
1
ADMUX = (1<<REFS1) | (1<<REFS0) | PC5;

>   if(test == 4) {
>     PORTD |= (1<<PD3);  //LED2
>   }
>   else {
>     PORTD &= ~(1<<PD3);  //LED2
> }

Antwort vom Sender Jerewan: "Im Prinzip ja, aber".

Die Wahrscheinlichkeit, dass dein ADC-Ergebnis exakt 4 beträgt,
ist ziemlich klein.  Du wirst wohl eher einen Vergleich auf
"größer/gleich" oder sowas haben wollen.

von Martin *. (mistermister606)


Lesenswert?

Soooo nun funktioniert die Schaltung  :)
Ich danke euch recht herzlich für die Hilfe und eure Geduld :)

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.