UART bei Atmega88

Gast #349127
Lesenswert?

Hallo,

ich mache gerade das GCC-Tutorial und hab da ein paar Probleme mit der
Aufgabe12 (UART2).

Versuche das Programm auf dem Atmega88 laufen zu lassen, jedoch bekomme
ich immer folgende Fehlermeldung:

avr-gcc.exe  -mmcu=atmega128 -Wall -gdwarf-2 -O0 -MD -MP -MT UART.o -MF
dep/UART.o.d  -c  ../UART.c
../UART.c: In function `main':
../UART.c:39: warning: implicit declaration of function `outp'
../UART.c:39: error: `RXCn' undeclared (first use in this function)
../UART.c:39: error: (Each undeclared identifier is reported only once
../UART.c:39: error: for each function it appears in.)
../UART.c:39: error: `UCsRnA' undeclared (first use in this function)
../UART.c:42: error: `UBRR' undeclared (first use in this function)
../UART.c:55: warning: implicit declaration of function `inp'
../UART.c:55: error: `USR' undeclared (first use in this function)
../UART.c:56: error: `UDRn' undeclared (first use in this function)
../UART.c:58: warning: implicit declaration of function `sbi'
../UART.c:61: warning: implicit declaration of function `cbi'
make: *** [UART.o] Error 1
Build failed with 7 errors and 4 warnings...


Für ein paar Tips wäre ich echt dankbar....!!!

Gruß
Angehängte Dateien:
Gast #349128
Lesenswert?

>RXCn, UDRn
Geil! Sowas hab ich ja noch nie gesehen.
Statt des "n" wirst du dort eine Zahl eintragen müssen.
(das n steht für eine der UARTs; scheibar hat der Mega88 bzw. der im
Tutorium verwendete Controller) mehrere davon.

"outp", "inp", "sbi", "cbi" sind obsolete (sollten nie mehr
verwendet werden) in der aktuellen gcc-Version.
Gast #349134
Lesenswert?

So,

hab einfach die Firmware mal neu drauf gespielt und der ISP Mode Error
ist weg.

Hab das Programm das sich im Anhang befindet nun auf den Atmega8515
umgeschrieben. Leider läuft es nicht so wie es soll. Es gehen alle
LED's an, laut Programm soll es nur eine sein. Und ein und ausschalten
lassen sie sich auch nicht.

Dann hab ich noch ne Frage, wie kannn ich dem Controller vom Rechner
aus über UART zB. eine 1 schicken. Hab gelesen mit Hyper Terminal, aber
wie?

Für ein paar Tips wäre ich super dankbar...!!!


Gruß
Angehängte Dateien:
Gast #349139
Lesenswert?

Benutzt du zufällig das STK500?

"Goto" ist sowieso sehr böse. Dafür benutzt man entweder eine
while(1)-Schleife oder eine for(;;)-Schleife.

switch (UDR) ist auch nicht sooo gut. Sobald einmal auf UDR zugegriffen
wurde, ist der Inhalt indifferent (oder so ähnlich).
Sicher UDR lieber in einer Variablen und setzt die in der
switch-Anweisung ein. Oder weisst du, was der Compiler aus switch(UDR)
macht?
Gast #349141
Lesenswert?

Das STK500 arbeitet mit inverser Logik: alles was logisch 1 sein soll
(LED ein), ist aus und anders herum (Um eine LED einzuschalten muß man
PORTx &= ~(1<<n); benutzen...

deklariere dir eine Variable z.B.

unsigned char temp;
temp = UDR;
switch(temp)...


Statt deiner Loop ... goto Loop solltest du
for(;;)
{
...
}
benutzen. Der Compiler erkennt dann, dass es sich dabei um eine
Endlosschleife handelt, und optimiert den Code entsprechend.
Gast #349142
Lesenswert?

Ok, hab statt goto eine Schleife verwendet.

Aber mein Problem ist ja eigentlich dass die ersten 6 LED#s leuchten
und die letzten bedien nicht.  Es dürfte ja eigentlich nur eine an sein
(oder halt aus weil ich nicht PORTx &= ~(1<<n); geschrieben habe).

Ist der Code denn vom Grundprinzip falsch?

Habe vor eine LED auf dem STK500 durch senden einer 1 einzuschalten und
durch senden einer 0 auszuschalten. Das ganze soll über UART vom PC aus
erfolgen.
Gast #349144
Lesenswert?

Guck dir mal das Beispiel im Datenblatt (complete) auf Seite 177 zur
Initialisierung und auf den folgenden Seiten die Beispiele fürs Senden
und Empfangen an.
Prinzipiell müsste dein Programm funktionieren...

Vielleicht solltest du aber erst mal ein Lauflicht programmieren, damit
du dich mit den Portzugriffen auseinandersetzt...
Gast #349148
Lesenswert?

So, hab das Programm jetzt mal für einen Atmega88 neu geschrieben.

Das empfangen von Daten klappt bestens, nur das senden vom µC zum PC
macht mir noch ein paar Probleme.

Hab es mit dem UDRE-Interrupt versucht. Wenn ich den Inreeupt direkt in
der UART-Initialisierung aktiviere, klappt es. Nur dann sendet er mir
halt dauerhaft.

Er soll mir aber nur was senden, wenn ich z.B. eine 3 eingebe. Nur das
klappt irgendwie nicht.

Wäre super wenn mir jemand einen Tip geben könnte::::!

Das Programm hab ich oben angehängt....
Angehängte Dateien:
Gast #349149
Lesenswert?

Zur Veranschaulichung:

// sendet einzelnes Zeichen an PC
void USART_transmit (unsigned char c)
{
  // warte bis Senden möglich
  while (!(UCSR0A & (1<<UDRE0))) {}

  // sende übergebenes Zeichen
  UDR0 = c;
}

// sendet Zeichenkette an PC
void USART_transmit_string (unsigned char *string)
{
  // warte bis Senden möglich
  while (!(UCSR0A & (1<<UDRE0))) {}

  // sende übergebene Zeichenkette (->einzelne Zeichen mit Hilfe der
Funktion USART_transmit)
  while ( *string)
  USART_transmit (*string++);
}

