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.
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.
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.
Proof of Concept / Prototyp 🔥
tbd
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);
}
}
}
PCB-Design
tbd
Inbetriebnahme
tbd
Langzeittest: Ein Jahr im Außeneinsatz ☀️🌧️❄️

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.
Fazit & Lessons Learned
tbd