Forum: Compiler & IDEs Atmega128 - ADC Funktion


von Johannes (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe µC Freunde,

ich habe eine Frage und hoffe Ihr könnt mir helfen.
Ich versuche bei meinem Projekt einen ADC zu verwenden. Bisher habe ich 
nur mit einem AtXmega 128 Erfahrungen sammeln können. Der Atmega 128 ist 
ähnlich jedoch nicht identisch von der Syntax.

Folgende Aufgabe:

Ich möchte eine Spannung am PORTF PIN 0 einlesen.

Setup:

Single Ended (GND)
Free Runing Mode
right Adjusted
Prescaler 64

Das Ergebnis möchte ich auf meinem angeschlossenen LCD ausgeben.
Display ist angeschlossen und funktioniert einwandfrei.

Leider habe ich trotz vieler Versuche keinen Erfolg mit dem ADC gehabt 
und hoffe Ihr könnt mir helfen,

1
//////////////////////// ADC Einstellungen ///////////////////////////////
2
unsigned char result;
3
4
5
// AVCC with external capacitor at AREF pin 
6
// right adjusted
7
// Single Ended Input
8
9
ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX4) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0);
10
 
11
////////// Starte den ADC ////////////////
12
13
//ADC Enable
14
//ADC Start Conversion
15
//ADFR: ADC Free Running Select
16
// Prescaler 64
17
18
19
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADFR) | (0 << ADIF) | (0 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
20
 
21
22
 
23
  // Lies den 8-Bit Wert aus
24
25
  result = ADCH;
26
27
28
///////////////////////////////////////////////////////////////////////////


Zusätzlich hänge ich auch den Code für die Display Ausgabe an wobei der 
erste Teil für die korrekte Darstellung der Zahlen benötigt wird und 
nicht betrachtet werden muss.
1
lcd_init();
2
3
  lcd_setcursor( 0, 4 );
4
     lcd_string("Speed: ");
5
6
7
8
9
   void lcd_number( uint8_t number, uint8_t len, uint8_t fill ) {
10
    uint8_t digit1 = 0;
11
    uint8_t digit2 = 0;
12
    while (number >= 100) {
13
        digit1++;
14
        number -= 100;
15
    }
16
    while (number >= 10) {
17
        digit2++;
18
        number -= 10;
19
    }
20
    if (len > 2) lcd_data( (digit1 != 0) ? digit1+'0' : fill );
21
    if (len > 1) lcd_data( ((digit1 != 0) || (digit2 != 0)) ? digit2+'0' : fill );
22
    lcd_data( number+'0' );
23
}
24
 
25
void lcd_number_xy( uint8_t x, uint8_t y, uint8_t number, uint8_t len, uint8_t fill ) {
26
    lcd_setcursor( x, y );
27
    lcd_number( number, len, fill );
28
  }
29
  
30
  lcd_setcursor( 6, 4 );
31
   lcd_number( result,4,4);
Das ADC Ergebnis (result) lasse ich mir auf mein Display ausgeben leider 
bisher ohne Erfolg. An PORTF PIN 0 liegt eine Spannung von 0-4,5V an ich 
variieren sie Spannung mit einem POTI bzw. einem Spannungsteiler.

Hoffe jemand hilft mit auf die Sprünge.

Vielen Dank

von Stefan E. (sternst)


Lesenswert?

Johannes schrieb:
> Ich möchte eine Spannung am PORTF PIN 0 einlesen.
1
ADMUX = ... | (1 << MUX4) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0);
Wie passt das zusammen?

von katastrophenheinz (Gast)


Lesenswert?

Hi,
Du kannst nicht unmittlelbar nach dem Start der Wandlung lesen, sondern 
musst warten, bis die Wandlung fertig ist, also z.B.
 while ( ADCSRA & (1 << ADSC) );
vor dem Auslesen des Wandlungsergebnisses aus ADCH.

von Stefan E. (sternst)


Lesenswert?

katastrophenheinz schrieb:
> musst warten, bis die Wandlung fertig ist, also z.B.
>  while ( ADCSRA & (1 << ADSC) );

