Forum: Mikrocontroller und Digitale Elektronik ATMega32 - ADC&UART


von Beginner (Gast)


Lesenswert?

Nabend!

Ich bin ein interessierter Anfänger was die Microcontroller angeht.
Für heute hatte ich mir vorgenommen mit dem integrierten AD-Wandler des 
ATMega32 zu arbeiten und die Daten dann über UART zum PC zu senden.

Orientiert habe ich mich dabei an den Artikeln hier aus dem Forum. 
Kurzum ich habe den Schleifer eines Potis an den ADC0 Eingang des 
Controllers gelegt und die anderen beiden Anschlüsse an VCC sowie GND.
AREF beträgt ebenfalls 5V.

Nun habe ich das Problem das ich mit dem Terminalprogramm immer nur "FF" 
empfange, egal wie ich das Poti verändere.
Könnt ihr mir sagen was ich falsch mache?


Anbei der Code:
#include <avr/io.h>
#include <inttypes.h>
#include <stdio.h>

#define BAUD        19200UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)




void uart_init(void)       // USART initialisieren
{
    UBRRH = (uint8_t) (UBRR_BAUD>>8);
    UBRRL = (uint8_t) (UBRR_BAUD & 0x0ff);
    UCSRB = (1<<RXEN)|(1<<TXEN);
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}


int main(void)
{
  int buffer;
  int i;


  ADCSRA = (1<<ADEN)|(1<<ADSC);

  while ( ADCSRA & (1<<ADSC) )
    {
    ;
    }

  buffer=ADCW;

//------------------------------------------------------------------

  uart_init();            // UART initialisieren

  while ( !( UCSRA & (1<<UDRE)) )
    {
    ;
    }

        UDR = buffer;
}

Ich hoffe ich habe Euch keine essentiellen Informationen unterschlagen 
;)
Gruß

von Johannes M. (johnny-m)


Lesenswert?

Was hältst Du davon, die Wandlung und das Senden mal in eine 
Endlosschleife zu packen? So wie es da steht, wird nur ein einziges Mal 
gewandelt und gesendet.

Außerdem: Wie groß ist Dein F_CPU, wo ist es angegeben und womit 
erzeugst Du den Takt?

Und noch was: AVCC ist intern als Referenz auswählbar (in ADMUX mit 
REFS0/1) und sollte nicht extern an den AREF-Pin angeschlossen werden! 
Der AREF-Pin sollte nur dann mit einer externen Spannung verbunden 
werden, wenn eine Referenzspannung benötigt wird, die der µC intern 
nicht zur Verfügung stellen kann.

von Johannes M. (johnny-m)


Lesenswert?

Ach ja, die erste Wandlung nach dem Aktivieren des ADC ergibt i.d.R. 
kein sinnvolles Ergebnis und sollte verworfen werden.

von Beginner (Gast)


Lesenswert?

Das nur einmal gewandelt und gesendet wird sollte eigentlich so sein, 
hab jetzt aber eine Endlosschleife drumherum gemacht.
F_CPU ist 16000000
Erzeugt wird der Takt mit einem 16MHz Quarz. Fusebits sind korrekt.

Mit der Endlossschleife empfange ich jetzt:
CE 67 99 CE 67 99 EE E3 67 99

was sich dann immer wiederholt. Irgendwie bin ich jetzt doch etwas 
verwirrt...

von Beginner (Gast)


Lesenswert?

Ahh ok Danke. Das mit dem AREF Pin werde ich dann nochmal ändern und auf 
den internen zurückgreifen.

von Johannes M. (johnny-m)


Lesenswert?

Beginner wrote:
> Ahh ok Danke. Das mit dem AREF Pin werde ich dann nochmal ändern und auf
> den internen zurückgreifen.
Und dann auch gleich an AREF einen kleinen Kondensator (100 nF) gegen 
GND.

Dürfte aber mit Deinem Problem nichts zu tun haben...

von Beginner (Gast)


Lesenswert?

Habe jetzt

ADMUX = (1<<REFS0);

in den Code eingefügt und auch den Kondensator zwischengeschaltet.
Mit dem terminalprogramm empfange ich jetzt das folgende:
CE 67 99 CE 67 99 CE 67 CE 67 99 CE 67 99 CE 77 CE 67 99

usw.
Drehen am Poti hat nachwievor keinen Einfluß auf die Werte

von STK500-Besitzer (Gast)


Lesenswert?

Dein ADC-Buffer ist 16 Bit breit und das UDR nur 8...

