Datenübertragung von Mikro Controller zu Mikro Controller - AZ-Delivery

Die älteste Schnittstelle an Computern und Micro Controllern ist die serielle Schnittstelle, häufig gekennzeichnet mit Rx/Tx (=Receive/Transmit) oder UART (=Universal Asynchronous Receiver Transmitter). Bei der technischen Realisierung wurden Standards unter den Namen RS-232 oder EIA-485 veröffentlicht. Mit anfänglich 75 Baud haben die ersten Computer über ein Modem Anschluss gefunden in der Welt der Fernschreiber. Der technische Fortschritt hat dann Übertragungsraten von 300, 1200, 2400, 9600, 19200 Baud bis 56kBaud gebracht. Dann begann das Zeitalter mit DSL.

Übrig geblieben aus der Zeit sind diese Schnittstellen als Verbindung zwischen den Computern und Micro Controllern. Wegen des Fehlens der alten COM-Schnittstelle am PC wird heute ein USB-Adapter mit einem Virtuellen Comm. Port (VCP) benötigt. Dabei kann der wesentliche Baustein, z.B. ATMega 16U2, CH340/341 oder FT232  auf der MCU verbaut sein oder – bei den ganz kleinen Micro Controllern – als separater USB-Seriell-Adapter notwendig sein, z.B. UART-TTLUSB Adapter 3.3V 5V CH340G Interface oder FT232-AZ USB to TTL Serial Adapter for 3.3V and 5V. Ggf. muss unter Windows der notwendige Treiber installiert werden.

Bei unserem Micro Controller mit ATMEGA 328P sind die Anschlüsse 2 und 3 (oben links im Bild) sowohl mit Chip für die USB-Schnittstelle ATMEGA 16U2 als auch mit den herausgeführten Pins 0=RX und 1 =TX verbunden. Während der Programmierung und bei Nutzung des Seriellen Monitors im Betrieb dürfen deshalb GPIO 0 und 1 nicht anders verwendet werden. Am besten, man verzichtet ganz auf deren Benutzung.

In diesem Blog wollen wir jedoch Micro Controller untereinander verbinden und Daten (z.B. Sensordaten) von einer MCU an einen zweiten Micro Controller senden. Der Sketch für den sendenden Micro Controller sieht dabei ganz einfach aus. Der Code ist identisch mit dem für das Senden von Daten an den Seriellen Monitor. Man öffnet die Serielle Schnittstelle und sendet Daten mit Serial.print() bzw. Serial.println().

Hier der Sketch für die Anzeige von Rel. Luftfeuchtigkeit und Temperatur im Seriellen Monitor, zugleich der „sendende“ Micro Controller (Download):

 #include "DHT.h"
 
 #define DHTPIN 2          // GPIO pin for data
 #define DHTTYPE DHT22     // DHT22(AM2302)
 DHT dht(DHTPIN, DHTTYPE);
 
 void setup(void) {
   Serial.begin(9600);
   Serial.println(F("DHT22 test!"));
   dht.begin();
 }
 
 void loop(void) {
   float h = dht.readHumidity();
   float t = dht.readTemperature();
   Serial.print(F("T = "));
   Serial.print(t);
   Serial.print(F(" °C H = "));
   Serial.print(h);
   Serial.println(F(" % "));
   delay(1000);
 }

Für den zweiten Mikro Controller starten wir erneut die Arduino IDE.

Achtung: Um zwei verschiedene Virtuelle Com-Ports zu öffnen, muss die Arduino IDE ein zweites Mal gestartet (instanziiert) werden, ein neues Fenster genügt nicht.

Zunächst wird der Sketch für den Empfang der Daten hochgeladen, dann werden jeweils TX und RX über Kreuz verbunden.

Achtung: Solange auf dem einen oder anderen Micro Controller Sketche hochgeladen werden, dürfen die MCUs untereinander nicht verbunden sein. Abhilfe dafür schaffen wir durch die Benutzung von SoftwareSerial. Damit können wir auch zugleich Daten empfangen und (ggf. weitere) Daten im Seriellen Monitor anzeigen. Dazu später mehr.

Hier zunächst der Schaltplan:

