1. RS485 Relay PCB

Inhalt:

Einleitung
Grundprinzip RS485
Blockschaltbild
Schaltplan
Proof of Concept / Prototyp
Firmware
PCB-Design
Inbetriebnahme
Langzeittest: Ein Jahr im Außeneinsatz
Fazit & Lessons Learned

Einleitung

Das Ziel dieses Projekts war eigentlich ganz einfach: Eine eigene PCB zu entwickeln, etwas dazulernen und meine Gartenbeleuchtung über RS485 ansteuern 😎

Daraus ist Schritt für Schritt ein kleines Hardwareprojekt rund um den ATmega8, den MAX485 und zwei Relais entstanden.
Perfekt also, um Bussysteme nicht nur theoretisch zu verstehen, sondern sie wirklich aufzubauen, zu messen und in der Praxis einzusetzen.

Grundprinzip RS485

RS485 ist im Grunde die elektrische Grundlage für eine robuste serielle Kommunikation über zwei Leitungen. Über die beiden Busleitungen A und B wird das Signal differentiell übertragen. Entscheidend ist also nicht die Spannung einer einzelnen Leitung gegen Masse, sondern die Spannungsdifferenz zwischen A und B.

Das macht RS485 ziemlich unempfindlich gegenüber Störungen und deshalb auch für längere Leitungen und industrielle Umgebungen interessant.

Der Mikrocontroller kann mit diesen differentiellen Signalen allerdings nichts direkt anfangen. Deshalb sitzt zwischen UART und Bus ein RS485-Transceiver, in diesem Fall ein MAX485 von Analog Devices. Er übersetzt das normale UART-Signal des ATmega8 in ein differentielles Signal auf A/B – und beim Empfangen wieder zurück.

In meinem Aufbau wird RS485 halbduplex betrieben. Senden und Empfangen laufen also über dasselbe Leitungspaar. Über die Pins DE und /RE wird gesteuert, ob der MAX485 gerade spricht oder zuhört.

Mehrere Teilnehmer können sich denselben Bus teilen. Wer wann senden darf und welcher Teilnehmer angesprochen wird, legt RS485 selbst allerdings nicht fest – das ist Aufgabe des darüberliegenden Protokolls. Für dieses Projekt bleibt es bewusst einfach: Hier geht es erstmal darum, die Hardware hinter dem Bus zu verstehen, aufzubauen und zu messen.

↑ Zurück nach oben

Blockschaltbild

Das Blockschaltbild zeigt erstmal nur die grobe Struktur der Platine und wie die einzelnen Funktionsbereiche zusammenspielen.

Die Versorgung kommt mit 24 V auf die Platine und wird über einen Buck-Converter auf 5 V heruntergesetzt. Diese 5 V versorgen den ATmega8, den MAX485 und die Relaisschaltung.

Die Kommunikation läuft über den RS485-Bus. Der MAX485 übernimmt dabei die Übersetzung zwischen dem differentiellen RS485-Signal auf A/B und der UART-Schnittstelle des Mikrocontrollers.

Der ATmega8 steuert außerdem über DE/RE, ob der MAX485 gerade sendet oder empfängt. Die beiden Relais werden über eigene Treiberstufen vom Mikrocontroller angesteuert.

↑ Zurück nach oben

Schaltplan

Nach dem Blockschaltbild geht es nun eine Ebene tiefer. Der Schaltplan besteht im Wesentlichen aus vier Bereichen: Spannungsversorgung, RS485-Schnittstelle, Mikrocontroller und den beiden Relaisausgängen.

Spannungsversorgung

Die Platine wird mit 24 V versorgt. Direkt am Eingang sitzt zunächst eine Polyfuse als Schutz. Danach folgen Schutz- und Filterbeschaltung sowie der Spannungsregler, der aus den 24 V die benötigten 5 V für Mikrocontroller, MAX485 und Relais erzeugt.

Die 100-nF-Kondensatoren dienen dabei hauptsächlich dazu, schnelle Störungen auf der Versorgung abzufangen. Zusätzlich sorgen größere Kondensatoren als lokale Energiespeicher dafür, dass die Versorgung beispielsweise beim Schalten der Relais nicht unnötig einbricht.