von Johannes M. (johnny-m)


Lesenswert?

Nun ja, die Werte an sich kann ich mir momentan auch nicht erklären. Was 
mir aber noch aufgefallen ist: In UDR passen ja nunmal nur 8 Bit rein, 
das Wandlungsergebnis hat aber 10 Bit. D.h., Du schneidest bei der 
Zuweisung "UDR = buffer;" die beiden höchsten Bits ab und überträgst nur 
die letzten 8. Dass da keine sinnvollen Werte am PC ankommen, sollte 
klar sein...

von Beginner (Gast)


Lesenswert?

Ja da habt ihr natürlich recht, aber wenn ich das Poti von min. nach 
max. und umgekehrt drehe, dann müssten sich die Werte doch auf jedenfall 
ändern.
Habs nochmal nachgemessen die Spannung am ADC0 Pin ändert sich durch 
verändern der Schleiferstellung...

Könnte man das Problem mit dem Cast Operator lösen?
Also im Prinzip: UDR = (char) buffer;

von Johannes M. (johnny-m)


Lesenswert?

Beginner wrote:
> Könnte man das Problem mit dem Cast Operator lösen?
> Also im Prinzip: UDR = (char) buffer;
Nö. Auf die Weise schneidest Du genauso das High-Byte ab wie in dem 
anderen Fall, nur dass Du jetzt noch dem Compiler mitteilst, dass das 
auch beabsichtigt ist... Was Du machen könntest ist, das Bit ADLAR im 
ADMUX setzen und nur ADCH auslesen (anstelle von ADC(W)). Dann bekommst 
Du die 8 höherwertigen Bits und die beiden letzten werden weggeworfen. 
Oder Du schiebst buffer bei der Zuweisung um zwei Stellen nach 
rechts...

von Beginner (Gast)


Lesenswert?

Also wenn ich das richtig verstanden und umgesetzt habe sieht der ADC 
Teil jetzt folgendermaßen aus:

ADCSRA = (1<<ADEN)|(1<<ADSC);
  ADMUX = (1<<REFS0);
  ADMUX = (1<<ADLAR);


  while ( ADCSRA & (1<<ADSC) )
    {
    ;                     // auf Abschluss der Konvertierung warten
    }


  buffer=ADCH;        // ADC Wert in Buffer schreiben

Ja jetzt passiert folgendes:
Ist die Spannung am ADC0 Pin größer als ~4,2V so sendet er "FF" ist die 
Spannung kleiner dann garnichts.
Ich bin etwas ratlos ....

von STK500-Besitzer (Gast)


Lesenswert?

>  ADMUX = (1<<REFS0);
>  ADMUX = (1<<ADLAR);

Jetzt ist nur noch das ADLAR-Bit gesetzt.

So muß das heissen:

  ADMUX = (1<<REFS0) | (1<<ADLAR);

von Beginner (Gast)


Lesenswert?

oh ja klar da hab ich gepennt ... im ADCSRA Register hatte ich es ja 
auch schon so gemacht.
Am Ergebnis hat sich leider nichts geändert. Bzw. durch das Verändern 
der Schleiferstellung ändern sich die empfangenen Werte im 
Terminalprogramm nicht

von STK500-Besitzer (Gast)


Lesenswert?

Poste mal dein aktuelles Programm (im Angang!).

von Beginner (Gast)


Angehängte Dateien:

Lesenswert?

Ok ist als Anlage beigefügt

von STK500-Besitzer (Gast)


Lesenswert?

Die Initialisierungen sollten beide vor die for(;;)-Schleife - 
schließlich braucht man die Schnittstelle und den ADC nur ein Mal 
initialisieren.
Vermutlich hast du deswegen auch nur unsinnige Werte.

von Beginner (Gast)


Lesenswert?

Mhh ja das war schonmal ein guter Schritt in die richtige Richtung!
Irgendwo ist aber noch eine Kleinigkeit würde ich sagen.
Das Terminalprogramm zeigt mir jetzt nur noch einen hexadezimalen Wert 
an, welcher sich allerdings auch nicht ändert, wenn man die 
Schleiferstellung verändert. Die Endlosschleife ist nachwievor im 
Programm.
Ich hab mir grad mal die Spannung am ADC0 Pin gemessen und die 
dazugehörigen HEX Werte aus dem terminalprogramm notiert:
5V  ->8C
3V  ->42
1,1V->C6

Das kann doch irgendwie nicht stimmen ...

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.