Aufgrund der unterschiedlichen Spannungen am Mikro Controller mit ATMega 328P (5V) und dem D1 mini (3,3V) habe ich einen Spannungsteiler mit 1 kOhm und 2,2 kOhm zwischen TX am sendenden Mikro Controller und RX am D1 mini eingebaut. Alternativ könnte man einen Logic Level Converter verwenden.

Hier nun die Erläuterungen zur Bibliothek SoftwareSerial

Wie eingangs erwähnt, verfügt die Arduino-Hardware über eine integrierte Unterstützung für die serielle Kommunikation an den Pins 0=RX und 1=TX (die auch über die USB-Verbindung zum Computer geht). Deshalb sollen die digitalen Pins 0 und 1 möglichst nicht im Programm verwendet werden.

Die native serielle Unterstützung erfolgt über eine Hardware (in den Chip integriert), die als UART bezeichnet wird. Diese Hardware ermöglicht es dem ATMega-Chip, auch während der Arbeit an anderen Aufgaben serielle Kommunikation zu empfangen, solange Platz im seriellen 64-Byte-Puffer vorhanden ist.

Die Programmbibliothek HardwareSerial ist in der Arduino IDE integriert und braucht nicht inkludiert zu werden (Ausnahme: ESP32 Serial1 und Serial2)

Die SoftwareSerial-Bibliothek wurde entwickelt, um eine zusätzliche serielle Kommunikation auf anderen digitalen Pins des Arduino zu ermöglichen, wobei Software verwendet wird, um die Funktionalität zu replizieren (daher der Name "SoftwareSerial"). Es ist möglich, mehrere serielle Software-Ports mit Geschwindigkeiten von bis zu 115200 bps zu initialisieren, jedoch stets nur eine zur Zeit zu verwenden. Ein optionaler Parameter ermöglicht invertierte Signale für Geräte, die dieses Protokoll benötigen.

Um diese Bibliothek zu verwenden, muss sie zunächst inkludiert werden mit:

 #include <SoftwareSerial.h>

Dann wird ein Objekt mit einem frei wählbaren Namen, häufig mySerial oder SoftSerial, mit den verwendeten Pins (im Beispiel 7 und 8) instanziiert mit:

 SoftwareSerial mySerial(7,8,);     // RX, TX

Dabei muss beachtet werden, dass der RX-Pin Interrupt-fähig ist.
Schließlich wird das Objekt mySerial in der Funktion void setup() mit der gewünschten Geschwindigkeit (Baudrate) gestartet (dabei sind Baudraten von 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600, and 115200 zulässig):

 mySerial.begin(9600);

Weitere Erläuterungen und vor allem Einschränkungen finden Sie unter https://www.arduino.cc/en/Reference/SoftwareSerial

Hier noch eine Übersicht über die Methoden/Funktionen (mit Link zur Arduino Dokumentation):

SoftwareSerial(), available(), begin(), isListening(), overflow(), peek(), read(), print(), println(), listen(), write()

Und hier kommt der Sketch für den Datenempfang (Download):

 #include <SoftwareSerial.h>
 SoftwareSerial SoftSerial;
 
 //global variables to store the incoming data
 int data = 0;
 String dataset="";
 String dataSet="";
 
 void setup() {
   //Begin Serial Comms with 9600 baud
   Serial.begin(9600);
   SoftSerial.begin(9600, SWSERIAL_8N1, 4, 5, false);   //RX=4, TX=5
 }
 void loop() {
   //When Data are available...
   if (SoftSerial.available() > 0) {
       //Read incoming data
       data = SoftSerial.read();
     //Data format is ASCII (0..255),
     //therefore conversion to char()      
       if (char(data) != '\n') {
       dataset += char(data);
    }  
     else {
       Serial.println("dataSet");    
       Serial.println(dataset);
       Serial.println();
       dataSet = dataset;      
       dataset="";
    }
  }
 }

Anmerkungen zu diesem Sketch:

Die Daten werden im ASCII-Format als einzelne Zeichen empfangen. Für die Weiterverarbeitung benötigen wir zunächst die Konkatenation (=Aneinanderreihung) der Zeichen zu einem String. Solange das Zeilenende (\n) nicht erreicht ist, werden die einzelnen Zeichen (data) nach Umwandlung mit char() zu dem String dataset zusammengesetzt.