Ein einzelnes Relais vom Typ SRD-05VDC-SL-C besitzt eine Spule von ungefähr 70 Ω. Daraus ergibt sich bei 5 V ca. 71mA Stromaufnahme

2 Relais ergibt also etwa 142 mA. Dazu kommen noch ATmega8, MAX485 und die restliche Elektronik. Für den LME78-05 1.0 kein Problem. Der schafft bis zu 1A also ausreichend Power vorhanden.

RS485-Schnittstelle

Der ATmega8 kann das differentielle RS485-Signal nicht direkt verarbeiten. Diese Aufgabe übernimmt der MAX485. Er bildet die Schnittstelle zwischen der UART des Mikrocontrollers und den beiden Busleitungen A und B.

Über TX und RX werden die eigentlichen Daten übertragen. Die zusammengefassten Pins DE und /RE bestimmen zusätzlich, ob der MAX485 gerade sendet oder empfängt.

Zwischen A und B ist ein 120-Ω-Abschlusswiderstand vorgesehen, der über einen Jumper zugeschaltet werden kann. Dieser wird nur benötigt, wenn sich die Platine tatsächlich an einem Ende des RS485-Busses befindet.

Zusätzlich habe ich zwei 470-Ω-Widerstände für ein optionales Failsafe-Biasing vorgesehen. Sie sorgen dafür, dass A und B auch dann einen definierten Zustand besitzen, wenn gerade kein Teilnehmer den Bus aktiv treibt.

Bei zwei 120-Ω-Abschlusswiderständen sieht das Bias-Netzwerk effektiv ungefähr 60 Ω zwischen A und B.

Da mein Aufbau bereits ohne diese Widerstände funktioniert hat, sind sie zunächst als DNP – Do Not Populate – vorgesehen. Falls sie später doch benötigt werden, sind die Footprints zumindest schon vorhanden.

Die beiden 0-Ω-Widerstände in A und B dienen ebenfalls als Bestückungsoption. Damit können die Leitungen später leicht aufgetrennt oder bei Bedarf andere Serienwiderstände eingesetzt werden.

ATmega8

Als Mikrocontroller kommt ein ATmega8 zum Einsatz. Er übernimmt die UART-Kommunikation, steuert DE/RE des MAX485 und schaltet die beiden Relais.

VCC und AVCC werden jeweils lokal mit 100 nF abgeblockt. Am RESET-Pin sitzt zusätzlich ein 10-kΩ-Pull-up, der dafür sorgt, dass der Mikrocontroller im normalen Betrieb sicher aus dem Reset bleibt.

Für die Programmierung ist außerdem ein eigener ISP-Anschluss vorhanden.

Relais-Treiber

Die Relaisspulen werden nicht direkt vom ATmega8 angesteuert. Rund 71 mA wären für einen GPIO deutlich zu viel. Stattdessen übernimmt jeweils ein BC337 den eigentlichen Spulenstrom.

Um den Transistor sicher in Sättigung zu bringen, habe ich ungefähr mit einem erzwungenen Stromverstärkungsfaktor von 10 gerechnet
IB ≈ 71 mA / 10 ≈ 7 mA

Mit einem Basiswiderstand von 560 Ω ergibt sich näherungsweise:
IB = (5 V − 0,8 V) / 560 Ω ≈ 7,5 mA

Das liegt in einem angenehmen Bereich für einen ATmega8-Ausgang und reicht aus, um den BC337 sauber durchzusteuern.

Ein zusätzlicher 10-kΩ-Pulldown an jeder Basis hält den Transistor sicher ausgeschaltet, solange der Mikrocontroller beim Einschalten oder während eines Resets seine GPIOs noch nicht aktiv treibt.

Über jeder Relaisspule sitzt außerdem eine Freilaufdiode. Beim Abschalten einer Spule entsteht durch deren Induktivität eine Spannungsspitze Selbstinduktionsspannung. Die Diode stellt dafür einen Strompfad bereit und schützt damit den Transistor.

Testpunkte

Für die spätere Inbetriebnahme habe ich mehrere Testpunkte vorgesehen:

+5 V, GND, TX, RX, DE/RE, RS485 A und RS485 B.

