Hallo zusammen! Ich will ein Byte über die serielle Schnittstelle an den Mikrocontroler senden, dort,soll ein Interrupt ausgelöst werden und das empfangene Byte zurück an den Computer gesendet werden. Ich benutze ein Arduino mit dem Controller Atmel 328P, programmiere und aber mit dem Atmel Studio 6. Wenn ich nun ein Byte an den Mikrocontroller sende, kommen bei bestimmten Werten der richtige Wert zurück. Bei anderen Werten kommt der falsche Wert zurück. Ich finde den Fehler einfach nicht. Hier der Code: #define BAUD 9600 #define FOSC 16000000 #define MYUBRR FOSC/16/BAUD-1 #include <avr/io.h> #include <avr/interrupt.h> #include <stdint.h> uint16_t ubrr = MYUBRR; uint8_t receive_byte_uart; ISR(USART_RX_vect) { receive_byte_uart = UDR0; while ( !( UCSR0A & (1<<UDRE0)) ); UDR0 = receive_byte_uart; } int main(void) { sei(); UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; UCSR0B |= (1<<RXEN0)|(1<<TXEN0) | (1<<RXCIE0); while(1) { } } Ein Screenshot habe ich auch hochgeladen. Ich übertrage 8 Datenbits und ein Stopbit. Dies ist ja schon standardmäßig im entsprechendne Register eingestellt. Diese fehlende Codezeile ist nicht der Fehler. Kann mir jemand weiterhelfen? lg Julian
Was macht denn bei dir die Zeile: [c] UCSR0B |= (1<<RXEN0)|(1<<TXEN0) | (1<<RXCIE0); [\c] ?
Was macht denn bei dir die Zeile:
1 | UCSR0B |= (1<<RXEN0)|(1<<TXEN0) | (1<<RXCIE0); |
?
Hallo! Den Interrupt einschalten wenn ein Datenbyte empfangen wurde, sowie das Senden und Empfangen über die UART-Schnittstelle einschalten. lg Julian
Schon, aber diese Veroderung bei einer Initialisierung auf einem Arduino, da scheinen manchmal wundersame Dinge zu passieren. Also, das Oder weglassen, oder, interessehalber, nach dem Oder das UCSR0B mal ausgeben. (ohne jetzt akg vorgreifen zu wollen)
Zur Fehlereingrenzung: definiere dir erstmal Datenbytes auf dem Controller und überprüfe, ob die Daten auch so gesendet werden. So kannst du zunächst überprüfen, wo der Fehler entsteht.
Hallo! Erstmal vielen Dank für die zahlreichen Antworten. Ich habe mir jetzt einen Timer_Interrupt programmiert der sekündlich aufgerufen wird. In der Interruptroutine versende ich zwei Datenbytes über die UART-Schnittstelle. Schon da gibt es Probleme :-(. es kommt lediglich ein Datenbyte an und dieses hat den falschen Wert. Bei anderen Programmierungen mit diesem Mikrocontroller hat die Datenausgabe über UART jedoch schonmal einwandfrei funktioniert. lg Julian
Hast Du jetzt mal geschaut, ob CKDIV8 gesetzt oder gelöscht ist und was das für eine Wirkung hat?
Das wäre ihm hoffentlich spätestens jetzt
> Timer_Interrupt ... sekündlich
aufgefallen.
In der Interrupt-Routine lasse ich eine LED blinken. Diese geht gefühlsmäßig auch jede Sekunde an bzw. aus. Also bin ich mir ziemlich sicher, dass der Mikrocontroller einen Takt von 16 kHz verwendet.
Falls Sie einem Softwareproblem noch eine gewisse Wahrscheinlichkeit zuordnen, sollten Sie das aktuelle Programm vorstellen.
Julian S. schrieb: > In der Interrupt-Routine lasse ich eine LED blinken. Diese geht > gefühlsmäßig auch jede Sekunde an bzw. aus. Also bin ich mir ziemlich > sicher, dass der Mikrocontroller einen Takt von 16 kHz verwendet. Nun, Dein weiterer (unbekannter) Code für das Blinken, führt auch eine weitere Fehlerquelle ein. Hingegen ist das ablesen dieser Information vom Bildschirm im Vergleich weniger fehlerträchtig. (Wenn ich auch zugeben muss, dass ich regelmäßig überlege was es nun bei Atmel heisst, wenn die Fuse programmiert ist oder nicht). Ich erlaube mir deswegen, Dir zu raten, Dich nicht auf Dein Gefühl zu verlassen sondern zu prüfen, zumal, falls Du vorher die Arduino-IDE und Firmware benutzt hast, möglicherweise mit dieser und anderen Fuses noch nie zu tun hattest.
Ich habe nun bei der Initalaisierung der UART-Schnittstelle die letzte Zeile hinzugefügt: UCSR0B = (1<<RXCIE0) | (1<< RXEN0) | (1<<TXEN0);; UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); UCSR0A = (1<<UDRE0); Nun klappt alles einwandfrei. Ich weiß allesdings nicht wieso ich dieses Bit zu Beginn setzen muss. Dies wird auch nicht beim Beispiel im Datenblatt gemacht. Habe zufällig diese Zeile im Internet gesehen und ausprobiert. Vielleicht kann mir das noch jemand erklären. Ansosnsten vielen Dank für die zahlreichen Antworten. lg Julian
Julian S. schrieb: > Ich weiß allesdings nicht wieso ich dieses > Bit zu Beginn setzen muss. Dieses Bit ist Read-Only. Das kannst du gar nicht setzen. > Dies wird auch nicht beim Beispiel im Datenblatt gemacht. Wozu auch. S.o. > Habe zufällig diese Zeile im Internet gesehen und ausprobiert. Ein Tip aus der Kategorie "Von Leuten, die keine Ahnung haben". > Vielleicht kann mir das noch jemand erklären. Die Erklärung ist eine ganz einfache: Mit dieser Anweisung wird das ganze Register gelöscht. Das ist das, was Sinn macht, weil damit nämlich auch das U2X0-Bit und das MCPM0-Bit gelöscht wird. Die einzigen Bits, die in diesem Register mit dieser Anweisung angetastet werden. Daß der Arduino das MCPM0-Bit benutzt ist unwahrscheinlich aber die Benutzung des U2X0-Bit umso wahrscheinlicher. Dieses Bit verdoppelt die Baudrate. Deswegen funktionierte es nicht. Das wurde dir hintenrum auch schon mitgeteilt: S. Landolt schrieb: > Schon, aber diese Veroderung bei einer Initialisierung auf einem > Arduino, da scheinen manchmal wundersame Dinge zu passieren. Also, das > Oder weglassen, oder, interessehalber, nach dem Oder das UCSR0B mal > ausgeben. Das gilt natürlich auch für alle anderen Register.
:
Bearbeitet durch User
Hi! Bei der Veroderung ging es um ein anderes Register. Ich habe es auch versucht indem ich das Register mit dem entsprechen Wert direkt beschrieben habe. Ohne Erfolg. Das ich durch die letzte Zeile das Bit U2X0 auf Null setze stimmt, trotzdem finde ich es komisch, da dieses ohnehin mit dem Wert 0 initialisiert wird. Das ich das UDRE0 gar nicht beschrieben kann, habe ich übersehen. Da habe ich einen Fehler durch einen anderen Fehler gelöst. lg Julian
Also "hintenrum" war nicht meine Absicht, besser wusste ich es einfach nicht, sorry, hatte noch nie mit Arduino etwas zu tun; versuche aber, mir die Zusammenhänge zu merken. "Wir fang' noch mal von vorne an, weils hintenrum nicht gehen kann..." (Otto Reutter)
Ich denke schon. Ich programmiere den Arduino über die USB-Konverter auf dem Mikrocontrollerboard. Hat das damit etwas zu tun?
Julian S. schrieb: > Ich denke schon. Ich programmiere den Arduino über die USB-Konverter auf > dem Mikrocontrollerboard. > > Hat das damit etwas zu tun? Ja der Bootloader verwendet ja auch den UART und wird entsprechend konfiguriert. Er sollte zwar vorm Verlassen den Urzustand wieder herstellen kann aber sein das das beim Arduino im Normalfall erst mit dem Init des über die IDE erstellten Anwenderprogramms gemacht wird. Dadurch kann es sein das beim Start Deines Programms die Registerwerte nicht den Zustand haben den das Datenblatt nach einem Reset vermuten lassen würde. Damit hast du dann mit einer Veroderung deiner Initwerte ein Problem. Sascha
:
Bearbeitet durch User
Ach sch... ich dachte Amazon Echo hätte ne praktische UART Schnittstelle :(
Julian S. schrieb: > Ich will ein Byte über die serielle Schnittstelle an den Mikrocontroler > senden, dort,soll ein Interrupt ausgelöst werden und das empfangene Byte > zurück an den Computer gesendet werden. Und deswegen schreibst du solch einen unüberlegten Murks? Du kannst dir nicht vorstellen, daß man bei einer asynchronen seriellen Übertragung sowohl empfangsseitig als auch sendeseitig im µC die Datenströme sinnvoll puffern sollte? Nein? mach es anders: schreib dir nen Treiber, der Sendedaten und Empfangsdaten in jeweils einem Ringpuffer zuwischenspeichert, der Daten per Interrupt empfängt und auch per Interrupt sendet. Das Abholen aus dem Rx-Puffer und ggf. das Senden (in den TX-Puffer) erledigst du auch nicht in der Grundschleife, sondern du schreibst dir sowas wie ein kleines Kommandoprogramm dafür. Also: - Grundschleife ruft zyklisch Kommandoprogramm auf. - Kommandoprogramm fragt Treiber, ob RX Daten vorhanden sind. Wenn nicht: return. - Wenn der Treiber sagt, daß RX Daten da sind, dann holt das Kommandoprogramm ein Zeichen ab (wieder vom Treiber), verarbeitet es nach Gusto und übergibt es wiederum dem treiber zwecks Senden. - Der Sende-Teil des Treibers schaut nach, ob noch Platz im TX Puffer ist und stapelt das Zeichen dort ein. Obendrein guckt er nach, ob das interruptgesteuerte Senden gerade im Gange ist und stößt es ggf. in geeigneter Weise an. W.S.
//ARDUINO int inChar; void setup() { Serial.begin(115200); } void loop() { } void serialEvent() { while (Serial.available()) { inChar = (char)Serial.read(); Serial.write( inChar); } }
Hm. Das hätte man vorher wissen müssen. Ich wusste gar nicht, dass man mit AVRStudio 6 den Arduino Bootloader verwenden kann und dachte, dass man, wie mit Version 4 in der Regel das komplette Flash löscht, bevor das Programm reingeschrieben wird.
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.