Forum: Mikrocontroller und Digitale Elektronik UART bei Atmega88


von Stefan (Gast)


Angehängte Dateien:

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ß

von Der inoffizielle WM-Rahul (Gast)


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.

von Stefan (Gast)


Lesenswert?

Ja, hast ja Recht. Musste ich selber drüber lachen....!!! Hab es jetzt
gändert.

Wie schreib ich denn outp anders....??


Gruß

von Der inoffizielle WM-Rahul (Gast)


Lesenswert?

outp: PORTx = ...
inp: var = PINx
sbi: PORTx |= (1<<bit);
cbi: PORTx &= ~(1<<bit);

wobei bit = 0..7.
x steht für den Port-Buchstaben.
var ist in der Regel eine unsigned char-Variable.

von Stefan (Gast)


Lesenswert?

Super, Danke...!!! Funktioniert alles!

Wie würde ich den das hier umschreiben:

if (inp (UCSR1A) & (1 << RXC1))    ?????

von Uwe Nagel (Gast)


Lesenswert?

if ( UCSR1A & (1 << RXC1))  !!

Ausserdem steht in deinem Makefile wohl noch der maga128. Erste Meldung
im ersten Posting...

von Stefan (Gast)


Lesenswert?

Danke, jetzt hab ich es kapiert.

Leider zeigt er mir beim aufspielen auf den Controller die
Fehlermeldung "ISP MODE ERROR" an.

Was bedeutet das..?

von Stefan (Gast)


Angehängte Dateien:

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ß

von Thorsten F. (thorsten)


Lesenswert?

avr-gcc.exe  -mmcu=atmega128
                   ^^^^^^^^^
                   |||||||||

sicher?

von Stefan (Gast)


Lesenswert?

Ne, sicher nicht!

Weiß nicht warum da immer der atmega128 angegeben wird. Hab eigentlich
den atmega88 gesetzt. Woran kann das liegen.....?

Gruß

von Der inoffizielle WM-Rahul (Gast)


Lesenswert?

Falsches Makefile

von Stefan (Gast)


Lesenswert?

Gut, das mit dem Makefile hab ich auch hinbekommen.

Aber das Programm läuft immer noch nicht. Sitze schon den ganzen Tag
davor, krieg es aber einfach nicht hin. Warum leuchten bei mir denn
alle LED's? Kann sich das Programm mal bitte einer anschauen und mir
einen Tip geben. Bin schon echt verzweifelt.....

Gruß

von Der inoffizielle WM-Rahul (Gast)


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?

von Stefan (Gast)


Lesenswert?

Ja, ich benutze das STK500.

Ne, keine Ahnung was der Compiler aus Switch UDR macht. Bin ziemlicher
Anfänger auf dem Gebiet.

Aber warum Leuchten denn alle LED's...??

Wie kann ich das Programm denn am besten umschreiben. Will gar kein
fertiges Programm, nur ein paar Tips in die richtige Richtung....

von Der inoffizielle WM-Rahul (Gast)


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.

von Stefan (Gast)


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.

von ecslowhand (Gast)


Lesenswert?

Wenn die LED auf dem STK500 an seinsoll, muss der entsprechende Portpin
auf LOW liegen !!!

von Der inoffizielle WM-Rahul (Gast)


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...

von Stefan (Gast)


Lesenswert?

Hey, Danke!

Das die Ports auf LOW liegen müssen hatte ich schon geändert.
Hab das Datenblatt hier liegen und mitlerweile das Programm schon
umgeschrieben.

Nur warum Leuchten 6 LED's obwohl ich nur Pin0 gesetzt (oder auch
nicht gesetzt habe)? Muss doch irgendeinen Grund haben, dass die
anderen auch Leuchten.

von Der inoffizielle WM-Rahul (Gast)


Lesenswert?

Vielleicht solltest du einfach zu beginn deines Programms mal alle LEDs
löschen (beim STK500: "PORTB = 0xFF;", sonst "PORTB = 0x00;").

von Der inoffizielle WM-Rahul (Gast)


Lesenswert?

Übrigens gibt es hier auf der Seite auch ein gutes C-Tutorium.
Die Sachen von Christian Schifferle sind schon etwas "antiquiert"...

von Stefan (Gast)


Angehängte Dateien:

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....

von Jens (Gast)


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ß

von Stefan (Gast)


Lesenswert?

Das hab ich wohl soweit schon kapiert! Ohne Interrupt klappt es ja
auch!

Nur würd ich es halt schon gerne mit nem Interrupt machen! Sobald ein
Zeichen empfangen wird, bei einer 1 soll eine LED geschaltet
werden(klappt alles) oder bei einer 2 soll er halt in die ISR springen
und was zurückschicken....

von Jens (Gast)


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");
   }
 }

von Karl heinz B. (kbucheg)


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.

von Stefan (Gast)


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

von Karl heinz B. (kbucheg)


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.

von Karl heinz B. (kbucheg)


Lesenswert?

Oder auf Deutsch:
Der Interrupt meldet sich bei: "Juhu, ich bin fertig. Gibts
noch was zu tun?"

von Stefan (Gast)


Lesenswert?

Hey, hatt geklappt!

Funktionierte alles super, bis gerade! Hab nichts verändert, aber nun
muss ich das zu sendende Zeichen zweimal drücken damit es z.B. die LED
einschaltet....!

Woran kann das nun wieder liegen....

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.