Damit lässt sich die Platine Schritt für Schritt überprüfen. Erst die Versorgung, dann die UART-Signale, danach DE/RE und schließlich das differentielle Signal direkt auf dem RS485-Bus.

Gerade wenn etwas nicht funktioniert, spart so ein Testpunkt manchmal deutlich mehr Zeit, als er auf der Leiterplatte Platz kostet.

↑ Zurück nach oben

Proof of Concept / Prototyp 🔥

tbd

↑ Zurück nach oben

Firmware

/*

  • main.c
  • Created: 3/12/2025 8:15:09 PM
  • Author: Kupfuzius
    */

#define F_CPU 8000000UL // Definiert die Taktfrequenz des ATmega8
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define RS485_CONTROL_PIN PB0 // RS485 Steuerpin (MAX485)
#define Relay1_PIN PC0
#define Relay2_PIN PC1

void uart_init() {
UBRRH = 0; // Setzt den oberen Teil des Baudrate-Registers
UBRRL = 51; // Setzt den unteren Teil des Baudrate-Registers für 9600 Baud bei 8 MHz
UCSRB = (1 << RXEN) | (1 << TXEN); // Aktiviert RX und TX
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); // 8 Datenbits, 1 Stopbit, keine Parität
}

void uart_send_byte(uint8_t data) {
while (!(UCSRA & (1 << UDRE))); // Warten, bis der Sende-Buffer leer ist
UDR = data; // Sende das Byte
}

uint8_t uart_receive_byte() {
while (!(UCSRA & (1 << RXC))); // Warten, bis ein Byte empfangen wurde
return UDR; // Empfangenes Byte zurückgeben
}

int main(void) {
uart_init(); // UART initialisieren
DDRC |= (1 << Relay1_PIN); //Relay PIN als Ausgang setzen
DDRC |= (1 << Relay2_PIN);
DDRB |= (1 << RS485_CONTROL_PIN); // RS485 Steuerpin als Ausgang setzen
PORTB &= ~(1 << RS485_CONTROL_PIN); // Standard auf Empfang (DE/RE Low)

while (1) {

uint8_t received = uart_receive_byte(); // Warte auf Empfang eines Bytes


if (received == ‚7‘){
PORTC |= (1 << Relay1_PIN);
}
else if (received == ‚6‘){
PORTC &= ~(1 << Relay1_PIN);
}
else if (received == ‚9‘){
PORTC |= (1 << Relay2_PIN);
}
else if (received == ‚8‘){
PORTC &= ~(1 << Relay2_PIN);
}
}
}

↑ Zurück nach oben

PCB-Design

tbd

↑ Zurück nach oben

Inbetriebnahme

tbd

↑ Zurück nach oben

Langzeittest: Ein Jahr im Außeneinsatz ☀️🌧️❄️

RS485 Relay PCB nach einem Jahr im Außeneinsatz im Garten
Nach einem Jahr mitten im Garten: außen Spuren der Witterung, innen läuft alles einwandfrei.

Die Platine ist inzwischen seit einem Jahr im Garten im Einsatz – in einem einfachen Kunststoffgehäuse mit PG9-Kabelverschraubungen, mitten im Garten und damit voll dem Wetter ausgesetzt.

Insgesamt sind zwei dieser Platinen verbaut, die gemeinsam am selben RS485-Bus hängen. Sie schalten meine Weg- und Gartenbeleuchtung.

In dieser Zeit haben sie so ziemlich alles abbekommen, was das Wetter in Oberösterreich zu bieten hat: Regen, pralle Sonne und Sommerhitze genauso wie Schnee und Minusgrade im Winter.

Das Ergebnis nach zwölf Monaten: Beide Platinen funktionieren einwandfrei. Keine Ausfälle – die Beleuchtung schaltet nach wie vor zuverlässig. Dem Gehäuse sieht man das Jahr im Freien von außen durchaus an, im Inneren ist die Platine aber sauber geblieben.

Für mich ist das die schönste Bestätigung für ein eigenes Hardwareprojekt: Es funktioniert nicht nur auf dem Labortisch, sondern hält auch draußen im echten Einsatz durch.

↑ Zurück nach oben

Fazit & Lessons Learned

tbd

↑ Zurück nach oben