Sa. Okt 12th, 2024

Wird gerade bearbeitet….

Serielle Kommunikation ist eine der elementaren Kommunikationstechniken. Dabei geht es grundsätzlich darum, 1 Daten Bit pro Zeiteinheit sequentiellster von einem Rechner zu einem Anderen zu übertragen. Diese Form der Kommunikation basiert auf dem UART Protokoll (Universal Asynchronous Receiver-Transmitter).

Das UART-Protokoll ist eines der ältesten und zugleich zuverlässigsten seriellen Kommunikations-protokolle, das wir heute noch verwenden. Dieses Protokoll verwendet zwei Drähte, die als Tx (Senden) und Rx (Empfangen) bekannt sind, damit beide Komponenten kommunizieren können.

Um Daten zu übertragen, müssen sowohl der Sender als auch der Empfänger fünf gängigen Konfigurationen zustimmen:

Arbeitsprinzip beim Arduino

Im Arduino Uno sind zwei Pins; Pin 0 und Pin 1 sind für die serielle Kommunikation belegt. Diese Pins werden mit 3,3 Volt oder 5 Volt betrieben. Es wird daher nicht empfohlen, sie mit dem seriellen RS232-Anschluss zu verbinden, da dieser mit 12 Volt betrieben wird. Der eingehende Datenstrom wird von einem UART Chip auf dem Arduino in 8 Bit Pakete gebündelt und Byteweise in den Seriellen Datenpuffer (Serial Receive Buffer) abgelegt. Die ankommenden Daten-Bits werden in genau der Reihenfolge in der sie eingehen in den Buffer abgelegt. Der Buffer hat eine maximale Größe von 64 Bytes.

Um nun auf die Daten im Buffer zugreifen zu können, stellt die Bibliothek <SoftwareSerial.h> verschiedene Funktionen bereit.

Es gibt verschiedene integrierte Funktionen in der Arduino Entwicklungsumgebung. Die am häufigsten verwendeten sind folgende:

Beispielsweise erlaubt es die Funktion Serial.read() das erste Zeichen im Buffer auszulesen und es von dort zu entfernen.

Um zu erkennen wann ein Datenstrom beendet ist, werden üblicherweise Terminierungssymbole angehängt. Dabei handelt es sich entweder um Carriage Return oder Line Feed Symbole, die es erlauben zu erkennen wenn Eingaben beendet wurden.

Eine weitere Funktion Serial.available() gibt an wieviele Zeichen sich aktuell im Datenpuffer befinden. Die Funktion verändert nicht den Inhalt sondern gibt nur an ob Zeichen vorhanden sind. D.h. wenn eine Zahl >0 als Ergebnis erscheint sind Daten vorhanden.

Der Algorithmus zur Seriellen-Datenübertragung lässt sich damit wie folgt beschreiben. Am Anfang definiert man sich wie die zu übertragenen Daten strukturiert sein sollen. Z.B. legt man dabei die Syntax fest, die maximale Länge einer Nachricht und wie das Terminierungszeichen aussehen soll. Üblicherweise verwendet man das NewLine Symbol „\n“. Dem folgt die Festlegung der notwendigen Datenstrukturen um die Informationen zu verarbeiten.

Beispiel

