Hallo, ich versuche jetzt schon seit einigen Tagen in der ArduinoIDE einen vernünftigen Workaround zu schaffen, mit dem ich uint8_t AT-Commands via UART senden kann. Ich habe das schon einige Mal mit FreeErtos gemacht, leider bekomme ich es aber in der ArduinoIDE nicht hin. Also serielles senden und empfangen eines uint8_t Array via UART. Und die Konvertierung in beiden Richtungen in Arduino::String klasse. Kann mir diesbezüglich jemand weiterhelfen. Vielen lieben Dank. René
:
Bearbeitet durch User
Serial.print , Serial.println und das andere Geraffel zum Thema "Serial". uint8_t* ist bei AT-Kommandos fehl am Platz.
> uint8_t* ist bei AT-Kommandos fehl am Platz.
Nicht immer bei meinen Modul werden uint8_t Zeichen erwartet und müssen
auch gesendet werden.
Was hat uint8_t mit AT-Kommandos zu tun. AT ist nur ein Syntax soweit
ich das Verstehe. Ich kann auch gerne mal einen Auszug eines RTOS
Programms welches ich mal geschrieben habe Posten.
1 | int mqtt_clean(mqtt_connect_configuration mqtt_connect_configuration) |
2 | { |
3 | char *msg_mqtt_clean = (char*) malloc(sizeof(char)*21); |
4 | if(msg_mqtt_clean == NULL) |
5 | { |
6 | return EXIT_ERROR; |
7 | } |
8 | sprintf(msg_mqtt_clean,"AT+MQTTCLEAN=%d\r\n",mqtt_connect_configuration.LinkID); |
9 | HAL_UART_Transmit(&huart1, (uint8_t*)msg_mqtt_clean, strlen(msg_mqtt_clean), HAL_MAX_DELAY); |
10 | HAL_UART_Receive(&huart1,(uint8_t*)RX_Buffer,TX_BUFFER_SIZE,TX_TIMEOUT_DURATION); |
11 | if (strstr(RX_Buffer,"OK") != NULL) |
12 | { |
13 | uart_handler_tx_message("MQTT Close MQTT Connection -> Was successful.",UART_HANDLER_MSG_TYP_STATUS,__FILE__,__LINE__); |
14 | } |
15 | else |
16 | { |
17 | uart_handler_tx_message("MQTT Close MQTT Connection -> Was not successful.",UART_HANDLER_MSG_TYP_ERR,__FILE__,__LINE__); |
18 | free(msg_mqtt_clean); |
19 | return EXIT_FAILURE; |
20 | } |
21 | free(msg_mqtt_clean); |
22 | memset(RX_Buffer,0,strlen(RX_Buffer)); |
23 | return EXIT_SUCCESS; |
24 | } |
Sowas Ähnliches möchte ich auch in der ArduinoIDE auf sinnvollerweise implementieren. Nur das es dieses Mal um BLE geht. Ich versuche eine serielle Kommunikation zum NINA B312 herzustellen und verwende als Enticklungsboard für meinen Brototypen Mikroe BLE 4 click. René
:
Bearbeitet durch User
René schrieb: > Ich kann auch gerne mal einen Auszug eines RTOS > Programms Posten. Man muß nicht gleich mit Kanonen auf Spatzen schießen. Wozu das umständliche malloc/free? Es reicht einfach ein Array von 21 Byte anzulegen. Das wird automatisch beim Verlassen der Funktion wieder freigegeben. Und es kann auch nicht fehlschlagen. Und da ja auf dem Arduino kein RTOS läuft, würde ich sowas eh nicht blockierend programmieren.
> Man muß nicht gleich mit Kanonen auf Spatzen schießen. > Wozu das umständliche malloc/free? Hat manche Funktionen gegeben dier mehrere sachen gleichzeitig machen und wir hatten ein heap problem. Save ist Save. Mich würde interessieren, wie ich sowas Ähnliches im Arduino Umfeld lösen könnte. Mir ist im Klaren, dass hier unterschiede gegeben sind. Ich wollte nur auf den vorhergehenden Kommentar eingehen. Hätte jemand ein Beispiel? Ich vermute mal: Ich bin nicht der einzige der ein Board bzw. Modul mit dem Arduino seriell betreibt, welches die Zeichen Byte weise liest und schreibt. LG René
:
Bearbeitet durch User
René schrieb: > Ich bin nicht der einzige der ein Board bzw. Modul mit > dem Arduino seriell betreibt, welches die Zeichen Byte weise liest und > schreibt. Typisch benutzt man für die UART je einen FIFO für TXD und RXD, die dann im Interrupt gesendet bzw. gefüllt werden. Das Main kann also ohne Warten eine Nachricht in den FIFO schreiben. Aus dem RX-FIFO sammelt es dann die Bytes in einen Puffer, bis das Zeilenende erkannt wird und parst es dann. Man sendet also ein Paket und parst das empfangene Paket.
René schrieb: > Save ist Save. Mit Fremdsprachen soll man vorsichtig sein - insbesondere, wenn man nicht damit umgehen kann. Was genau willst du sparen?
STK500-Besitzer schrieb: > Serial.print > , Serial.println Leist denn heute keiner mehr die Dokus? Niemand mehr? Auch nicht die Fragen? Mit print und println kann man vieles ausgeben. aber... STK500-Besitzer schrieb: > und das andere Geraffel zum Thema "Serial". > uint8_t* ist bei AT-Kommandos fehl am Platz. Naja... Serial.write(buf, len) Das ist dafür gemacht um uint8_t Arrays auszugeben https://www.arduino.cc/reference/de/language/functions/communication/serial/write/
Peter D. schrieb: > Typisch benutzt man für die UART je einen FIFO für TXD und RXD, die dann > im Interrupt gesendet bzw. gefüllt werden. Öhm... Genau das tut Serial
was hier wieder alles durcheinander geworfen wird... René schrieb: > in der ArduinoIDE einen Die ArduinoIDE ist die (spartanische) Entwicklungsumgebung, die ist nicht das API das du für eine jeweilige Zielhardware brauchst. FreeRTOS hat auch keine Devicetreiber, dein Beispiel nutzt Funktionen aus der STM32 HAL. Peter D. schrieb: > Und da ja auf dem Arduino kein RTOS läuft, würde ich sowas eh nicht > blockierend programmieren. Sehr falsch, beim ESP ist FreeRTOS im Kern eingebaut, und auch für den ESP gibt es das Arduino Framework. Und auch wenn FreeRTOS nicht im Core ist, kann man es einbauen. Auch für die AVR, nur macht es da keinen Sinn wg. wenig RAM. Hier geht es aber offensichtlich um einen fetten Cortex-M7 mit reichlich Resourcen. Da kommt es jetzt drauf welcher Arduino Core verwendet wird. Wenn es ein STM32Duino ist, dann baut der auf dem STM32 HAL auf und die UART Funktionen können genauso verwendet werden. Arduino krallt sich da allerdings gerne die Interruptvektoren, für die Interrupt getriebenen Funktionen muss dieser dann zurückgebogen werden. Und bei so einem Projekt würde ich PlatformIO verwenden, das bietet da wesentlich mehr Komfort.
> Naja... > Serial.write(buf, len) > Das ist dafür gemacht um uint8_t Arrays auszugeben
1 | if (Serial1.available()==0) { |
2 | Serial1.write((uint8_t*)"AT+UBTLN=\"u-blox NINA René\"", strlen("AT+UBTLN=\"u-blox NINA René\"")); |
3 | } |
Ja, das funktioniert bei mir, ich schaffe es das mein Modul reagiert. Jedoch stelle sich für mich nun 2 Fragen: Wie kann ich die Antwort danach lesen und wie kann ich diese nachher in einen Ardoino::String konvertieren? Ja, du hast absolut recht: von J. S. (jojos) Ich möchte es auch früher oder später auf PlatformIO umsetzen. Jedoch vorerst auf der Ardoino Plattform, um zu testen, ob ich mit der Rechenleistung, sprich mit der Zeit der Berechnung auskomme. Da meinen yC ein UWD und ein BLE Sensor verbunden werden und ich damit TOA und RSSI von mehreren Notes messen möchte. Ja ich weiß, ich könnte auch den B312 als zentrale yC verwenden, aber dann habe ich nicht mehr die Möglichkeit die Module einfach und kompakt untereinander zu vergleichen. (Verschiedene Antennen ... verschiedene Chips). Die Arduino Plattform ermöglicht es mir eine raschen Mikrochip wechsel ohne grobe Code Änderungen. Normalerweise arbeite ich mit Microchip-Studio , Ertos oder PlatformIO. Ich poste anschließend auch gerne eine komplette Funktionsbibliothek, welche die NINA Chips abdeckt. Also so einfach wie möglich. Alles andere nimmt e schon riesige ausmaße. Nach den ganzen Test kann ich es in eine Richtige IDE überführen. LG René
:
Bearbeitet durch User
Hallo, @ TO: Hast du ein Übertragungsprotokoll? Ohne dem geht nichts. Hast du einen Lesebuffer der vom Serial FIFO befüllt wird? Hast du einen Schreibbuffer mit dem der Serial FIFO befüllt wird?
René schrieb: > Ja, das funktioniert bei mir, Was du da ausgibst, ist kein uin8_t Array , sondern ein char Array Also liegt der Fehler schon in der Frage! Richtig wäre damit: Serial1.print("AT+UBTLN=\"u-blox NINA René\""); oder eben println, wenn es ein Zeilenende benötigt é ist ein utf8 Dingen?!? Dann ist strlen() irgendwie komisch, denn das erkennt keine UTF8 Dinger
EAF schrieb: > René schrieb: >> Ja, das funktioniert bei mir, > Was du da ausgibst, ist kein uin8_t Array , sondern ein char Array > Also liegt der Fehler schon in der Frage! So ist es. Auf den allermeisten Platformen ist uint8_t einfach nur ein Alias für unsigned char. Und ein old school "String" in C ist ein Array derselben bzw. ein Pointer darauf. Dementsprechend kann man die Konvertierunsfunktionen jeglicher String-Klasse benutzen. > é ist ein utf8 Dingen?!? > Dann ist strlen() irgendwie komisch, denn das erkennt keine UTF8 Dinger Es ist kompatibel. Mehrbyte-Sequenzen a'la UTF-8 werden einfach als die entsprechende Anzahl Zeichen gerechnet. Dös baschd scho!
René schrieb: > uint8_t AT-Commands via UART Klassischerweise sendet oder empfängt man über UART Zeichen, also im Grunde Textzeichen, wofür eigentlich 'char' der richtige Datentyp ist. Rein physisch bestehen die herkömmlicherweise aus einem Byte, wobei bei ASCII das MSB nicht benutzt ist. Deine Ausführungen zeigen eigentlich nur eine erhebliche Oberflächlichkeit. AT-Kommandos sind blanker Text, aber keine uint8_t (also unsigned char). Und falls du in deiner Firmware einen ordentlichen Treiber für den UART hast, dann sendet und empfängt der die Zeichen auch ordentlich über den UART. Dabei ist es herzlich egal, was für ein Bitmuster da in einem Byte übergeben werden. Allenfalls kann es einem möglicherweise passieren, daß das MSB gelöscht wird, um dem Wertebereich von ASCII zu entsprechen. Aber das ist unerheblich für AT-Kommandos und heutzutage recht unüblich geworden. Dei Problem ist wohl, daß du ein Array senden/empfangen willst. Bedenke mal, daß der serielle Transport über UART nicht arrayweise, sondern zeichenweise erfolgt. Also richte dich danach und erwarte nicht, daß der serielle Treiber dir die Arbeit abnimmt. Und der Rest deiner Probleme ist wohl, daß du mit den diversen Automatismen von C nicht klarkommst. So zum Beispiel mit dem Backslash in Zeichenketten. Das hat aber weder mit dem Editor noch mit einem RTOS noch mit einer IDE zu tun. Forist schrieb: > Was genau willst du sparen? Scherzbold. Frag ihn lieber "do you speak british?" und erwart die Antwort "yes, a paar broken" W.S.
Axel S. schrieb: > Und ein old school "String" in C ist ein > Array derselben bzw. ein Pointer darauf. Ein C-String ist ein Array aus char, nicht ein Array aus unsigned char. Ob char selbst wiederum signed oder unsigned ist, ist nicht festgelegt (bzw. kann als Compileroption spezifiziert werden).
Axel S. schrieb: > Dös baschd scho! Zufall, Glück, oder was auch Immer.... Hier geht es gerade mal gut. Aber im nächsten unbedarften Augenblick kann das ins Auge gehen. Dann, ist das ein schwer zu findender Fehler, da man sich sicher ist, dass das schon mal so (oder so ähnlich) geklappt hat. sizeof() strlen() mblen() Ich rate da zu ein klein wenig Aufmerksamkeit/Sorgfalt. Émile schrieb: > Ob char selbst wiederum signed oder unsigned ist, ist nicht festgelegt So ist es, wenn ich meinen AVR-GCC frage, dann antwortet er auf beide Fragen is_signed() is_unsigned() mit false
Absolut Richtig. Komme noch von der Alten Schule. Jedoch zurück zu meiner Frage. Gibt es einen einfachen Weg in der Arduinobibliothek, welche mir einen *"unsigned char []" oder "uint8_t char []" von UART lesen kann* und eine gute Methode um diesen danach wieder in einen *Arduin::String Objekt konvertieren* kann. Liebe Grüße René Ramsauer
René schrieb: > um diesen danach > wieder in einen *Arduin::String Objekt konvertieren* kann. Du konvertierst zuviel! Damit legst du dir selber Steine in den Weg. Unter Vorbehalt: Serial.readString() Beachte dabei den Timeout
René schrieb: > Jedoch zurück zu meiner Frage. Gibt es einen einfachen Weg in der > Arduinobibliothek, welche mir einen *"unsigned char []" oder "uint8_t > char []" von UART lesen kann* und eine gute Methode um diesen danach > wieder in einen *Arduin::String Objekt konvertieren* kann. Ich glaub, ich krieg bei sowas Pickel. Also, eben noch habe ich versucht, dir zu erklären, daß du dich um's Block machen selbst kümmern solltest und nun willst du einen char[] vom Treiber haben. Mal ganz abgesehen davon, daß ein char[ohne anzahl] hier fehl am Platze ist. So, hoffentlich gibt's keine Rüge vom Moderator für so ein Stück Beipiel. Die Zeichen werden einzeln abgeholt und zur Kommandozeile zusammengesetzt. Ein bissel Primitiv-Editieren ist auch dabei, falls man sich mal vertippt hat:
1 | /* Kommandozeile hereinholen */
|
2 | void Talk (word wo) |
3 | { char c; |
4 | |
5 | if (RxAvail(wo)) |
6 | { c = GetChar(wo); |
7 | if (c==10) return; |
8 | if (c==13) |
9 | { CRLF_Out(wo); |
10 | DoCommand (Kommandozeile, wo); |
11 | InitCmd(wo); |
12 | }
|
13 | else
|
14 | { if (kzi>=(sizeof(Kommandozeile)-1)) return; |
15 | if (c==8) |
16 | { Char_Out(8, wo); |
17 | Char_Out(' ', wo); |
18 | Char_Out(8, wo); |
19 | if (kzi) --kzi; |
20 | Kommandozeile[kzi]=0; |
21 | }
|
22 | else
|
23 | { if (c<' ') |
24 | { Char_Out('^', wo); |
25 | Char_Out(c+0x40, wo); |
26 | Kommandozeile[kzi++] = c; |
27 | Kommandozeile[kzi] = 0; |
28 | return; |
29 | }
|
30 | Char_Out(c, wo); |
31 | Kommandozeile[kzi++] = c; |
32 | Kommandozeile[kzi] = 0; |
33 | }
|
34 | }
|
35 | }
|
36 | }
|
Das stammt aus einem uralten Beispiel, was ich vor etwa 5 Jhren hier mal gepostet hatte. W.S.
Ich lasse hirmit die Frage Fallen und melde mich sobalt ich einen Workeround gefunden habe. Zu deinen Code: Es ist mir auch im klaren wie ich das selber Implementieren kann. Jedoch würde ich es anderst machen da das sauberer geht. Nachdem es in der libary eine funktion giebt die einen String einlesen kann. (im hintergrund zeichen für zeichen und über Pointer.) Mir ist auch im klaren das die länge einen Rolle in einen char array hat jedoch nicht für eine saubere Funktion die würde die länge selber ermitteln. Aber wie gesagt warum etwas selber impl wenn es eine Bibliothek giebt und ich kann es mir fast nicht vorstellen das es keine giebt. Aber ja ansonsten werde ich es über eine Weilshleife Zeichen für Zeichen lesen und in einen String schreiben.
Hallo, welche Lib soll das sein die dir deine individuelle Zeichenverarbeitungsfunktion anbietet? Das Arduino Framework hält für jede Serielle einen Ringbuffer bereit worin üblicherweise 63 Zeichen reinpassen. Darauf kann man mit read/write zugreifen. Die Zeichen muss man auslesen und verarbeiten. Dafür verwendet man üblicherweise einen eigenen char Buffer abgestimmt auf seine Aufgabe. Also auslesen und in eigenen Buffer schreiben. Wenn Übertragung fertig, Daten vom eigenen Buffer verarbeiten. Wenn fertig auf neue Daten warten und das Spiel beginnt von vorn.
W.S. schrieb: > Ich glaub, ich krieg bei sowas Pickel. Die bekommen wir hier auch, wenn Du weiterhin komplett ingnorierst, daß Arduinos in C++ programmiert werden und String eine Klasse ist, die einiges an Dir völlig unbekannter Funktionalität enthält.
René schrieb: > Workeround Oder vielleicht ein Würgaround? Ein Workaround dient dazu, einen Fehler zu umgehen. Wenn z.B. dein PC abstürzt wenn du 100·2 rechnest, dann könnte ein Workaround sein, stattdessen 100+100 zu rechnen. Dein NINA B312 ist offenbar ein Wifi/Bluetooth Modem, dass mittels AT Kommandos konfiguriert wird. Das hat mit Byte Arrays erst mal wenig zu tun. AT Kommandos sind Strings. Nach dem Verbindungsaufbau überträgt es alle Daten 1:1 so wie du sie seriell ausgibt. Das ist der Moment, wo dein eigenes Übertragungsprotokoll wichtig wird. Du musst dir ein Übertragungsprotokoll ausdenken. Es ist leicht, über einen Seriellen Port eine Folge von Bytes zu senden. Aber woher soll der Empfänger wissen, wo genau diese Folge von Bytes beginnt und wo sie endet? Darüber musst du dir Gedanken machen. Du sendest ja letztendlich nicht nur einmal diese eine Folge von Bytes und beendest dann das Programm. Außerdem können Übertragungsstörungen auftreten, von denen sich der Empfänger sinnvollerweise erholen können muss. Es wäre schlecht, wenn er nach einem verlorenen oder falschen Byte für immer nur noch Quatsch macht. Ein einfacher Klassiker ist, die Daten mit Serial.printf() in Text umzuwandeln, zu gruppieren und Zeilenweise zu senden. Zum Beispiel: Temperaturen:20;19,5;20;21<Zeilenumbruch> Der Empfänger kann am Zeilenumbruch das Ende eines Datenpaketes erkennen. Die Arduino Funktion Serial.readString() ist dazu gut geeignet, wenn du vorher einen Timeout festlegst. Anschließend kannst du die Zeile mit String Funktionen in ihre Bestandteile zerlegen.
Falls es einen interessiert.... Hier mal ein primitiver Bufferfüller/Parser in Arduino.
1 | #include <Streaming.h> // die Lib findest du selber ;-) |
2 | Print &cout = Serial; // cout Emulation für "Arme" |
3 | |
4 | |
5 | String buffer; |
6 | |
7 | void verarbeitung(String &str) |
8 | {
|
9 | // hier tuwas mit str
|
10 | cout << str << endl; |
11 | }
|
12 | |
13 | void serialEvent() |
14 | {
|
15 | char c = Serial.read(); |
16 | switch(c) |
17 | {
|
18 | case '\n': /* fall through */ |
19 | case '\r': if(buffer.length()) verarbeitung(buffer); |
20 | buffer = ""; |
21 | break; |
22 | default: buffer += c; |
23 | }
|
24 | }
|
25 | |
26 | void setup() |
27 | {
|
28 | buffer.reserve(50); // buffer mindestgröße |
29 | Serial.begin(9600); |
30 | cout << F("Start: ") << F(__FILE__) << endl; |
31 | }
|
32 | |
33 | void loop() {} |
Émile schrieb: > Axel S. schrieb: >> Und ein old school "String" in C ist ein >> Array derselben bzw. ein Pointer darauf. > > Ein C-String ist ein Array aus char, nicht ein Array aus unsigned char. Albern! > Ob char selbst wiederum signed oder unsigned ist, ist nicht festgelegt Eben. Es spielt für die Anwendung des Typs als Zeichen auch gar keine Rolle. Signedness ist nur im Kontext von Arithmetik relevant. Oder für Vergleiche, die über die Unterscheidung gleich/ungleich hinaus gehen. Aber das ist ja überhaupt nicht der Fall. Du hast nur eine verk*ckte Funktion, die darauf besteht, daß "ihre" Strings ein Array von uint8_t sein müßten. Wenn du daran hängst, dann caste halt. Aber wenn du schon eine Programmiersprache (C++) mit richtigen Strings verwenden willst, dann ist das sicherlich der falsche Weg. Millionen von C-Programmierern haben ebensoviele Bugs in ihren C-Programmen eingebaut, bloß weil die Sprache über keinen Typ für Strings verfügt, sondern statt dessen char* als solche mißbraucht. Da sollte man nicht auf Teufel komm raus dran festhalten. Sondern alte Zöpfe auch mal abschneiden.
:
Bearbeitet durch User
René schrieb: > Nachdem es in der libary eine funktion giebt die einen String einlesen > kann. Solch eine Funktion gibt es schlichtweg nicht, da es keinen String als Protokoll gibt. Es gibt Funktionen, die Bytes über die UART senden oder empfangen. Diese Bytes können Binärdaten, Text oder sonstwas sein. Daher werden die Bytes nicht interpretiert, sondern nur in FIFOs gepuffert, falls die CPU noch anderes zu tun hat, damit keine Bytes verloren gehen. Du brauchst daher in jedem Fall noch ein Protokoll, das den Bytestrom zusammen setzt bzw. wieder interpretiert. Ein Timeout ist mit Abstand das schlechteste Protokoll. Ein sehr einfaches Protokoll ist eine Textzeile, d.h. ein Paket wird mit CR, LF oder beidem abgeschlossen. Du brauchst also eine Funktion, die die Bytes in ein Array sammelt und das CR,LF durch '\0' ersetzt. Fertig ist ein String, den man z.B. mit sscanf parsen kann. Als Fehlerbehandlung kann man noch ein Timeout aufsetzen, was dann die Verbindung als gestört meldet. Das Timeout ist aber nicht Bestandteil des Protokolls. Daneben gibt es noch haufenweise Binärprotokolle.
das Protokoll ist gegeben, AT Kommandos mit CR+LF als Endekennung. Damit reicht das eingebaute Serial.readStringUntil('\n'). Und durch das Timeout kann auch ein Fehler durch unvollständige Sendungen abgefangen werden. Komplizierter wird es nur wenn das Modem auf Daten umschalten kann und dann auch ein LF im Datenstrom vorkommen kann. Der TO muss nur nachsehen ob für die gewünschte Schnittstelle eine Serial_n im core als globales Objekt angelegt wurde, sonst kann man das mit einer Instanz von HardwareSerial selber machen.
J. S. schrieb: > Damit > reicht das eingebaute Serial.readStringUntil('\n'). Ich mag solche blockierenden Funktion nicht, sondern programmiere sowas nebenläufig. D.h. die Funktion zum Sammeln der Bytes wird zyklisch aufgerufen. Und erst, wenn die Funktion eine Zeile erkannt hat, wird diese dem Parser übergeben. Die CPU kann derweil andere Sachen ausführen und muß nicht an dieser Stelle Däumchen drehen. Als Master kann man ein Timeout aufsetzen, um eine Störung zu erkennen. Der Slave hingegen braucht kein Timeout. Er wartet geduldig (jahrelang), bis ihm der Master was sagt und antwortet dann. Warten heißt, der Slave macht alles andere, was er tun soll.
deshalb benutze ich Arduino auch nicht, komplexere Anwendungen machen mit dem simplen API keinen Spaß. Aber die Frage war ja wie es damit geht. Bei Targets mit STM kann man auf die asynchronen HAL Funktionen zugreifen, verliert dann aber die Portabilität die der TO auch haben wollte. Dann gäbe es noch OS wie NuttX oder ChibiOS, in die muss man sich aber auch erstmal einarbeiten und man muss hoffen das seine Plattform unterstützt wird und die Implementierung auch funktioniert.
René hat bisher noch nicht gesagt, welchen konkreten Arduino er überhaupt benutzt.
J. S. schrieb: > deshalb benutze ich Arduino auch nicht, Das ist dir ungenommen! Deine Argumentation ist allerdings defekt. J. S. schrieb: > komplexere Anwendungen machen > mit dem simplen API keinen Spaß. Aha... Die Ganze Welt des C++, C und ASM steht dir doch damit offen. Niemand zwingt einen, sich auf das Arduino Framework zu beschränken. Das sind selbst auferlegte, willkürliche, Grenzen im Kopf. Darum sind sie auch nicht als Argument gegen Arduino gültig. EAF schrieb: > Hier mal ein primitiver Bufferfüller/Parser in Arduino. Das ist "fast" so ein Datansammler, wie von Peda beschrieben. Sammelt die Daten nebenläufig. Einen Timeout hat es allerdings (noch) nicht.
Peter D. schrieb: > René hat bisher noch nicht gesagt, welchen konkreten Arduino er > überhaupt benutzt. Mein Vorschlag funktioniert mit allen Arduinos und Arduino fähiger Hardware, welcher HardwareSerial (uart) nutzt. Alle! Von 8 Bit über 32 Bit bis 64 Bit Kesselchen. Egal welcher µC Type/Hersteller.
EAF schrieb: > Das sind selbst auferlegte, willkürliche, Grenzen im Kopf. Nein, die Portabilität ist die Grenze. Es ist sicher vieles machbar, aber dann sehr aufwändig wenn es für mehrere Platformen implementiert sein soll. Wenn man die Eigenheiten der STM nutzt, dann läuft es nicht auf Xtensa und umgekehrt. Das ist immer ein Abwägen ob es schnell funktionieren soll oder ob es möglichst plattformunabhängig laufen soll. In Serial und den darunterliegenden Streams sehe ich kein asynchrones API für den Benutzer. Aber vielleicht übersehe ich das ja auch nur. edit: ok, serialEvent() ist ein Ansatz. EAF schrieb: > Mein Vorschlag funktioniert mit allen Arduinos und Arduino fähiger > Hardware, welcher HardwareSerial (uart) nutzt. > Alle! Dagegen sagt die Doku:
1 | Notes and Warnings |
2 | serialEvent() doesn’t work on the Leonardo, Micro, or Yún. |
3 | serialEvent() and serialEvent1() don’t work on the Arduino SAMD Boards |
4 | serialEvent(), serialEvent1(), serialEvent2(), and serialEvent3() don’t work on the Arduino Due. |
also nichtmal die Arduino Hardware ist da konsistent.
:
Bearbeitet durch User
Peter D. schrieb: > René hat bisher noch nicht gesagt, welchen konkreten Arduino er > überhaupt benutzt. doch: René schrieb: > Ich versuche eine serielle Kommunikation zum NINA B312 herzustellen und > verwende als Enticklungsboard für meinen Brototypen Mikroe BLE 4 click. Ich kenne die allerdings nicht, hatte erst angenommen das wäre ein anderer Click 4 mit STM32F7.
:
Bearbeitet durch User
J. S. schrieb: > Dagegen sagt die Doku: > Notes and Warnings > serialEvent() doesn’t work on the Leonardo, Micro, or Yún. > serialEvent() and serialEvent1() don’t work on the Arduino SAMD Boards > serialEvent(), serialEvent1(), serialEvent2(), and serialEvent3() don’t > work on the Arduino Due. > > also nichtmal die Arduino Hardware ist da konsistent. Dann hast du mich nicht verstanden! Oder du ziehst Argumente an den Haaren herbei, weil du recht behalten willst, unter Aufgabe jeglicher Ehre. Ich sprach eindeutig und klar von HardwareSerial! Die von dir aufgeführten verwenden Serial über USB auf dem µC. Übrigens, der TO möchte nicht Serial über nativ USB nutzen. Aber selbst dann ist ein Nachrüsten von serialEvent() nun wirklich nicht das Problem. Eine einzige und dann noch einfache Zeile in loop(). Damit bist du überfordert? Das kann ich mir nicht vorstellen! J. S. schrieb: > Nein, die Portabilität ist die Grenze. Es ist sicher vieles machbar, > aber dann sehr aufwändig wenn es für mehrere Platformen implementiert > sein soll. Wenn man die Eigenheiten der STM nutzt, dann läuft es nicht > auf Xtensa und umgekehrt. Das Problem dass unterschiedliche Hardware eben unterschiedlich ist, das wird man wohl nie aus der Welt schaffen können. Deine STM32 HAL ist auch nur eine API, und die läuft auch nicht auf einem ESP o.ä., wie du schon ganz korrekt bemerkt hast. Da ist das Arduino Framework schon deutlich universeller. Eine API zu entwickeln, welche ALLE Unterschiede der verschiedensten µC abdeckt ist schlicht unmöglich, aus meiner Sicht. Der Versuch ist zum scheitern verurteilt. Und damit ist es immer recht aufwendig portablen Code zu erzeugen. Ob mit, oder ohne Arduino.
Serial ist eine Instanz von HardwareSerial. Aber mit solchen Streitsüchtigen diskutiere ich nicht weiter. Falk hatte schon Recht.
J. S. schrieb: > Serial ist eine Instanz von HardwareSerial. Nein, nicht immer, nur wenn die/eine UART in Hardware genutzt wird. Für µC mit USB Interface sieht das anders aus. J. S. schrieb: > Streitsüchtigen Streitsüchtig? Wie kommst du darauf? Möchtest du die Unwahrheit hier unwidersprochen herausblähen wollen?
Eine Nachrüstung:
1 | // serialEvent() Nachrüstung für ATMega32U4 USB CDC Serial (z.B. Leonardo/Micro)
|
2 | // Entspricht weitestgehend der Implementierung wie bei HardwareSerial
|
3 | |
4 | |
5 | void serialEvent() __attribute__((weak)); |
6 | // void serialEvent(){} // implementieren, wenn gewünscht
|
7 | |
8 | void setup() |
9 | {
|
10 | Serial.begin(9600); |
11 | }
|
12 | |
13 | void loop() |
14 | {
|
15 | if(serialEvent && Serial && Serial.available()) serialEvent(); |
16 | }
|
Auf die "weiche" Deklaration kann natürlich verzichtet werden, wenn serialEvent wirklich implementiert wird.
Émile schrieb: > Die bekommen wir hier auch, wenn Du weiterhin komplett ingnorierst, daß > Arduinos in C++ programmiert werden und String eine Klasse ist, die > einiges an Dir völlig unbekannter Funktionalität enthält. Was geht einen Treiber für einen UART eine C++ Klasse an? Natürlich garnichts. Die Übertragung erfolgt zeichenweise und wenn man mehrere Zeichen empfangen und auswerten will, dann muß man eben SELBER so viele sammeln, bis es einem reicht und anderweitige Kriterien (Protokoll) erfüllt sind. Es war noch nie die Aufgabe eines Treibers, jemandem seine eigentlichen Arbeiten in den Algorithmen zu erledigen, sondern der Treiber soll bloß für einen geordneten Transport der betreffenden Daten sorgen. Und das eigentlich ganz ohne Bezug auf irgendeine spezielle Programmiersprache. Lerne du mal lieber, strukturiert zu denken, anstatt nur als vermeintliches Totschlag-Argument "C++" zu sagen. Und wenn man meint, daß es allemal besser sei, für sein spezielles Vorhaben eine Quelle zum Kopieren zu suchen anstatt das, was das Spezielle am Vorhaben ausmacht, selbst zu schreiben, dann ist das eine falsche Ansicht und nur eine Art anzufragen "wer macht mir für lau meine Arbeit ?". W.S.
W.S. schrieb: > Was geht einen Treiber für einen UART eine C++ Klasse an? Natürlich > garnichts Deine Ahnungslosigkeit ist wirklich grenzenlos.
J. S. schrieb: > edit: > ok, serialEvent() ist ein Ansatz. EAF schrieb: > Ich sprach eindeutig und klar von HardwareSerial! Ihr beiden streitet über des Kaisers Bart. Mal ne Frage: Was soll eigentlich "SerialEvent()" oder gar "HardwareSerial"? Wichtig für die Portabilität ist eigentlich, daß das Interface von Treibern dem Problem angepaßt ist und nicht einem bestimmten Chip oder Hersteller. Und ob nun der Zeichen-Verkehr über einen echten UART oder eine USB-Verbindung oder per reitendem Boten erfolgt, ist der aufrufenden Firmware eigentlich egal. Für die Sendeseite sollte lediglich eine Funktion zum Entgegennehmen der Daten, zum Abfragen, ob der Kanal noch etwas aufnehmen kann (der Transport dauert ja auch) und zum Abfragen, ob bereits alles gesendet ist bereitstehen und für die Empfangsseite wären es eine Funktion zum Ermitteln, ob etwas da ist, eine zum Abholen dessen was da gekommen ist und ggf. noch eine, die angibt, ob es einen Empfangsfehler gegeben hat. Da ist eigentlich kein Platz für 'SerialEvents' und 'HardwareSerial' oder ähnliches Zeug, das bloß irgend eine Bindung der Benutzer an die herstellende Firma bewirken soll. W.S.
W.S. schrieb: > Da ist eigentlich kein Platz für 'SerialEvents' und 'HardwareSerial' > oder ähnliches Zeug, du schriebst mal in einem anderen Thread das du ein C++ Buch hast. Das sollte nicht dazu dienen den Monitor etwas höher zu stellen, da muss man mal reingucken. W.S. schrieb: > das bloß irgend eine Bindung der Benutzer an die > herstellende Firma bewirken soll. Paranoia. In C++ hat eine Klasse ein Interface und eine Implementierung. HardwareSerial hat ein Inteface, einen Vertrag wie etwas aussehen soll. Die Implementierung kann und sieht für verschiedene Controller unterschiedlich aus. Also Perfekt auch für die Implementierung von Treibern. serialEvent ist ein Callback, auch sowas macht Sinn. Für den Rest bemühe dein Buch und versuche mal dich einen mm weiterzubilden.
W.S. schrieb: > lieber, strukturiert zu denken, anstatt nur als > vermeintliches Totschlag-Argument "C++" Ohne jetzt den C++ Priester spielen zu wollen, aber C++ Jünger denken anders, als C Fans. Alleine schon die OOP führt dazu, dass sich andere Denkstrukturen einstellen. Die Prozedurale Denke, oder auch das hangeln an KontrollFlussDiagrammen, hindert oft mehr, als es nützlich ist.
W.S. schrieb: > Ihr beiden streitet über des Kaisers Bart. Wir sind schon fertig mit miteinander streiten, jetzt verbrüdern wir uns gerade und machen dich fertig. ;-)
Na ganz so weit würde ich da in beiden Punkten nicht gehen, aber bei solchen komischen Ansichten kriege ich Pickel. In C++ kann man Dinge unterschiedlich lösen und da darf man unterschiedlicher Meinung sein.
J. S. schrieb: > In C++ kann man Dinge unterschiedlich lösen Waren es 4 oder 5 Paradigmen, die C++ unterstützt? Und C nur ein einzelnes?
Hat jemand von euch schon einmal Firmata zur Kommunikation benutzt? https://docs.arduino.cc/hacking/software/FirmataLibrary
W.S. schrieb: > Was geht einen Treiber für einen UART eine C++ Klasse an? Ich sehe keinen Grund, warum man Treiber nicht in C++ programmieren soll. Sogar der Linux Kernel erlaubt inzwischen Treiber (Module) in C++. https://olegkutkov.me/2019/11/10/cpp-in-linux-kernel/
EAF schrieb: > Wir sind schon fertig mit miteinander streiten, jetzt verbrüdern wir uns > gerade und machen dich fertig. Na grandios. Dann macht mal - aber vergeßt darüber nicht, daß es hier einen TO gibt, der mit seinem Latein am Ende ist, weil ihm keiner seine Zeichen einsammelt und nirgendwo etwas passendes zum Kopieren sich findet. Steve van de Grens schrieb: > W.S. schrieb: >> Was geht einen Treiber für einen UART eine C++ Klasse an? > > Ich sehe keinen Grund, warum man Treiber nicht in C++ programmieren > soll. Das ist dir auch völlig freigestellt. Programmiere deine Treiber in einer Programmiersprache deiner Wahl. Aber eines bleibt: deinem selbstprogrammierten Treiber sollte es egal sein, ob jemand, der ihn benutzt und empfangene Zeichen geliefert haben will, die gleiche oder eine andere Programmiesprache benutzt. Und laß dir genau deshalb das Schicksal von Symbian eine Warnung sein. W.S.
W.S. schrieb: > aber vergeßt darüber nicht, daß es hier > einen TO gibt, der mit seinem Latein am Ende ist, weil ihm keiner seine > Zeichen einsammelt und nirgendwo etwas passendes zum Kopieren sich > findet. Wenn du nicht erkennst, dass serialEvent() nützlich sein kann, dann kann man auch nicht von dir erwarten, dass du ein Mundgerecht serviertes Beispiel als solches erkennst. Wenn du irgend was nicht verstehst, wäre es im ersten Schritt für dich wichtig zu erkennen dass du irgendwas nicht verstehst. In einem zweiten Schritt könntest du dann dich kundig machen, z.B. Fragen stellen. Aber: Offensichtlich urteilst du lieber über Dinge und Menschen, ohne die Hintergründe zu erfassen. Das ist sehr schade, wie ich finde.
Ich erläutere noch mal mein Problem. Sende ich ein normalen String (char Array) oder ein String-Objekt mit der Funktion Serial1.println() oder Serial1.write() dann reagiert mein BLE-Modul nicht. Sende ich jedoch Serial1.write((uint8_t*)"AT+UBTLN=\"u-blox NINA René\"", strlen("AT+UBTLN=\"u-blox NINA René\"")); funktioniert es. Beim Lesen bekomme ich mit Serial1.readBytes() oder Serial1.readString() nur siehe Bild. Dies soll Conn heißen. Womöglich bin ich dumm, aber wie sollte ich es anterst machen. Ach ja verwende ich einen anderen Mikrochip und arbeite ich mit der HallUart bib funktioniert es. Bitte nicht nochmals mir erklären, was ein Ringbuffer, wie ein String Objekt aufgebaut ist und wie ein char Array bzw. ein String in C aufgebaut ist. Ich habe in reinen C auf einem Linux System schon einige Projekte umgesetzt. Also Variablentypen und co kann ich unterscheiden und das Verständnis, wie eine serielle Kommunikation aufgebaut ist, habe ich auch. C++ ist jedoch etwas neuer für mich (muss ich zugeben). Ich möchte keinen 50 Zeilen Code schreiben und im reinen C bleiben, sondern möchte die Funktionalitäten, welche mir C++ oder Ardoino-LIB zur Verfügung stellt, stellt nutzen. Würde mich Freuen. LG. René
EAF schrieb: > Wenn du irgend was nicht verstehst, wäre es im ersten Schritt für dich > wichtig zu erkennen dass du irgendwas nicht verstehst. > In einem zweiten Schritt könntest du dann dich kundig machen, z.B. > Fragen stellen. Die großen drei Gruppen: 1. Dinge, von denen wir wissen, dass wir sie wissen. 2. Dinge, von denen wir wissen, das wir sie nicht wissen. 3. Dinge, von denen wir nicht wissen, dass wir sie nicht wissen. Du hoffst auf 2. aber allzuoft haben wir hier im Forum 3. aufploppen. ;)
Ok Ich gebe es auf. Ich schreibe es auf basic c noch in eine sauber Funkt und erledigt. Ich glaubte, ich hätte immer wieder darauf aufmerksam gemacht. Das ich weiß wie es grundsätzlich funktioniert und ich nicht weiß wie ich es am besten in der Atrduino umgebung umsetzen kann. Ohne dies hartcoded zu implementieren. Dud mir leid dann möchte ich mich für die Fragestellung entschuldigen: Da es mir nicht im klaren ist wie ich es anderst Formulieren sollte. Lasse ich es. Möchte euch ja nicht verergern. Vielen lieben Dank. Liebe Grüße Ramsauer René
:
Bearbeitet durch User
fehlt da nicht beim Senden das CR+LF im string? Also "\r\n" ist im HAL Beispiel drin, hier nicht. Und beim Empfang sieht es nach falscher Schnittstellengeschwindigkeit aus. Die muss für Serial1 dann auch mit begin(speed) eingestellt werden.
René schrieb: > Sende ich ein normalen String (char Array) oder ein String-Objekt mit > der Funktion Serial1.println() oder Serial1.write() dann reagiert mein > BLE-Modul nicht. > aber wie sollte ich es anterst machen. Zeige erst mal diesen Source code, dann können wir Verbesserungsvorschläge dazu machen.
René schrieb: > Ich erläutere noch mal mein Problem. Was heißt hier noch mal? Das ist das allererste Mal. > Sende ich ein normalen String (char Array) oder ein String-Objekt mit > der Funktion Serial1.println() oder Serial1.write() dann reagiert mein > BLE-Modul nicht. Sende ich jedoch > Serial1.write((uint8_t*)"AT+UBTLN=\"u-blox NINA René\"", > strlen("AT+UBTLN=\"u-blox NINA René\"")); funktioniert es. Dann würde ich als erstes einen Logikanalyzer an den UART klemmen und gucken, was da gesendet wird. Notfalls den seriellen Port vom PC. Sonst ist das bloß blindes Stochern im Nebel. Oh, und zuallererst würde ich das "é" durch ein "e" ersetzen.
Nun habe ich es gefunden: Das Problem ist das die AruinoIDE je nach Board eine eigene Seriell bzw. IO Konfiguration mit gibt. Da ich einen zweiten Mikrocontroller am PC angesteckt hatte. Hat die IDE zwar oben Ardoino nano angezeigt, jedoch die Falsche config in der Ardoino ide geladen. Nun war meine zweite serielle Schnittstelle als USB definiert. Fahrzit TI-Mikrochip am PC gefällt der IDE nicht. Dies ist natürlich im reinen C Code nicht aufgefallen, da ich dort nicht auf die Bibliothek zugegriffen habe. So dumm hätte ich gleich sehen können. Ich schaue nochmal nach, wie der geheißen hat. Sende das dann Arduino Support. (Muss das Gehäuse meines Reglers zerlegen und gebe euch danach die Info welcher yC es war.) Danke. Nochmals wäre fast verzweifelt. Danke an den letzten Kommentar, das hat mich dazu veranlasst nochmals in die lib zu schauen. Sorry, falls ich einige Tippfehler habe. Bin jetzt einfach nur noch müde. Und Sorry das ich manchen nicht geglaubt habe. Kaum ist die Richtige Config drinnen, macht er alles richtig(TI abgesteckt und Arduino neu angesteckt). Da habe ich mich geirrt und am falschen Platz nach Lösungen gesucht. Die Seriel libarry convertiert den String sowiso von selber in einen unsigned char. Das war wirklich dumm von mir.
:
Bearbeitet durch User
Ich verstehe dich immer noch nicht.... Kaum. Aber schön, dass es jetzt funktioniert.
Die ArduinoIDE hat die falsche Arduino.h geladen. Deswegen war bei Serriel1 standartmäßig USB configuriert. Dies war wegen einen zweiten yC welcher auf meinen PC angeschlossen war. Ein TexasInstrument yC. Ein BUG der IDE. Ales was ich vorher gefragt habe ist in der Serial.cpp implementiert.
:
Bearbeitet durch User
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.