Ne, bei Free-Running kann er nicht auf ADSC warten. Da müsste er schon 
auf ADIF warten.


Noch eine Sache:
1
 // Lies den 8-Bit Wert aus
2
3
  result = ADCH;
Wie soll denn bei Right-Adjusted aus ADCH ein 8-Bit Wert rauskommen?
Da stehen dann nur 2 Bits drin.

von katastrophenheinz (Gast)


Lesenswert?

> Ne, bei Free-Running kann er nicht auf ADSC warten. Da müsste er schon
> auf ADIF warten.
Stimmt, ich hab free running überlesen.

... und wenn du mit
> result = ADCH;
nur die 8 MSB lesen willst, dann musst du ADC 'left aligned' sein, d.h. 
ADLAR=1.

Ausserdem sollte man nach ADEN=1 nicht umittelbar eine Wandlung starten, 
sondern das erste Wandlungsergebnis wegwerfen, da erst mit ADEN=1 die 
Referenzspannung durchgeschaltet wird.

von Johannes (Gast)


Lesenswert?

Hallo und vielen Dank für die Antworten.

Ich habe euren Rat befolgt und "lefet aligned" eingestellt: ADLAR=1.
Leider sehe ich kein Ergebnis auf dem Display.
Ich habe eine andere Frage, da ich vermute es könnte auch an der Ausgabe 
liegen.

Frage1: Stimmt der PORTF PIN0 als ADC analog Eingang?
Wie stelle ich den PIN ein bin leider aus ADC MUX nicht besonders schlau 
geworden.

Frage2: Wie prüfe ich schnell ob der ADC funktioniert ohne Display 
Ausgabe?

Kann ich mit AVR Studio nicht Breakpoints setzen und mir einzelne 
Variabeln anschauen? Ich habe vor langer Zeit mal sowas verwendet weiß 
aber nicht mehr genau ob es AVR Studio war?

Grüße an alle Helfer und vielen lieben Dank

von STK500-Besitzer (Gast)


Lesenswert?

Johannes schrieb:
> Frage1: Stimmt der PORTF PIN0 als ADC analog Eingang?

Ja.

Johannes schrieb:
> Wie stelle ich den PIN ein bin leider aus ADC MUX nicht besonders schlau
> geworden.

Eingang, ohne Pull-Up.

Johannes schrieb:
> Frage2: Wie prüfe ich schnell ob der ADC funktioniert ohne Display
> Ausgabe?

Den Wert über die serielle Schnittstelle ausgeben.

von Karl H. (kbuchegg)


Lesenswert?

STK500-Besitzer schrieb:

> Johannes schrieb:
>> Frage2: Wie prüfe ich schnell ob der ADC funktioniert ohne Display
>> Ausgabe?
>
> Den Wert über die serielle Schnittstelle ausgeben.

Entweder das, oder man prüft eben die Umkehrung: Funktioniert die 
Zahlenausgabe aufs LCD, selbst wenn die Werte dafür nicht vom ADC kommen 
sondern zb über eine for-Schleife generiert werden.


Im übrigen: Meiner Meinung nach wird der Free-Running Modus meistens 
sowieso überschätzt. Warum verwendest du die ROutinen aus dem 
AVR-GCC-Tutorial nicht einfach so, wie sie sind? Für 99% aller Fälle 
reicht das völlig aus, und wenn nicht, dann sind sie erst mal trotzdem 
ein guter Ausgangspunkt um Hardware-Probleme erst mal auszuschliessen 
und dann daraus (nachdem man den ADC in Betrieb genommen hat!) die 
gewünschte Funktionalität zu erzeugen.

Im Moment hast du 3 Baustellen
du weißt nicht, ob du einen Hardware Fehler hast
du weißt nicht, ob deine Zahlenausgabe aufs LCD funktioniert
du weißt nicht, ob deine Eigenbaufunktionen funktionieren

