Serielle Geräte anschließen

Der RevPi Flat hat zwei RS485-Schnittstellen. Dadurch kannst Du serielle Protokolle wie z. B. Modbus verwenden und Geräte wie Smart-Meter oder Solarwechselrichter kostengünstig in Dein System einbinden.

Die Anschlüsse sind mit “RS485-0” und “RS485-1” bezeichnet. Der RS485-0-Anschluss liegt auf einer 3-poligen Klemme, für den RS485-1-Anschluss steht Dir eine RJ11-Buchse zur Verfügung. Beide Anschlüsse sind untereinander und jeweils vom RevPi Flat System galvanisch getrennt.

Die Datenleitungen der RS485-Klemme sind mit P (positive) und N (negative) bezeichnet. Bei anderen Geräten werden diese Leitungen auch häufig D+ und D- oder A und B bezeichnet.

Für die eigentliche Datenübertragung werden nur die Leitungen N und P benötigt. Wir empfehlen Dir, bei größeren Leitungslängen oder Baudraten ein verdrilltes Pärchen zu verwenden.

Beschaltung Anschluss RS485-0

GND

Erde

N

Negativ

P

Positiv

 

Beschaltung Anschluss RS485-1

1: NC

Nicht angeschlossen

2: GND

Erde

3: N

Negativ

4: P

Positiv

5: GND

Erde

6: NC

Nicht angeschlossen

Bezugspotential
Falls ein Bezugspotenzial notwendig sein sollte, kannst Du die elektrische Schaltungsmasse “GND” vom jeweiligen RS485-Bus dazu verwenden. Da die beiden RS485-Systeme über eine vollständige galvanische Trennung untereinander und zur restlichen RevPi Flat Schaltung verfügen, sind diese “GND”-Anschlüsse auch untereinander sowie vom RevPi Flat GND‑Anschluss galvanisch getrennt.

Schirmung
Leitungen mit einer Länge über 30 Metern oder Leitungen, die das Gebäude verlassen, sollten geschirmt sein. Um die EMV-Eigenschaften des Schirmes noch zu verbessern, kannst Du bei Bedarf den Schirm mit der Potenzialausgleichsschiene des Verteilerkastens verbinden. Eine solche Verbindung lässt sich einfach mit einer Kontakt-Rollfeder herstellen.

Bitraten
Von Linux aus werden die Schnittstellen über die Character Devices “/dev/ttyAMA0” und “/dev/ttyS0” angesprochen. Du kannst Bitraten von 50 bis 3.000.000 für “/dev/ttyAMA0” und von 1.200 bis 4.000.000 für “/dev/ttyS0” konfigurieren. Allerdings kann es bei mehr als 230.400 Bit zu gelegentlichen Empfangsfehlern kommen. Das liegt daran, dass der UART des Raspberry Pi, an den die Schnittstelle angeschlossen ist, nur eine 16-Byte-kleine FIFO hat und kein DMA unterstützt. Je höher die Bitrate, desto häufiger passiert es, dass die FIFO nicht schnell genug ausgelesen wird und empfangene Daten verloren gehen. Beispielsweise kommt es bei 460.800 Bit zu 1-2 Fehlern pro empfangenen 50 MByte, bei 921.600 Bit zu rund 10 Fehlern. Wenn Dein RevPi Flat vorwiegend Daten sendet und nur selten empfängt, kannst Du bedenkenlos auch höhere Bitraten verwenden, ansonsten empfehlen wir Dir aber, nicht mehr als 230.400 Baud einzustellen.

Terminierung
Die Schnittstelle verfügt über einen integrierten Abschlusswiderstand mit 120 Ohm. Diese Terminierung ist nach dem Booten ausgeschaltet. Das ist am sichersten, da keine Kommunikation möglich ist, wenn mehrere Geräte am RS485-Bus ihre Terminierung einschalten. Über kurze Kabel ist die Kommunikation auch ohne Terminierung möglich. Für längere Distanzen solltest Du sie einschalten, falls sich Dein RevPi Flat an einem Ende der Busleitung befindet.

Das Ein- und Ausschalten der Terminierung geschieht folgendermaßen:

  • Öffne das Character Device “/dev/ttyAMA0” oder “/dev/ttyS0” mit “open()”.
  • Lies die aktuelle RS485-Konfiguration mit einem “TIOCGRS485 ioctl()” aus.
  • Setze oder lösche das SER_RS485_TERMINATE_BUS Flag in der “struct serial_rs485”.
  • Aktiviere die geänderte RS485-Konfiguration mit einem “TIOCSRS485 ioctl()”.
  • Ggf. sende oder empfange die Daten mit “read()” oder “write()”.
  • Schließe das Character Device mit “close()”.

Achtung: Diese Schritte musst Du nach jedem Booten wiederholen, falls die Terminierung eingeschaltet sein soll.

Wir haben ein C-Listing mit diesen Schritten vorbereitet, das Du nur noch kompilieren brauchst:

/*
 *  Copyright (c) 2020 KUNBUS GmbH
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/serial.h>
#include <sys/ioctl.h>
#define RCV_LEN 3

int main(int argc, char **argv)
{
	struct serial_rs485 rs485conf;
	int fd, ret;
	char buf[RCV_LEN];

	if (argc != 2) {
		printf("Usage: %s <device>\n", argv[0]);
		return 0;
	}

	fd = open(argv[1], O_RDWR);
	if (fd < 0) {
		printf("Cannot open: %s\n", strerror(errno));
		return errno;
	}

	ret = ioctl(fd, TIOCGRS485, &rs485conf);
	if (ret < 0) {
		printf("Cannot get rs485 config: %s\n", strerror(errno));
		return errno;
	}

	rs485conf.flags ^= SER_RS485_TERMINATE_BUS;

	ret = ioctl(fd, TIOCSRS485, &rs485conf);
	if (ret < 0) {
		printf("Cannot set rs485 config: %s\n", strerror(errno));
		return errno;
	}
	ret = write(fd, "abc", 3);
	ret |= read(fd, buf, RCV_LEN);
	if (ret < 0) {
		printf("send or receive error: %s\n", strerror(errno));
		return errno;
	}

	ret = close(fd);
	if (ret < 0) {
		printf("Cannot close: %s\n", strerror(errno));
		return errno;
	}
}

Standardmäßig wird nach dem Booten „/dev/ttyAMA0“ als Konsolenterminal mit den folgenden Konfigurationen verwendet:

pi@RevPi0000:~ $ sudo stty -F /dev/ttyAMA0
speed 115200 baud; line = 0;
lnext = <undef>; min = 1; time = 0;
-brkint -icrnl ixoff -imaxbel iutf8
-icanon -iexten -echo