Wenn das empfangene Zeichen gleich dem Zeilenumbruch (\n) ist, erfolgt der Sprung zu else mit der Ausgabe des Strings dataset im Seriellen Monitor, dem Speichern des Strings in einer zweiten Variablen dataSet (mit dem großen S) für die weitere Verarbeitung, sowie dem Zurücksetzen von dataset zum Leerstring für den erneuten Empfang von Daten.

Selbstverständlich kann man den kompletten String mit einem ESP-Mikro Controller als WebServer ins heimische WLAN stellen und komplett im Browser des PCs oder Smartphones anzeigen. Wenn man jedoch die Werte für Temperatur und Rel. Luftfeuchtigkeit (engl. Humidity) weiterverarbeiten möchte, müssen der String zerlegt und die Zeichen in die jeweiligen Zahlenwerte mit Nachkommastellen (float) umgewandelt werden.

Dafür benötigen wir die Funktionen substring() und toFloat(). Die entsprechenden Zeilen im Code lauten:

 String Tstring = dataSet.substring(from, to);
 String Hstring = dataSet.substring(from, to);
 T = Tstring.toFloat();
 H = Hstring.toFloat();

Bleibt als letztes die Frage, welche Werte wir jeweils für from und to einsetzen, um die beiden Teilstrings so zu erhalten, dass wir sie anschließend in die Gleitkommazahlen (=floating point!) umwandeln können.

Im ersten Versuch habe ich die Zeichen abgezählt. Die Zählung des Indizes beginnt bei 0, from ist der Index inklusive, ab dem der Teilstring beginnt, to der Index für das Ende exklusive, also das erste Zeichen danach. Das klappt solange, wie die Werte für die Temperatur und die Luftfeuchtigkeit zwei Stellen vor dem Komma haben. Einstellige Temperaturen oder Minuszeichen bringen die Zählweise durcheinander. Wir benötigen also Bezugspunkte für die Indizes. Ich habe mich entschieden, jeweils den Index für T und H zu ermitteln, denn die Funktionen für Zeichen (isAlpha() , isAlphaNumeric() , isAscii() , isControl() , isDigit() , isGraph() , isHexadecimalDigit() , isLowerCase() , isPrintable() , isPunct() , isSpace() , isUpperCase() , isWhitespace()  ) waren leider ungeeignet für diesen Zweck.

Also habe ich kurzerhand eine for-Schleife programmiert, in der von Index=0 bis zur letzten Stelle (Funktion length() ) geprüft wird, ob charAt(i) gleich ‘T‘ bzw. ‘H‘ ist. (Achtung: char erfordert ‘einfache Anführungszeichen‘) Nun hatte ich jeweils einen Bezug für meine Teilstrings. Die genauen Werte hängen natürlich von dem gesendeten String ab.

 for (int i=0; i<=dataSet.length(); i++)  
    {
       if (dataSet.charAt(i) == 'T') indexT = i;
       if (dataSet.charAt(i) == 'H') indexH = i;          
    }

Hier der komplette Sketch (Download):

 for (int i=0;i<=dataSet.length();i++)  
 #include <SoftwareSerial.h>
 SoftwareSerial SoftSerial;
 
 //global variables to store the incoming data
 int data = 0;
 String dataset="";
 String dataSet="";
 int indexT;
 int indexH;
 float T;
 float H;
 
 void setup() {
   //Begin Serial Comms with 9600 baud
   Serial.begin(9600);
   SoftSerial.begin(9600, SWSERIAL_8N1, 4, 5, false);
 }
 void loop() {
   //When Data are available...
   if (SoftSerial.available() > 0) {
       //Read incoming data
       data = SoftSerial.read();
     //Data format is ASCII (0..255),
     //therefore conversion to char()      
       if (char(data) != '\n') {
       dataset += char(data);
    }  
     else {
       Serial.println("dataSet");    
       Serial.println(dataset);
       Serial.println();
       dataSet = dataset;      
       dataset="";
       dataConversion();
    }
  }
 }
 void dataConversion() {  
   for (int i=0; i<=dataSet.length(); i++)  
    {
       if (dataSet.charAt(i) == 'T') indexT = i;
       if (dataSet.charAt(i) == 'H') indexH = i;          
    }
     String Tstring = dataSet.substring(indexT+4, indexH-5);
     String Hstring = dataSet.substring(indexH+4, indexH+9);
     T = Tstring.toFloat();
     H = Hstring.toFloat();
     Serial.print("T = ");
     Serial.println(T);
     Serial.print("H = ");
     Serial.println(H);    
     Serial.println();
 }

