Aus Raspberry Pi Geek 06/2017

Mehr serielle Schnittstellen für den ESP8266 (Seite 3)

Abbildung 5: Ein eigens auf dem ESP8266 installierter Webserver übernimmt die Ausgabe der Daten aus dem intelligenten Stromzähler.

Abbildung 5: Ein eigens auf dem ESP8266 installierter Webserver übernimmt die Ausgabe der Daten aus dem intelligenten Stromzähler.

Listing 1

 

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <SoftwareSerial.h>
const char* ssid = "SSID WLAN";
const char* pass = "Passwort";
IPAddress serverip(192, 168, 1, 99);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);
ESP8266WebServer server(80);
SoftwareSerial irSerial(14, 12, false, 512); // RX, TX, inverse, buffsize
void handleRoot() {
  String data;
  String message = "";
  message += "<html><body>\n";
  message += "Verbrauchswerte<BR>";
  message += data;
  message += "\n";
  Serial.println("Send /?!");
  irSerial.write(0xAF); // "/"
  irSerial.write(0x3F); // "?"
  irSerial.write(0x21); // "!"
  irSerial.write(0x8D); // "\r"
  irSerial.write(0x0A); // "\n"
  data ="";
  delay(1000);
  while(irSerial.available() > 0) {
    yield();
    char in = irSerial.read();
    in &= 0x7F;
    data = data + String(in);
    delay(10);
  }
  Serial.println(data);
  Serial.println("Send -000");
  irSerial.write(0x06); // "-"
  irSerial.write(0x30); // "0"
  irSerial.write(0x30); // "0"
  irSerial.write(0x30); // "0"
  irSerial.write(0x8D); // "\r"
  irSerial.write(0x0A); // "\n"
  delay(4000);
  data ="";
  while(irSerial.available() > 0) {
    yield();
    char in = irSerial.read();
    in &= 0x7F;
    if (in==0x0A) data = data + "<br>";
    data=data + String(in);
    delay(10);
  }
  Serial.println(data);
  delay(5000);
  message += data;
  message += "</body></html>\n";
  server.send(200, "text/html", message);
}
void setup(void) {
  irSerial.begin(300);
  Serial.begin(115200);
  WiFi.begin(ssid, pass);
  WiFi.config(serverip, gateway, subnet, dns);
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  server.on("/", handleRoot);
  server.begin();
  Serial.println("HTTP server started");
}
void loop(void) {
  server.handleClient();
}

Haben Sie alle nötigen Bibliotheken importiert, definieren Sie die für den Betrieb nötigen Konstanten. Achten Sie darauf, die passenden Zugangsdaten für das WLAN in Ihrem Netzwerk zu verwenden. Darüber hinaus passen Sie die IP-Konfiguration des Servers an die IP-Range im LAN an.

Das Objekt SoftwareSerial irSerial (Zeile 14) initialisieren Sie mit den Pinnummern für RX und TX, der Größe des Puffers und einem Parameter zum Invertieren des Signals. Haben Sie versehentlich die zwei Datenleitungen vertauscht, brauchen Sie deswegen auch nicht zum Lötkolben zu greifen: Sie “verdrahten” sie einfach an dieser Stelle im Programm wieder richtig.

Die Größe des Lesepuffers ist ein sehr wichtiger Parameter, den Sie mit Bedacht wählen sollten. Das Testprogramm wartet zunächst, bis die komplette Nachricht des Stromzählers im Buffer ankommt, und beginnt dann erst, ihn auszulesen. Entsprechende Buffer baut man immer als Ringspeicher auf: Laufen sie voll, überschreibt der Rechner die ältesten Daten.

Jetzt bleibt noch zu klären, was der Parameter inverse in Zeile 14 bewirkt. Zu Anfang des Artikels haben wir kurz erwähnt, dass es unter Umständen vorkommt, dass ein System die Daten invertiert überträgt. Die in Software implementierte serielle Schnittstelle arbeitet von Haus aus nicht invertiert. Falls Sie sie aber mit einem invertiert arbeitenden Gerät verbinden, können Sie über diesen Parameter das Verhalten der Schnittstelle anpassen.

In der Funktion setup() in Zeile 63 legen Sie die Geschwindigkeiten der zwei seriellen Schnittstellen fest. Ja, Sie haben richtig gelesen: Der Stromzähler überträgt nur 300 Zeichen in der Sekunde – nicht gerade schnell, aber für unseren Zweck ausreichend. Des Weiteren startet die Funktion die WLAN-Verbindung und den Webserver. Die Funktion loop() (Zeile 83) ruft die Methode handleClient() des Server-Objekts auf, um den Server zu betreiben.

Die Funktion handleRoot() ab Zeile 16 sendet die Steuersequenz an den Stromzähler. Der erwartet 7 Datenbits, eine gerade Parität und ein Stoppbit. Hier tricksen wir etwas: Anstatt das Parity-Bit nachträglich hinter den Datenbits zu übertragen, senden wir es als erstes Bit im Byte. Der UART im Zähler errechnet die Parität aus allen Bits, die ankommen. Da es sich nur um wenige Bytes handelt, die Sie anpassen müssen, sind die Parity-Bits in die zu übertragenden Bytes der Steuersequenz eingefügt.

Das erklärt die Diskrepanz zwischen ASCII-Zeichen und dazugehörigen hexadezimalen Werten in den Zeilen mit irSerial.write(). Als Beispiel: Aus 0x0D (CR) wird 0x8D, damit die Parität wieder passt. Der Wert 0x0A (LF) hat schon eine gerade Parität, Sie brauchen also das höchste Bit im Byte nicht zu setzen.

Nach dem Senden der ersten Steuersequenz gibt der Rechner dem Zähler eine Sekunde Zeit für die Antwort (Zeile 30). Danach liest er den Buffer aus und sendet ihn zum Debugging an die erste serielle Schnittstelle, die mit dem Rechner verbunden ist. Beim Auslesen des Puffers löscht das Programm das vom Zähler übertragene Parity-Bit mit der Anweisung in &= 0x7F; aus dem Byte heraus (Zeile 34).

Was Sie jetzt über die Debug-Schnittstelle angezeigt bekommen, ist die Kennung des Stromzählers, aus der Sie unter anderem dessen maximale Schnittstellengeschwindigkeit ersehen.

Mit der zweiten Steuersequenz ab Zeile 39 veranlasst die Software den Stromzähler, die gemessenen Werte zu übertragen. Hier finden sich ebenfalls die für das Parity-Bit nötigen Anpassungen im Code. Diesmal ist die Verzögerung etwas länger, bevor das Programm den Buffer ausliest: Es laufen mehr Daten über die Leitung. Letztendlich schreibt die Software diese in die Zeichenkette message und übergibt diese an die Methode send() des Server-Objekts (Zeile 60).

Vergessen Sie nicht, dass dieses Programm als Beispiel für die Funktionsweise der in Software implementierten seriellen Schnittstelle dient. Es arbeitet so nur mit dem Stromzähler E350 von Landis & Gyr zusammen. Zudem ließe sich die rudimentäre Ausgabe mit wenigen Handgriffen optisch ansprechender oder maschinenlesbar gestalten. Für Letzteres böte sich die Ausgabe in JSON an, sodass eine App die Daten direkt lesen könnte.

Fazit

Eine in Software implementierte serielle Schnittstelle erweist sich für viele Fälle als eine gute Alternative zum echten Hardware-UART. Sie lässt sich leicht konfigurieren und kommt auch mit ungewöhnlicheren Protokollen zurecht, wie dem 7E1 unseres Stromzählers. Der wohl größte Vorteil gegenüber einem Hardware-UART: Die Kosten beschränken sich auf RAM für den Buffer und CPU-Leistung zum Verwalten.

Im Bastler-Bereich gibt es noch eine Menge Geräte, die serielle Schnittstellen mitbringen. Daher lohnt es sich, einen Nachmittag zu investieren und mit der vorgestellten Bibliothek zu arbeiten. Sie öffnet die Tür zu vielen weiteren interessanten Projekten, wie zum Beispiel Volkszähler.org, das interessante Ansätze zur Heimautomation bietet. 

Der Autor

Martin Mohr hat die komplette Entwicklung der modernen Computertechnik live miterlebt. Bereits in früher Jugend entwickelte er eine Vorliebe für alles, was blinkt. Mit dem RasPi erwachte seine alte Liebe zur Elektronik wieder.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 6 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben