Forum: Mikrocontroller und Digitale Elektronik Echo UART-Schnittstelle


von Julian S. (julian_s416)


Angehängte Dateien:

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

von akg (Gast)


Lesenswert?

Was macht denn bei dir die Zeile:
[c]
UCSR0B |= (1<<RXEN0)|(1<<TXEN0) | (1<<RXCIE0);
[\c]
?

von akg (Gast)


Lesenswert?

Was macht denn bei dir die Zeile:
1
UCSR0B |= (1<<RXEN0)|(1<<TXEN0) | (1<<RXCIE0);
?

von Julian S. (julian_s416)


Lesenswert?

Hallo!

Den Interrupt einschalten wenn ein Datenbyte empfangen wurde, sowie das 
Senden und Empfangen über die UART-Schnittstelle einschalten.

lg Julian

von S. Landolt (Gast)


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)

von CKDIV8 (Gast)


Lesenswert?

CKDIV8

von akg (Gast)


Lesenswert?

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.

von Julian S. (julian_s416)


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

von CKDIV8 (Gast)


Lesenswert?

Hast Du jetzt mal geschaut, ob CKDIV8 gesetzt oder gelöscht ist und was 
das für eine Wirkung hat?

von S. Landolt (Gast)


Lesenswert?

Das wäre ihm hoffentlich spätestens jetzt
> Timer_Interrupt ... sekündlich
aufgefallen.

von Julian S. (julian_s416)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

Falls Sie einem Softwareproblem noch eine gewisse Wahrscheinlichkeit 
zuordnen, sollten Sie das aktuelle Programm vorstellen.

von CKDIV8 (Gast)


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.

von Julian S. (julian_s416)


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

von Thomas E. (thomase)


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.

: Bearbeitet durch User
von Julian S. (julian_s416)


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

von S. Landolt (Gast)


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)

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

hast du auf den Arduino noch einen Bootloader drauf?

Sascha

von Julian S. (julian_s416)


Lesenswert?

Ich denke schon. Ich programmiere den Arduino über die USB-Konverter auf 
dem Mikrocontrollerboard.

Hat das damit etwas zu tun?

von Sascha W. (sascha-w)


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

: Bearbeitet durch User
von MuxMux (Gast)


Lesenswert?

Ach sch... ich dachte Amazon Echo hätte ne praktische UART Schnittstelle 
:(

von W.S. (Gast)


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.

von 0815 (Gast)


Lesenswert?

//ARDUINO


int   inChar;
void setup() {
  Serial.begin(115200);

}

void loop() {

}
void serialEvent()
{
  while (Serial.available())
  {
    inChar = (char)Serial.read();
    Serial.write( inChar);

  }
}

von CKDIV8 (Gast)


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.

von Thiange (Gast)


Lesenswert?

Stück Draht zwischen RX und TX spart Dir all die Probleme..

von Thiange (Gast)


Lesenswert?

Mit Autom. Baudratenerkennung!
Das mach erst mal in Software nach.

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.