Arduino – Serielle Kommunikation

Auf jedem Arduino-Board stehen (je nach Typ) ein oder mehrere serielle Ports (UART oder USART) zur Verfügung. Die serielle Schnittstelle ermöglicht die Kommunikation zwischen dem Arduino-Board und geeigneten Geräten.

Beachten wir, dass die serielle Kommunikation auf dem Arduino-Board TTL-Logikpegel an den TX/RX-Pins verwendet, die je nach Board 5 V oder 3,3 V betragen können. Wenn das Gerät, das wir verbinden möchten, mit der gleichen Spannung arbeitet, können wir sie direkt miteinander verbinden. Im Bild unten ist der Arduino UNO mit einem HC-05 Bluetooth-Modul verbunden. Da beide Platinen mit 5V Spannung arbeiten, können wir sie direkt anschließen.

Serielle Arduino-Port-Verbindung

Wenn die Spannung der Geräte nicht gleich ist, muss eine Pegelwandler verwendet werden. Andernfalls kann das Arduino-Board oder das angeschlossene Gerät beschädigt werden. Die folgende Abbildung zeigt die serielle Verbindung des Arduino UNO und eines ESP8266-01 Moduls. Die beiden Platinen arbeiten mit unterschiedlichen Spannungen, dieses Problem wird durch die Bidirektionaler Pegelwandler gelöst.

Arduino Serielle-Port Verbindung mit Pegelwandler

Arduino Uno-, Nano- und Mega-Boards haben einen USB-Serial-Konverter, sie verwenden die Pins 0 und 1, um mit dem Computer zu kommunizieren.

Arduino Mini-Boards haben kein USB-Serial-Gateway an Bord, also brauchen wir ein solches Gerät, um mit dem Computer zu kommunizieren. Verbinden wir den TX-Pin des Arduino-Boards mit dem RX-Pin des USB-Serial-Konverters, dann den Arduino RX mit dem TX-Pin des USB-Serial-Konverters und verbinden wir schließlich die GND-Pins.

Arduino mini pro - FTDI232 mit USB-Serial-Konverter

Der Arduino Mega hat insgesamt 4 serielle Ports. Der erste serielle Port ist mit dem integrierten USB-Seriell-Konverter verbunden. Um die zusätzlichen seriellen Anschlüsse für die Kommunikation mit unsere Computer zu verwenden, benötigen wir einen zusätzlichen USB-Seriell-Adapter.

In der folgenden Tabelle können wir sehen, auf welchen Pins sich bei einigen Arduino-Boards die serielle Schnittstelle befindet.

Arduino-BoardsSerialSerial1Serial2Serial3
Uno, Nano, Mini0(RX), 1(TX)
Mega0(RX), 1(TX)19(RX), 18(TX)17 (RX), 16 (TX)15 (RX), 14 (TX)
Leonardo, Mikro, Yun0(RX), 1(TX)
Uno WLAN Rev.2An USB angeschlossen0(RX), 1(TX)Verbunden mit Nina
MKR-Boards13 (RX), 14 (TX)
ZeroVerbunden mit dem Programmierport0(RX), 1(TX)
Due0(RX), 1(TX)19(RX), 18(TX)17 (RX), 16 (TX)15 (RX), 14 (TX)
1010(RX), 1(TX)
Pinbelegung der seriellen Schnittstelle von Arduino-Boards

Bei Uno, Nano, Mini und Mega werden die Pins 0 und 1 zur Kommunikation mit dem Computer verwendet. Diese Pins können als digitale Ausgänge und Eingänge verwendet werden, wenn die serielle Schnittstelle nicht benötigt wird. Wenn wir etwas an diese Pins anschließen und die serielle Schnittstelle verwenden möchten, kann dies die Kommunikation stören und zu erfolglosen Programm-Uploads auf das Arduino-Board führen.

Diese können erforderlich sein zum üben:

Serielle Kommunikation, der Softwareteil

Mal sehen, wie wir die serielle Kommunikation auf dem Arduino-Board zum Laufen bringen können. Für die Verwendung der seriellen Kommunikation ist keine zusätzliche Bibliothek erforderlich, die Arduino IDE enthält die erforderlichen Funktionen.

Die erste wichtigste ist die Funktion Serial.begin(Baud) legt die Datenrate für die serielle Datenübertragung fest. Der Baudwert muss in Bits pro Sekunde angegeben werden. Dies muss in der Funktion setup() angegeben werden.

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  
}

Um mit dem Arduino IDE Serial Monitor zu kommunizieren, wählen wir eine Baudraten im Dropdown-Menü in der unteren rechten Ecke des Bildschirms aus.

​​Baudrateneinstellung für Arduino Serial Monitor
​​Baudrateneinstellung für Arduino Serial Monitor

Serial.begin(Baud, Konfiguration); Das optionale zweite Argument konfiguriert die Daten-, Paritäts- und Stoppbits. Der Standardwert ist 8 Datenbits, keine Parität und ein Stoppbit.

void setup()
{
  Serial.begin(9600, SERIAL_8N1);   // Standardwert
}

void loop()
{
  
}

Wählen wir aus den folgenden gültigen Werten:

Keine Parität:

SERIAL_5N1
SERIAL_6N1
SERIAL_7N1
SERIAL_8N1
SERIAL_5N2
SERIAL_6N2
SERIAL_7N2
SERIAL_8N2

Gerade Parität:

SERIAL_5E1
SERIAL_6E1
SERIAL_7E1
SERIAL_8E1
SERIAL_5E2
SERIAL_6E2
SERIAL_7E2
SERIAL_8E2

Ungerade Parität:

SERIAL_5O1
SERIAL_6O1
SERIAL_7O1
SERIAL_8O1
SERIAL_5O2
SERIAL_6O2
SERIAL_7O2
SERIAL_8O2

Zurück zum Inhaltsverzeichnis.

Die Funktion Serial.end() deaktiviert die serielle Kommunikation und gibt die RX- und TX-Pins frei, damit sie als Ausgänge und Eingänge verwendet werden können. Wenn wir wieder die serielle Kommunikation nutzen wollen, müssen wir die Funktion Serial.begin() aufrufen .

Lass es uns versuchen:

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  Serial.println("1. String");
  Serial.end();

  pinMode(0, OUTPUT);
  digitalWrite(0, HIGH);
  delay(500);
  digitalWrite(0, LOW);

  Serial.begin(9600);
  Serial.println("2. String");
  delay(1000);
}

Zurück zum Inhaltsverzeichnis.

Serial.flush() wartet darauf, dass ausgehende serielle Daten abgeschlossen werden. In den meisten Fällen ist ein serieller Übertragungspuffer eine gute Sache, er verhindert, dass das Arduino-Programm auf eine serielle Übertragung wartet. Es kann aber vorkommen, dass Sie im Arduino-Programm auf das Ende der seriellen Datenübertragung warten müssen. Dabei hilft die Funktion Serial.flush().

Serial.println(F("Hallo Arduino"));
Serial.flush();

Zurück zum Inhaltsverzeichnis.

if(Serial) gibt true zurück, wenn der angegebene serielle Port einsatzbereit ist . Dies ist wichtig, wenn Karten mit nativem USB verwendet werden. Für Nicht-USB-CDC-Ports gilt dies immer.

void setup()
{
  Serial.begin(9600);
  while(!Serial)
  {
    // Wartet darauf, dass der serielle Port verbunden wird. 
    // Erforderlich für Karten mit nativem USB!
  }
}

void loop()
{
  
}

Zurück zum Inhaltsverzeichnis.

Serial.print() druckt die Daten als ASCII-Text an die serielle Schnittstelle.

Zahlen verwenden ASCII-Zeichen für jede Ziffer.

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  Serial.print(29);  // 29
  delay(1000);
}

Der zweite Parameter, der optional hinzugefügt werden kann, definiert das Format, im folgenden Code-Snippet können wir beispielsweise den Wert in verschiedenen Zahlensystemen drucken.

Serial.print(29, BIN);  // 11101

Serial.print(29, OCT);  // 35

Serial.print(29, DEC);  // 29

Serial.print(29, HEX);  // 1D

Gleitkommazahl werden standardmäßig mit zwei Dezimalstellen gedruckt.

Serial.print(1.23456);  // 1,23

Der optionale zweite Parameter gibt die Anzahl der Dezimalstellen an, die für Gleitkommazahlen verwendet werden sollen.

Serial.print(1.23456, 0);  // 1

Serial.print(1.23456, 1);  // 1,2

Serial.print(1.23456, 4);  // 1,2345

Bytes werden als einzelnes Zeichen gesendet.

Zeichen und Zeichenfolgen werden unverändert gesendet.

Serial.print('M');                 // M
Serial.print("myhomethings.eu")    // myhomethings.eu

Zurück zum Inhaltsverzeichnis.

Serial.println() funktioniert ähnlich wie Serial.print() , außer dass Serial.println() ein Wagenrücklaufzeichen (ASCII 13 oder ‚\r‘) zurückgibt und ein Zeilenumbruchzeichen (ASCII 10 oder ‚\ n‘) ergänzt wird .

Zurück zum Inhaltsverzeichnis.

Der Arduino Mega 2560 Mikrocontroller-Board

Arduino Mega 2560
Werbung – Arduino Mega 2560

Serial.write() Schreibt Binärdaten auf die serielle Schnittstelle. Die Daten werden als Byte oder Folge von Bytes gesendet. Um numerische Zeichen zu senden, verwenden wir die Funktion Serial.print() oder Serial.println().

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  Serial.write(65);     // ASCII 65 -> A
  Serial.write(66);     // B
  Serial.write(67);     // C
  Serial.write('\n');   // Zeilenumbruchzeichen 


  int bytesLength = Serial.write("myhomethings.eu\n");  
  //Druckt den String "myhomethings.eu" und gibt die Länge des Strings zurück
  
  Serial.println(bytesLength);
  // Um numerische Zeichen zu senden, verwenden wir die Funktion print() oder println().
  
  char buf[] = {'m','y','h','o','m','e','t','h','i','n','g','s','.','e','u','\n'};
  int len = 16;

  Serial.write(buf, len);   // Sendet die Anzahl der Bytes aus dem buf-Array

  Serial.write('\n');
  delay(1000);
}

Zurück zum Inhaltsverzeichnis.

Serial.availableForWrite() wird verwendet , um die Anzahl der Bytes zu erhalten, die in den seriellen Puffer geschrieben werden können, ohne den Schreibvorgang zu blockieren. Sehen wir uns ein Beispiel für seine Verwendung an.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

String myString = "Arduino s eriellen Puffer - myhomethings.eu";

void setup() 
{
  Serial.begin(9600);
  
  // Wir fragen die Größe des Puffers ab 
  // und wir schreiben auf die serielle Schnittstelle.
  Serial.print("TX-Puffergröße: ");
  Serial.println(Serial.availableForWrite());
}

void loop() 
{
  // wenn die Größe des Puffers größer als der String ist...
  if(Serial.availableForWrite() > myString.length()) 
  {

    // wir schreiben den String auf die serielle Schnittstelle
    Serial.println(myString);
  }
  delay(1000);
}

Zurück zum Inhaltsverzeichnis.

Serial.available() gibt die Anzahl der von der seriellen Schnittstelle gelesenen Bytes zurück, die bereits im seriellen Empfangspuffer gespeichert sind. Im folgenden Beispiel prüfen wir, ob der Empfangspuffer Daten enthält. Wenn der Empfangspuffer nicht leer ist, wird mit der Funktion Serial.read() gelesen, bis er leer ist.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0)
  {
    char myChar = Serial.read();
    Serial.print(myChar);
  }
}

Zurück zum Inhaltsverzeichnis.

Serial.read() liest Daten von der seriellen Schnittstelle. Sein Rückgabewert ist das erste Byte der eingehenden seriellen Daten oder -1, wenn keine weiteren Daten im seriellen Empfangspuffer vorhanden sind.

Zurück zum Inhaltsverzeichnis.

Serial.readBytes() liest Zeichen von der seriellen Schnittstelle in einen Puffer. Die Funktion wird beendet, wenn die angegebene Länge gelesen wurde oder wenn das Standard-Timeout von 1 Sekunde oder der in Serial.setTimeout() angegebene Wert überschritten wird . Serial.readBytes() gibt die Anzahl der Zeichen im Puffer zurück oder 0, wenn keine gültigen Daten gefunden werden.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char myBuff[64];
int len = sizeof(myBuff)-1;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0) 
  {
    size_t read = Serial.readBytes(myBuff, len);
    myBuff[read] = '\0';
    Serial.print(myBuff);
  }
}

Zurück zum Inhaltsverzeichnis.

Serial.readBytesUntil() liest Zeichen aus dem seriellen Puffer in ein Array. Die Funktion endet, wenn die angegebene Länge gelesen wurde, wenn ein Timeout eintritt oder wenn das beendende Zeichen gefunden wird.

char myBuff[64];
int len = sizeof(myBuff)-1;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0) 
  {
    size_t read = Serial.readBytesUntil('\n', myBuff, len);
    myBuff[read] = '\0';
    Serial.println(myBuff);
  }
}

Zurück zum Inhaltsverzeichnis.

Serial.readString() liest Zeichen aus dem seriellen Puffer in einen String. Bei einem Timeout stoppt die Funktion ggf. kann diese Zeit mit der Funktion Serial.setTimeout() gesetzt werden. Die Funktion Serial.readString() stoppt nicht, wenn die Daten Zeilenendezeichen enthalten. 

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Den Text bitte:");
  if(Serial.available() > 0) 
  {
    String myString = Serial.readString();
    myString.trim();
    if(myString != "")
    {
      Serial.print("Der eingegebene Text: ");
      Serial.println(myString);
      myString ="";
      Serial.println("Den Text bitte:");
    }
  }
}

Zurück zum Inhaltsverzeichnis.

Die Funktion Serial.readStringUntil () liest die Zeichen aus dem seriellen Puffer bis zum abschließenden Zeichen in einen String ein. Das abschließende Zeichen ist nicht im String enthalten. Bei Timeout stoppt die Funktion. Die Zeit kann mit der Funktion setTimeout() verschoben werden .

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char terminator = 't'; // abschließenden Zeichen

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Den Text bitte:");
  if(Serial.available() > 0) 
  {
    String myString = Serial.readStringUntil(terminator);
    myString.trim();
    if(myString != "")
    {
      Serial.print("Der eingegebene Text: ");
      Serial.println(myString);
      myString ="";
      Serial.println("Den Text bitte:");
    }
  }
}

Zurück zum Inhaltsverzeichnis.

Serial.find() liest Daten aus dem seriellen Puffer, bis es den „target“ parameter findet oder das Ende erreicht oder abläuft. Die Zeit kann mit der Funktion setTimeout() gesetzt werden. Die Funktion gibt true zurück, wenn das Ziel gefunden wird, andernfalls false.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char target[] ="hallo";

void setup()
{
  Serial.begin(9600);
  Serial.println("Den Text bitte:");
}

void loop()
{

  if(Serial.available() > 0) 
  {
    if (Serial.find(target))
    {
      Serial.println("Gefunden!");
    }
    else
    { 
      Serial.println("Leider nicht gefunden!"); 
    }
    Serial.println("Den Text bitte:");
  }
}

Optional kann ein zweiter „length“ parameter angegeben werden, der definiert, wie viele Zeichen ab dem „target“ gesucht werden sollen.

char target[] ="hallo";
size_t length = 3;

Serial.find(target, length)

Zurück zum Inhaltsverzeichnis.

Serial.findUntil() liest Daten aus dem seriellen Puffer, bis es den Parameter „target“ oder die abschließende Zeichenfolge „Terminal “ findet oder das Zeitlimit überschreitet. Die Zeit kann mit der Funktion setTimeout() gesetzt werden. Die Funktion gibt true zurück, wenn das Ziel gefunden wird, andernfalls false.

char target[] ="hallo";
char terminal[] = "abc";

Serial.findUntil(target, terminal);

Zurück zum Inhaltsverzeichnis.

Serial.parseInt() sucht nach der nächsten gültigen Ganzzahl in der eingehenden Zeichenfolgen . Bei Timeout stoppt die Funktion. Dabei können wir mit der Funktion setTimeout() helfen .

Wenn Serial.parseInt() nicht numerische Werte vor einer gültigen Ganzzahl findet, verwirft es diese und gibt die Ganzzahl zurück, wobei der Rest übrig bleibt. Wenn Serial.parseInt() keinen numerischen Wert findet, gibt es null zurück.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0) 
  {
    long myInt = Serial.parseInt();
    Serial.println(myInt);
  }
}

Die Funktion Serial.parseInt() kann auch mit optionalen Parametern aufgerufen werden.

Serial.parseInt()
Serial.parseInt(lookahead)
Serial.parseInt(lookahead, ignore)

Der erste optionale Parameter ist lookahead , Lookahead-Modus genannt. Es kann drei vordefinierte Werte haben.

SKIP_ALL: Alle Zeichen außer Ziffern und dem Minuszeichen werden bei der Suche nach einer ganzen Zahl im Datenstrom ignoriert. Dies ist der Standardmodus.

SKIP_NONE: Es wird nichts übersprungen. Wenn der erste Wert des seriellen Empfangspuffers keine Ziffer ist, wird 0 zurückgegeben.

SKIP_WHITESPACE: Nur Tabulatoren, Leerzeichen, Zeilenvorschübe und Wagenrücklaufzeichen werden übersprungen.

Der zweite optionale Parameter ist Ignorieren : Das angegebene Zeichen wird bei der Suche übersprungen. Dies kann nützlich sein, wenn es bekannte Zeichen gibt, die wir nicht als Trennzeichen in Zahlen verwenden möchten. Es kann unter anderem verwendet werden, um Dezimalpunkte oder Schrägstriche wegzulassen.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0) 
  {
    unsigned long myInt = Serial.parseInt(SKIP_NONE, ',');
    Serial.println(myInt);
  }
}

Zurück zum Inhaltsverzeichnis.

Serial.parseFloat() gibt die erste gültige Fließkommazahl aus dem seriellen Puffer zurück. Das erste Nicht-Gleitkommazeichen beendet die Funktion Serial.parseFloat(). Die Funktion stoppt auch bei einem Timeout. Dabei können wir mit der Funktion setTimeout() helfen .

Die Funktion Serial.parseFloat() kann auch mit optionalen Parametern aufgerufen werden.

Serial.parseFloat()
Serial.parseFloat(lookahead)
Serial.parseFloat(lookahead, ignore)

Der erste optionale Parameter ist lookahead , Lookahead-Modus genannt. Es kann drei vordefinierte Werte haben.

SKIP_ALL: Alle Zeichen außer Minuszeichen, Dezimalpunkt und Ziffern werden bei der Suche nach einer Fließkommazahl im Datenstrom ignoriert. Dies ist der Standardmodus.

SKIP_NONE: Nichts wird übersprungen und der Stream wird nicht berührt, es sei denn, das erste Wartezeichen ist gültig.

SKIP_WHITESPACE: Nur Tabulatoren, Leerzeichen, Zeilenvorschübe und Wagenrücklaufzeichen werden übersprungen.

Der zweite optionale Parameter ist Ignorieren : Das angegebene Zeichen wird bei der Suche übersprungen. Dies kann nützlich sein, wenn es bekannte Zeichen gibt, die wir nicht als Trennzeichen in Zahlen verwenden möchten.

Zurück zum Inhaltsverzeichnis.

Serial.setTimeout() setzt die maximale Zeit in Millisekunden, um auf serielle Daten zu warten. Der Standardwert ist 1000 ms.

long time = 800; // 800ms

void setup()
{
  Serial.begin(9600);
  Serial.setTimeout(time);
}
void loop()
{
  
}

Zurück zum Inhaltsverzeichnis.

Serial.peek() gibt den Dezimalwert des nächsten Bytes (Zeichens) eingehender serieller Daten zurück, ohne ihn aus dem internen seriellen Puffer zu entfernen. Das heißt, aufeinanderfolgende Aufrufe von Serial.peek() geben dasselbe Zeichen zurück wie der nächste Aufruf von Serial.read(). Mit Serial.peek() können Sie also das nächste Zeichen analysieren, ohne es zu lesen, um zu sehen, ob es relevant ist.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available() > 0) 
  {
    if(isDigit(Serial.peek()))
    {
      Serial.println("Es ist eine Zahl!");
      char myChar = Serial.read();
      Serial.println(myChar);
    }
    else
    {
      Serial.println("Es ist keine Zahl!");
      Serial.read();                   // dies löscht den Eingangspuffer
    }
  }
}

Zurück zum Inhaltsverzeichnis

Die Funktion serialEvent() wird automatisch am Ende von loop() aufgerufen, wenn sich serielle Daten im seriellen Puffer befinden. Das folgende Beispiel extrahiert die Zahlenzeichen aus dem seriellen Puffer.

/*****************************************/
/**       https://myhomethings.eu       **/
/*****************************************/

char myChar ="";
bool flag = false;

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  if(flag) 
  {
    Serial.println(myChar);
    myChar = "";
    flag = false;
  }
}

void serialEvent() 
{
  if(Serial.available() > 0) 
  {
    myChar = Serial.read();
    if(isDigit(myChar))
    {
      flag = true;
    }
  }
}

Zurück zum Inhaltsverzeichnis

AZDelivery-ATmega328 Mikrocontroller Board mit USB-Kabel
AZDelivery-ATmega328 Mikrocontroller Board mit USB-Kabel
Werbung