mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mit STM32 Byte-Sequenz aus UART-Strom herausfischen?


Autor: lorns (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, die Überschrift klingt etwas wirr. Ich möchte von einem STM32 über 
einen UART mit einem ESP8266 über AT-Befehle kommunizieren.

Wenn ich einen AT-Befehl gesendet habe, möchte ich wissen, ob die 
Antwort OK oder ERROR ist. Da die Antwort keine feste Länge hat, hole 
ich nacheinander Bytes und schaue, ob das Ende aus der gesuchten Sequenz 
(z.B. "OK") besteht:
uint8_t *p = buffer;
int found = 0, count = 0;

while (1) {
  if (HAL_UART_Receive(&huart7, p++, 1, 1000))
    break;
  if (++count >= 2 && !strncmp(p - 2, "OK", 2)) {
    found = 1;
    break;
  }
}
dlog(buffer);  // log on other serial connection
if (found)
  dlog("FOUND");
else
  dlog("ABORT");

Falls die Schleife irgendwann mit Timeout abbricht, war die Sequenz 
nicht enthalten.

Leider funktioniert das nicht so, wie es soll. Hier ist das Log:

AT check ...        <-- meine Meldung, nach Abseten von "AT"
T                   <-- ESP über dlog(buffer), Anfang verpasst
                    <-- ESP    
OK                  <-- ESP
FOUND               <-- meine Meldung
set station ...     <-- meine Meldung, nach Absetzen von "AT+CWMODE=1"
                    <-- ESP
                    <-- ESP 
OK                  <-- ESP
ABORT               <-- meine Meldung

Wieso wird das letzte OK nicht erkannt? Verhält sich der 
HAL_UART_Receive anders als ich denke?

Autor: Stefan P. (form)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Ein erster Schritt zum Erfolg könnte daraus bestehen den 
RX-Complete-Interrupt des verwendeten Mikrocontrollers zu verwenden um 
einen Empfangspuffer zu füllen ohne etwas zu verpassen.

Autor: Bülent C. (mirki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich mich nicht irre schickt der ESP am Ende immer ein 0Ah,0Dh.
Diese Zeilenenden musst Du abfangen.
Also:
im RX interrupt immer byteweise in ein buffer schreiben und schauen ob 
der aktuelle und der letzte byte ein 0Dh und ein 0Ah ist.
Achtung: Du benutzt diese s...ß HAL Treiber, ein RX interrupt wird hier 
nur ausgelöst, wenn der angegeben buffer mit seiner angegeben länge 
gefüllt ist. Daher die länge immer mit 1 angeben, aber das tust Du 
schon.

Autor: lorns (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan P. schrieb:
> Ein erster Schritt zum Erfolg könnte daraus bestehen den
> RX-Complete-Interrupt des verwendeten Mikrocontrollers zu verwenden um
> einen Empfangspuffer zu füllen ohne etwas zu verpassen.

Ich hatte es mit Interrupts versucht, aber dann muß ich mit der HAL eben
HAL_UART_Receive_IT(&huart7, p++, 1)

schreiben. Der Interrupt wird bei Erreichen der angeforderten 
Zeichenzahl ausgelöst und nicht, wenn der UART einige Zeit keine Zeichen 
mehr empfangen hat.

Wie sollte das helfen? Der Nachteil ist ja sogar, dass es kein Timeout 
mehr gibt.

Autor: Curby23523 N. (nils_h494)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bülent C. schrieb:
> Achtung: Du benutzt diese s...ß HAL Treiber

So siehts aus ;).

Autor: lorns (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bülent C. schrieb:
> im RX interrupt immer byteweise in ein buffer schreiben und schauen ob
> der aktuelle und der letzte byte ein 0Dh und ein 0Ah ist.
> Achtung: Du benutzt diese s...ß HAL Treiber, ein RX interrupt wird hier
> nur ausgelöst, wenn der angegeben buffer mit seiner angegeben länge
> gefüllt ist. Daher die länge immer mit 1 angeben, aber das tust Du
> schon.

Aber dann müßte doch auch mein Code funktionieren, indem ich direkt nach 
"OK" suche, oder?

(Nebenbei: Es ist DMA konfiguriert, aber für diesen Abschnitt verwende 
ich Polling.)

Autor: STM32 User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
strncmp  verlangt 0-terminierte Strings.

Autor: Auch Einer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
STM32 User schrieb im Beitrag #5426352:
> strncmp  verlangt 0-terminierte Strings.

Käse.

Einfach mal eine C Referenz lesen.

Autor: Bülent C. (mirki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
lorns schrieb:
> Bülent C. schrieb:
> im RX interrupt immer byteweise in ein buffer schreiben und schauen ob
> der aktuelle und der letzte byte ein 0Dh und ein 0Ah ist.
> Achtung: Du benutzt diese s...ß HAL Treiber, ein RX interrupt wird hier
> nur ausgelöst, wenn der angegeben buffer mit seiner angegeben länge
> gefüllt ist. Daher die länge immer mit 1 angeben, aber das tust Du
> schon.
>
> Aber dann müßte doch auch mein Code funktionieren, indem ich direkt nach
> "OK" suche, oder?
>
> (Nebenbei: Es ist DMA konfiguriert, aber für diesen Abschnitt verwende
> ich Polling.)

Dma macht man nur bei festen längen. Das ist hier nicht der Fall.
Du musst das Zeilenende abfangen, aber das schrieb ich ja oben bereits.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bülent C. schrieb:
> Du musst das Zeilenende abfangen, aber das schrieb ich ja oben bereits.

Es gibt viele Typen von Antworten, wo der ESP mehrere Zeilen als eine 
Antwort schickt, z.B. die Liste der verfügbaren APs. Welches Zeilenende 
genau soll der TO abfangen?

Als ich damals einen Parser für die ESP-AT-Schnittstelle schrieb, musste 
ich frustriert feststellen, dass je nach Firmware-Version die Antworten 
des ESP vollkommen anders strukturiert waren und das 
Firmware-übergreifend nicht mehr in den Griff zu bekommen war.

Also hab ich eine eigene Firmware für den ESP geschrieben. Seitdem 
klappt das reibungslos mit der Aufgabenteilung zwischen STM32 und 
ESP8266, siehe auch:

WordClock mit WS2812

Autor: lorns (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bülent C. schrieb:
> Dma macht man nur bei festen längen. Das ist hier nicht der Fall.

Das habe ich oben geschrieben.

> Du musst das Zeilenende abfangen, aber das schrieb ich ja oben bereits.

Ja, kann man machen, aber ich bin nur daran interessiert, ob irgendwo 
OK vorkommt. Im ersten Beispiel funktioniert es, im zweiten nicht - 
wieso?

Sähe Dein Code denn großartig anders aus? Du würdest die Zeichen doch 
auch einzeln vom UART abholen?

Autor: Bülent C. (mirki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
lorns schrieb:
> Bülent C. schrieb:
>> Dma macht man nur bei festen längen. Das ist hier nicht der Fall.
>
> Das habe ich oben geschrieben.
>
>> Du musst das Zeilenende abfangen, aber das schrieb ich ja oben bereits.
>
> Ja, kann man machen, aber ich bin nur daran interessiert, ob irgendwo
> OK vorkommt. Im ersten Beispiel funktioniert es, im zweiten nicht -
> wieso?
>
> Sähe Dein Code denn großartig anders aus? Du würdest die Zeichen doch
> auch einzeln vom UART abholen?

Ja, aber ich würde sie alle erstmal in ein Buffer tun, und dies solange 
bis ich ein Zeilenende sehe, und erst dann schaue ich nach was drinne 
ist.

Autor: foobar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dir ist schon bewußt, dass deine Routine bei konstantem Datenstrom ohne 
erkanntes OK irgendwann wild im Speicher rumschreibt? Ab wann was 
passiert, hängt von der Größe von buffer ab.

Autor: lorns (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, nach vielen, vielen Versuchen, hier endlich die Lösung:
HAL_Receive_DMA();
HAL_Transmit_DMA();
findOK(timeout);
HAL_UART_DMAStop();
// ...
HAL_UART_DMAResume();
HAL_Receive_DMA();
HAL_Transmit_DMA();
findOK(timeout);
HAL_UART_DMAStop();
// ...

HAL_DMA_Abort(), oder einfach einen neuen DMA-Request ohne Resume 
abzusetzen funktioniert bei mir NICHT.

Wäre ich nie draufgekommen, wenn ich nicht zufällig den Code irgendwo 
gesehen hätte.

Autor: lorns (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Funktioniert doch nicht, der Code liest immer wieder das erste OK.

Ich suche also immer noch ein funktionierendes Beispiel.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.