Besser ist natürlich die Bibi von P. FLeury, die sich auch hier
irgendwo im Forum tummeln müsste.
Gruß
Gast #349151
Lesenswert?

Ahja,

am besten wird sein, du murkst nicht innerhalb einer ISR weitere IR an
(zumal zum Auslösen ja noch das UDREn Flag fehlt), sondern setzt dir
ein  Flag, und arbeitest dies denn in der main ab.

global flag;

ISR Receive
{
 if UDR=2 --> flag=true;
}


main()
 for(;;)
 {
   if(flag=true)
   {
    flag=false;
    USART_transmit_string("alles klar");
   }
 }
#349152
Lesenswert?

> oder bei einer 2 soll er halt in die ISR springen
> und was zurückschicken....

Das soll er mit Sicherheit nicht.
Was er machen soll ist:
Er soll die Sende-Funktion mit einem Text als
Parameter anspringen. Direkt aus der ISR ist das aber
nicht so gut. Besser ist es, das zu Sendende erst mal
in einen Buffer zu schreiben und die Hauptschleife in main()
ruft dann die Sendefunktion auf. Die Sendefunktion
ihrerseits stellt die Zeichen in einen Ausgangspuffer,
stellt das erste Zeichen in den UART und
schaltet den Interrupt ein, der immer dann aufgerufen
wird, wenn das UART-Ausgangsregister frei zur Aufnahme
des nächsten Zeichens ist. Innerhalb der ISR wird dann
das nächste Zeichen aus dem Ausgangspuffer geholt, so
es noch eines gibt, und weggeschickt. Gibt es kein Zeichen
mehr im Ausgangspuffer, so dreht die ISR den Interrupt ab
woraufhin wieder Ruhe im µC herrscht.

Das ist dein Plan. Und wenn ich mich richtig erinnere
arbeitet die UART-Lib von Peter Fleury genau nach diesem
Plan.
Gast #349153
Lesenswert?

Danke!

Also die UART-LIB von Peter Fleury hab ich mir mir gerade mal
angeschaut. Doch das ist mir alles zu viel auf einmal, da verstehe ich
gar nix. Und nur das von ihm übernehmen und gut iss, das will ich
nicht.

Aber soweit kann ich doch mit meinem Programm auch nicht von einer
Lösung entfernt sein.

Also gehe ich nun folgendermaßen vor:

1. Ich deklariere mir einen Buffer für die zu sendenden Werte, z.B.
   unsigned char buffer;

2. Diesem wird dann bei einem bestimmten emfangenen Zeichen ein Wert
   zugewiesen.

3. Ich erstelle mir eine Sendefunktion z.B. UART_send, welche ich in
   der main() aufrufe und weise

3. In dieser Sendefunktion weise ich dem UDR0 den Wert vom Buffer
   zu, mache eine Abfrage ob das Ausgangsregister frei ist und
   schalte den Interrupt ein.

So ungefähr?

Und warum muss ich UDREn auch noch setzen? Wird das nicht automatisch
gesetzt sobald der UDRE-Interrupt gestartet wird...?

Grüße
#349154
Lesenswert?

> So ungefähr?

Yep. Klingt gut.

> Und warum muss ich UDREn auch noch setzen? Wird das nicht
> automatisch gesetzt sobald der UDRE-Interrupt gestartet wird...?

Der Interrupt wird ja nicht gestartet. Der Interrupt wird nur
freigegeben. D.h. Du erlaubst nur, dass Interrupts kommen
können. Die Aussage des Interrupts ist aber: "Das zu sendende
Zeichen ist soweit abgearbeitet, dass du mir wieder ein
Zeichen geben könntest." Damit das aber zutrifft, muss irgendwann
einmal ein Zeichen in UDRn gelandet sein. Und das ist das
erste Zeichen, dass du händisch hineinschreibst. Das Zeichen
wird abgearbeitet und dann beginnt der Interrupt Mechanismus
zu laufen.

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