ALs Beispiel wie man Daten an den Arduino aus dem Monitor Fenster des PC/Mac übertragen kann sei dieses kleine Demo-Programm vorgestellt:

  //-------------------------------------------
  // PHOF PARSER
  // Version 1.0  06.04.15 Arduino UNO
  // Liest Befehle vom Monitor ein, parst diese
  // und führt entsprechende Aktionen aus
  //-------------------------------------------
  
  int bufferCount;    // Anzahl der eingelesenen Zeichen
  char buffer[80];    // Serial Input-Buffer
  String inputString="";
  int   wert;
  
  void setup() {
    Serial.begin(9600); 
    Serial.println("Bitte Zahl eingeben und mit Enter bestaetigen: ");
  }
  
  void loop() {}     // noch tut sich nichts hier
  
  void serialEvent() {  // liest die Daten vom Seriellen Port  
    char ch = Serial.read();
    buffer[bufferCount] = ch;
    bufferCount++;
    if (ch == 13) {   // sobald Return gedrueckt...
      Serial.println(bufferCount);
      evalSerialData(); 
     } 
  }
  
  void evalSerialData() { //Auswertung der empfangenen Daten

     for (int i = 0; i <= bufferCount ; i++) {
         char inChar=buffer[i]; 
         if(inChar != '\n') {     // String Ende erkennen
            inputString+=inChar;  // Zeichen anhängen
         }
      wert=inputString.toInt();  // Wandelt Sting in Integer
      Serial.print("Ausgabe :");
      Serial.println(inputString); 
   
     }    
     Serial.print("Finaler INT wert : ");Serial.println(wert);
   }// end EvalData
    
  

Datenübertragung mit FTDI Adapter

Ein FTDI Adapter ist ein Modul der Firma FTDI. Die Firma Future Technology Devices International wurde unter ihrem Kürzel FTDI für ihre USB-UART-Interface-Chips bekannt, mit denen es möglich ist, eine serielle Schnittstelle vom Typ RS-232 über einen weiteren Pegelwandler-Schaltkreis mit einem Universal Serial Bus (USB) zu verbinden.

Im folgenden Beispiel wird gezeigt, wie man einen solchen Adapter nutzen kann, wenn man gleichzeitig zwei Monitor-Ausgaben bedienen möchte. Im vorliegenden Versuch wurde ein Arduino Mega über die übliche IDE mit dem integrierten Monitor auf einem Mac programmiert.

Standardmässig wird dabei der Serial(0) auf dem integrierten Monitor ausgegeben. Serial1 wird über einen FTDI Adapter mit einem Windows PC verbunden. Das einfache Programm gibt dann die Nachrichten auf den beiden Monitor-Programmen aus.

Das entsprechende einfache Programm sieht wie folgt aus. Da hier nur gesendet wird sind die Tx und Rx Pins direkt und nicht überkreuzt verbunden.

Weiteres Beispiel

Im nachfolgenden Beispiel wird gezeigt, wie man zwischen Mac und PC Nachrichten austauschen kann. Die auf dem Mac im Monitor eingegeben Nachricht wird einerseits auf dem Monitor angezeigt und gleichzeitig an das Terminal Programm auf dem PC übertragen. Ebenso wird die im Terminal Programm auf dem PC eingegebene Nachricht sowohl auf dem PC als auch dem Monitor-Programm auf dem Mac angezeigt.

Dazu wird die Funktion SerialEvent() verwendet. Sie wird aktiviert, sobald auf dem definierten Kanal Daten ankommen. Dazu müssen selbstverständlich zwei identische Funktionen SerialEvent und SerialEvent1 definiert werden. Beide haben den gleichen Aufbau.

  int bufferCount;    // Anzahl der eingelesenen Zeichen
  char buffer[80]; 
  int bufferCount1;    // Anzahl der eingelesenen Zeichen
  char buffer1[80]; 
  
void setup() {
  Serial.begin(9600);
  Serial1.begin(14400);
  
  pinMode(LED_BUILTIN, OUTPUT);


  Serial.println("Hello via Serial 0 on Mac ---- Test I/O");
  Serial1.println("Hello via Serial 1 to PC ---- Test I/O");
}

void loop() {  
}


void serialEvent() { 
   char ch = Serial.read();
    buffer[bufferCount] = ch;
    bufferCount++;
    if (ch == 13) {   // sobald Return gedrueckt...
      Serial.println(buffer);
      Serial1.println(buffer);
     } 
}


void serialEvent1() { 
  char ch1 = Serial1.read();
    buffer1[bufferCount1] = ch1;
    bufferCount1++;
    if (ch1 == 13) {   // sobald Return gedrueckt...
      Serial1.println(buffer1);
      Serial.println(buffer1);                        
     } 
}