das sind mindestens 2 Baustellen zuviel.
Speziell dann, wenn man bedenkt, dass ausser deine Hardware alles andere 
im Grunde schon fix&fertig auf dich warten würde.
1
...
2
3
int main()
4
{
5
  char buffer[20];
6
  uint16_t value;
7
8
  lcd_init();
9
  adc_init();
10
11
  while( 1 ) {
12
    value = adc_read( 0 );    // vom Kanal 0, Pin F0
13
    sprintf( buffer, "value = %04d", (int)value );
14
    lcd_gotoxy( 0, 0 );
15
    lcd_string( buffer );
16
  }
17
}

(Im adc_init die Einstellung der Referenzspannung laut Datenblatt nicht 
vergessen)

von Stefan E. (sternst)


Lesenswert?

Johannes schrieb:
> Wie stelle ich den PIN ein bin leider aus ADC MUX nicht besonders schlau
> geworden.

Wie lautet der Name des Pins in Bezug auf den ADC?
Wo in der MUX-Tabelle steht dieser Name als Input?
Wie müssen demzufolge die MUX-Bits gesetzt werden?

von holger (Gast)


Lesenswert?

M103C Fuse deaktiviert?

ATmega103 Compatibility Mode
• Port F serves as digital input only in addition to analog input to the 
ADC.

von Johannes (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe mal versucht eine Zahl zu generieren und auf dem Display 
auszugeben.
1
for(i=0;i<=1000;i++)
2
  
3
{
4
 lcd_setcursor( 6, 4 );
5
 lcd_number( i, 4, 4 );
6
 _delay_ms(20);
7
 i++;
8
9
 }

Die Ausgabe funktioniert soweit, jedoch hat Herr Buchegger vollkommen 
Recht.
Ich habe zuviele Baustellen und verliere mich. Für die Inbetriebnahme 
des ADCs sollte ich die eingelesenen Werte meiner Meinung nach erstmal 
digital ausgeben per sprintf Befehl. Folgende Syntax habe ich immer bei 
meinem Xmega verwendet.

1
// Beispiel für eine Ausgabe Xmega (Ausgabewert wäre hier i
2
// Hyperterminal als Anzeige für digitale Ausgabe
3
4
char Wert[100]
5
init_RS232 (F0, 115200);  // Serielle Schnittstelle initialisieren
6
7
sprintf(Wert,"\r%d\n",i); 
8
serial_puts(Wert,F0);

Wie lautet die Syntax für den Atmega128?

Gibt es für den ADC/DAC eine Include Datei habe bisher noch keine 
gefunden für den Atmega. Leider kann ich die für den Xmega nicht 
verwenden, da andere µC Struktur.



Danke für eure Hilfe

von Karl H. (kbuchegg)


Lesenswert?

Johannes schrieb:

> Wie lautet die Syntax für den Atmega128?


genau gleich, schliesslich ist sprintf eine C-Standard-Funktion.

Lediglich die \r und \n brauchst du auf einem LCD nicht


> Gibt es für den ADC/DAC eine Include Datei habe bisher noch keine
> gefunden für den Atmega.

AVR-GCC-Tutorial
Konkret
AVR-GCC-Tutorial/Analoge Ein- und Ausgabe

von katastrophenheinz (Gast)


Lesenswert?

Hallo Johannes,
nimm dir den Beispielcode aus dem Link von K-H. Buchegger oben. Da ist 
alles berücksichtigt, was es beim ADC im ATmega an Besonderheiten zu 
berücksichtigen gibt.

Und um weitere Fehlerquellen auszuschließen, würde ich als ersten 
Versuch
die interne Vbg (1,23V) gegen die interne Vref (2,56V )wandeln.

d.h. ADMUX = ( 1 << REFS1 ) | ( 1 << REFS0 ) | ( 1 << ADLAR ) | 0b11110;

Da sollte dann konstant 123 als 8bit-Ergebnis in ADCH rauskommen.
Wenn das funktioniert, dann weißt du, daß dein ADC-Code grundsätzlich 
funktioniert und du kannst drangehen, ein externes Analogsignal zu 
wandeln.
Falls das dann nicht funktioneren sollte, kannst du als Fehlerquelle den 
ADC-Programmcode ausschließen.

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.