Echo UART-Schnittstelle

OP #4775239
Lesenswert?

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
Angehängte Dateien:
Gast #4775287
Lesenswert?

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)
OP #4775349
Lesenswert?

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
Gast #4775426
Lesenswert?

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.
OP #4775472
Lesenswert?

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
#4775519
Lesenswert?

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.
OP #4775527
Lesenswert?

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
Gast #4775602
Lesenswert?

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)
#4775640
Lesenswert?

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
Gast #4775703
Lesenswert?

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.
Gast #4775746
Lesenswert?

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.

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