Atmega128 - ADC Funktion

Gast #2975208
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
Angehängte Dateien:
Gast #2975220
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.
Gast #2975232
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.
Gast #2975641
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
#2975661
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)
Gast #2977054
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
Angehängte Dateien:
Gast #2978272
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren