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ß
>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.
Ja, hast ja Recht. Musste ich selber drüber lachen....!!! Hab es jetzt gändert. Wie schreib ich denn outp anders....?? Gruß
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.
Super, Danke...!!! Funktioniert alles! Wie würde ich den das hier umschreiben: if (inp (UCSR1A) & (1 << RXC1)) ?????
if ( UCSR1A & (1 << RXC1)) !! Ausserdem steht in deinem Makefile wohl noch der maga128. Erste Meldung im ersten Posting...
Danke, jetzt hab ich es kapiert. Leider zeigt er mir beim aufspielen auf den Controller die Fehlermeldung "ISP MODE ERROR" an. Was bedeutet das..?
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ß
Ne, sicher nicht! Weiß nicht warum da immer der atmega128 angegeben wird. Hab eigentlich den atmega88 gesetzt. Woran kann das liegen.....? Gruß
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ß
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?
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....
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.
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.
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...
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.
Vielleicht solltest du einfach zu beginn deines Programms mal alle LEDs löschen (beim STK500: "PORTB = 0xFF;", sonst "PORTB = 0x00;").
Übrigens gibt es hier auf der Seite auch ein gutes C-Tutorium. Die Sachen von Christian Schifferle sind schon etwas "antiquiert"...
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....
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ß
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....
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"); } }
> 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.
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
> 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.
Oder auf Deutsch: Der Interrupt meldet sich bei: "Juhu, ich bin fertig. Gibts noch was zu tun?"
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.