Ich hoffe, diese kleinen Tipps und Tricks rund um Datenübertragung und String-Manipulation sind hilfreich. Ich selbst musste ein ganzes Weilchen tüfteln. Das Gesamtergebnis unserer Versuche, einschließlich der Datenausgabe im WLAN, können Sie demnächst im eBook zu unserem Smart-Home Starter Set lesen.

Esp-8266Für arduinoProjekte für anfänger

2 commenti

Bernd Albrecht

Bernd Albrecht

Hallo, Herr Schulz,
vielen Dank für Ihr Interesse an unseren Produkten und Blog-Beiträgen. Gerne nehmen wir auch Anregungen auf oder schreiben über „Ihr Projekt“. Bitte haben Sie Verständnis, dass wir keine maßgeschneiderten Auftragsarbeiten annehmen können.
Zu Ihrer Anfrage teile ich Ihnen folgendes mit:
zu 1. Kennen Sie eigentlich die Suchfunktion auf der Seite von AZ-Delivery.de? Ich habe das Wort Ethernet eingegeben und erhalte eine Registerkarte „Products“ (12) und auf Mausklick gelange ich zur zweiten Registerkarte „Pages“ (18). Hier finden Sie die Beiträge zu den Ethernet-Shields und – Modulen.
zu 2. Für das Senden von Befehlen (z.B. Datenabfrage) an den Micro Controller empfehle ich auch die Arduino IDE. In der obersten Zeile können Sie dann z.B. T für Temperatur und P für Luftdruck (pressure) eingeben und auf Senden drücken. Mit der Befehlszeile Serial.read() im Sketch lesen Sie den gesendeten Buchstaben und können dann mit einer if-Abfrage den gewünschten Wert senden. Für die Aufzeichnung größerer Datenmengen benötigen Sie ein Speichermedium. Produkte und passende Blog-Beiträge habe ich über das Wort „Daten“ im Suchfenster erhalten.
zu 3. Zum Thema Anzeige von Messdaten im heimischen WLAN haben wir ebenfalls in der Vergangenheit bereits im Blog berichtet. Ein weiterer Beitrag befindet sich im Vorlauf und sollte zeitnah erscheinen.
zu 4. Um einfache Emails zu versenden, benötigen Sie ein Modul für eine SIM-Karte. Ich selbst habe ein GPS-Modul verwendet, um Positionsdaten zu senden. Aber es gibt auch ein einfaches GSM-Modul im Sortiment.

Thomas Schultz

Thomas Schultz

Ich finde die Idee des Blogs wirklich toll, abr leider ist bis jetzt nicht ein Projekt aufgetaucht,
das mich interessieren würde. Diese Beitrag mc zu mc ist zwar etwas in dieser Richtung, aber immer noch nicht, was ich bräuchte. Was ich mir wünschen würde wären folgende drei Beispiele:
1. Der Einsatz eines LAN-Shields
2. Die Steuerung eines Arduino via USB vom PC aus. Daten- und Befehlsaustausch.
Der arduino soll Daten sammeln und auf Anforderung an den PC schicken oder auf der Platte ablegen.
Und, es sollten vom PC aus Befehle (z.B. via DOS-Zeile) an den Arduino geschickt werden.
3. Die Steuerung z.B. eines Relais via Webseite ist ja bereits behandelt worden. Was mich aber interessieren würde ist, wie ich permanent auf der Webseite einen Meßwert anzeigen lassen kann.
Aktuelles Anwendungsprojekt: Ich möchte gerne den ELV-Gewitterwarner mit einer Logik versehen und aus der Ferne ablesbar machen.

Und zum Schluss noch eine Frage: Kennt ihr eine Möglichkeit um einen Schaltzustand per Emails oder noch besser als Pushnachricht an mehrere Freunde schicken kann.

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione