Forum: Mikrocontroller und Digitale Elektronik mehrere Zeichen per UART empfangen


von Tobias L. (tobias_l477)


Angehängte Dateien:

Lesenswert?

Hallo zusammen
ich bin gerade ein wenig am verzweifeln...
ich habe eine ESP32 BT-Modul über die UART an einen Atmega88 
angeschlossen....
Ich möchte das BT-Modul als Gateway nutzen.
das heisst das BT Modul soll Daten per bluetooth empfangen und weiter an 
den Atmega88 schicken...

Ich kann aber leider NUR EIN ZEICHEN  empfangen
das heisst ich komme in die beiden IF Zweige (das sehe ich da ich die 
LED per BT ein und ausschalten kann)
aber ich bekomme als response nicht die 0x55 zurück.... hat einer eine 
idee woran es liegen kann?
ich bin seit längere Zeit aus dem aktiven coden raus und will mich 
wieder einarbeiten

von Olli Z. (z80freak)


Lesenswert?

Das ist ein Timing-Problem.

Der ESP32 sendet receive_BT_Array[1] und receive_BT_Array[2] über UART:
1
cppSerial.write(receive_BT_Array[1]);  // 0x33
2
Serial.write(receive_BT_Array[2]);

Der ATmega empfängt das in fillReceiveBuffer():
1
while ((UCSR0A & (1<<RXC0)))  // ← Problem hier!
2
{
3
    receivebuffer[indexBuffer] = UART_Receive();
4
    indexBuffer++;
5
}

Die while-Bedingung (UCSR0A & (1<<RXC0)) prüft nur ob im Moment der 
Ausführung wenigstens ein Byte im Buffer liegt. Nach dem ersten Byte ist 
RXC0 dann kurz 0, bevor das zweite Byte ankommt – die Schleife bricht 
also zu früh ab.

UART_Receive() wartet zwar intern mit while (!(UCSR0A & (1<<RXC0))), 
aber die äußere while-Schleife prüft das Flag bevor das nächste Byte 
ankam.

Du musst Deinen Code umbauen, auf Timeoutgesteuerten Empfang. Oder 
besser gleich mit UART-Events. Bei UART ist es auch eine Protokollfrage, 
wann Du glaubst das eine Übertragung beendet ist.

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Tobias L. schrieb:
> hat einer eine Idee, woran es liegen kann?
An der falschen Dateiendung!? SCNR

Dir ist schon klar, dass die serielle Schnittstelle wesentlich langsamer 
als der Prozessor ist, oder?
Wenn da kein Zeichen in der Zwischenzeit eingegangen ist, wird die 
Schleife verlassen und du löscht den Puffer.

Du solltest den Puffer entweder per Interrupt in der ISR füllen, oder in 
einer Schleife prüfen, ob ein neues Zeichen vorliegt (und es in den 
Puffer schreiben).
Deine Statemachine habe ich mir nicht angeguckt.

Du könntest natürlich auch eine Echo-Funktion zu Debugzwecken basteln, 
die das empfangene Zeichen über das Bluetooth-Modul (an dein BT-Terminal 
auf dem PC) zurücksendet.

von Falk B. (falk)


Lesenswert?


von Obelix X. (obelix)


Lesenswert?

Tobias L. schrieb:
> ich habe eine ESP32 BT-Modul über die UART an einen Atmega88
> angeschlossen....

Den Atmega raus schmeißen und die Aufgaben des Atmega auch den ESP32 
erledigen lassen.

Beitrag #8015843 wurde von einem Moderator gelöscht.
Beitrag #8015908 wurde von einem Moderator gelöscht.
Beitrag #8015909 wurde von einem Moderator gelöscht.
Beitrag #8015929 wurde von einem Moderator gelöscht.
Beitrag #8015961 wurde von einem Moderator gelöscht.
Beitrag #8016081 wurde von einem Moderator gelöscht.
von Adam P. (adamap)


Lesenswert?

Hey Tobias,

ich würde an deiner Stelle den Code erstmal anpassen um ein "sauberes" 
Verhalten zu bekommen.

Nutze den UART Interrupt:

In diesem kopierst du lediglich das UDR in ein Empfangsbuffer und 
erhöhst den Index.


Prüfung auf empfangenes Frame (Datenpaket):

Die Prüfung führst du dann z.B. in deiner main() aus.
Entweder wenn eine Mindestmenge an Daten empfangen wurde oder jedes mal 
wenn sich der Index erhöht hat, kommt immer dauf an was du machen 
möchtest.
Natürlich könnte man jetzt auch noch einen Funktion hinzufügen, die z.B. 
alles löscht bis zu einem Startzeichen (0xAB) oder sowas.

Grundsätzlich hast du damit den Empfang und die Verarbeitung getrennt 
und bist nicht mehr darauf angewiesen, immer auf den Empfang zu 
"hören/warten".

von Falk B. (falk)


Lesenswert?

https://www.mikrocontroller.net/articles/Interrupt#UART_mit_Interrupts

Das Prinzip geht so.

Das Datenpaket vollständig empfangen, incl. Abschlußzeichen, meisten in 
einer ISR, siehe Interrupt. Geht aber im Zweifel auch ohne.
Mittels Variable das Datenpaket signalisieren
Eine andere Funktion / State machine wertet das Datenpaket aus
Datenpaket als bearbeitet markieren
Datenpaket löschen
Neues Datenpaket empfangen

: Bearbeitet durch User
von Tobias L. (tobias_l477)


Lesenswert?

meeeeegangeil danke... ich schaue es mir gleich an

von Martin V. (oldmax)


Lesenswert?

Hi
Die Lösung kann ein Ringpuffer sein. Dazu wird ein Speicherbereich 
definiert, je nach Bedarf so 5 bis 10 Telegrammlängen. Dazu brauchst du 
einen Schreibzeiger und einen Lesezeiger, die beim Start auf 0 gesetzt 
werden.
Die eingehenden Daten erfasst du mit einem Interrupt und schreibst in 
der ISR das empfangene Byte auf die Startadresse + Schreibzeiger. Den 
Schreizeiger erhöhst du und prüfst die Grenze des reservierten 
Speicherbereiches. Hast du die Grenze erreicht, setzt du den 
Schreibzeiger wieder auf 0. In der Programmschleife fragst du ab ob 
Schreib- und Lesezeiger gleich sind. Wenn nicht, holst du dir das 
empfangene Byte aus dem Ringpuffer (Startadresse + Lesezeiger) in einen 
Arbeitsbereich und erhöhst den Lesezeiger. Es folgt die Grenzwertabfrage 
mit entsprechendem Rücksetzen. Anschießend wird der Inhalt des 
Arbeitsbereiches auf ein vollständiges Telegramm geprüft und dieses dann 
verarbeitet. Ein Telegramm kann zusätzlich zu den Nutzdaten einen Kopf 
(z.B "STRT") und eine Endekennung bekommen (z.. "ok") Auch die 
Nutzdatenläge kann hinter der Startkennung stehen. Inder Regel holst du 
dir so bei jedem Programmdurchlauf ein Byte. Das bedeutet aber auch, das 
du bei einer Gesamtlänge eines Telegrammes von bspw. 20 Byte 20 
Programmdurchläufe brauchst, bevor du die Daten vollständig verwerten 
kannst Das sollte aber in Anbetracht einer relativ langsamen seriellen 
Übertragung kein Problem bereiten.
Na dann, viel Erfolg
Gruß oldmax

von Falk B. (falk)


Lesenswert?

Martin V. schrieb:
> Hi
> Die Lösung kann ein Ringpuffer sein.

Kann. Ist hier aber für den Anfang nicht sinnvoll und auch nicht nötig, 
es erhöht nur die Komplexität. Ein einfacher Puffer reicht erstmal.

Beitrag #8018766 wurde vom Autor gelöscht.
von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Etwa so.

von Christian M. (christian_m280)


Lesenswert?

Martin V. schrieb:
> Schreizeiger

Zeigt der auf Schreie?

Gruss Chregu

von Martin V. (oldmax)


Lesenswert?

Hi
Falk B. schrieb:
> Kann. Ist hier aber für den Anfang nicht sinnvoll und auch nicht nötig,
> es erhöht nur die Komplexität. Ein einfacher Puffer reicht erstmal.

Ich halte einen Ringpuffer schon für sinnvoll. Wir wissen ja nicht, wann 
die Daten eintrudeln, wann und wie schnell eine Übertragung stattfindet 
und ob immer vollständige Datensätze ohne Fehler übertragen werden. Das 
allein fängt auch ein Ringpuffer nicht ab, aber in Zusammenspiel mit ein 
bisschen Protokoll im Telegramm (z.B. Start und Länge) lassen sich 
Fehler erkennen. Geht natürlich auch mit einem einfachen Puffer. Ist ein 
Ringpuffer erst einmal verstanden, ist er auch für andere Aufgaben 
nutzbar. Und so kompliziert und komplex ist er nun auch wieder nicht. 
Aber was auch immer, im Ergebnis zählt ein sicher funktionierendes 
Programm.
Gruß oldmax

von Rahul D. (rahul)


Lesenswert?

Martin V. schrieb:
> Ich halte einen Ringpuffer schon für sinnvoll.
Bei jeder Anwendung?

> Wir wissen ja nicht, wann
> die Daten eintrudeln, wann und wie schnell eine Übertragung stattfindet
> und ob immer vollständige Datensätze ohne Fehler übertragen werden.
> Das allein fängt auch ein Ringpuffer nicht ab,
> aber in Zusammenspiel mit ein
> bisschen Protokoll im Telegramm (z.B. Start und Länge) lassen sich
> Fehler erkennen.
Ein Protokoll mit einer Checksumme kann beliebig lang sein.
Mein Lieblingsbesipiel dafür ist NMEA0183.

> Geht natürlich auch mit einem einfachen Puffer.
Gut erkannt. Wenn das Telegrammende erkannt und das Telegram geparsed 
wurde, setzt mal den Schreibpointer einfach wieder auf 0.

> Ist ein Ringpuffer erst einmal verstanden
Deswegen schrieb Falk ja auch "für den Anfang".

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.