Seite 1 von 1

Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Sonntag 28. Juni 2026, 13:11
von kiaralle
Ein Hallo in die Runde,

ich versuche gerade ein Aufsatz für den Rapberry in Betreib zu nehmen.
Dazu habe ich den Code, eine Lib von Waveshare in meinen Code verbastelt, welcher so scheinbar läuft, aber ein paar Fragen für mich aufwirft.

https://www.waveshare.com/wiki/2-CH_RS ... 7cRwHaclk

Da ich einen Raspberry 5 verwende ist doch die Verwendung von RPi.GPIO nicht korrekt. Oder?

Die beiden RS485-Kanäle sind mit Kabeln zueinander verbunden, ich fahre also im Kreis ohne externe RS485-Geräte
Ich sende über "clock" raus und enpfange über "data". Funktioniert also.

das "dev = "/dev/ttyS0"" in der Class bei "def __init__" kann doch durch ein dev = "" ersetzt werden und es funktioiert immer noch.
Wird es durch
endat_clock = RS485config(dev = "/dev/ttySC0")
endat_data = RS485config(dev = "/dev/ttySC1")
definiert?

Code: Alles auswählen

import serial
import RPi.GPIO as GPIO
import time

import os
import sys
import logging


class RS485config(object):
    def __init__(ser, Baudrate = 115200, dev = "/dev/ttyS0"):
        print (dev)
        ser.dev = dev
        ser.serial = serial.Serial(ser.dev, Baudrate)
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)
        
        GPIO.setmode(GPIO.BCM)
        
        GPIO.setup(TXDEN_1, GPIO.OUT)
        GPIO.setup(TXDEN_2, GPIO.OUT)

        GPIO.output(TXDEN_1, GPIO.HIGH)
        GPIO.output(TXDEN_2, GPIO.HIGH)
        
    def Uart_SendByte(ser, value): 
        ser.serial.write(value.encode('ascii')) 
    
    def Uart_SendString(ser, value): 
        ser.serial.write(value.encode('ascii'))

    def Uart_ReceiveByte(ser): 
        return ser.serial.read(1).decode("utf-8")

    def Uart_ReceiveString(ser, value): 
        data = ser.serial.read(value)
        return data.decode("utf-8")
        
    def Uart_Set_Baudrate(ser, Baudrate):
         ser.serial = serial.Serial(ser.dev, Baudrate)
    
  
logging.basicConfig(level=logging.INFO)
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
    sys.path.append(libdir)

TXDEN_1 = 27
TXDEN_2 = 22

endat_clock = RS485config(dev = "/dev/ttySC0")
endat_data = RS485config(dev = "/dev/ttySC1")

GPIO.output(TXDEN_1, GPIO.LOW) #send
GPIO.output(TXDEN_2, GPIO.HIGH) #read

clock = endat_clock.Uart_SendString("Hallo")
data = endat_data.Uart_ReceiveString(5)
    
print(data)

Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Sonntag 28. Juni 2026, 15:24
von DeaD_EyE
Da ich einen Raspberry 5 verwende ist doch die Verwendung von RPi.GPIO nicht korrekt. Oder?
Ist aufgrund einer Hardware-Änderung inkompatibel.
The legacy RPi.GPIO library is incompatible with the Raspberry Pi 5 due to its new RP1 I/O chip. To run old code without rewriting it, use the rpi-lgpio wrapper, which translates RPi.GPIO calls to the modern lgpio library.
rpi-lgpio: https://pypi.org/project/rpi-lgpio/

Da das bei dir zu funktionieren scheint, hast du den Wrapper wahrscheinlich schon. Ansonsten müsste RPi.GPIO eine Fehlermeldung ausgeben.
das "dev = "/dev/ttyS0"" in der Class bei "def __init__" kann doch durch ein dev = "" ersetzt werden und es funktioiert immer noch.
Wird es durch
endat_clock = RS485config(dev = "/dev/ttySC0")
endat_data = RS485config(dev = "/dev/ttySC1")
definiert?
Ja und wenn du nur RS485config() aufrufst, wird die Zuweisung in der Funktionssignatur verwendet, also Baudrate=115200 und dev="/dev/ttyS0".
Da sich das ändern kann, würde ich die Default-Argumente entfernen:

Code: Alles auswählen

def __init__(ser):
Bleibt nur noch `ser` übrig, dass auf die Instanz der Klasse verweist. Aber man verwendet normalerweise das Wort `self` dafür.

Code: Alles auswählen

def __init__(self):
Danach musst du alle Referenzen von `ser.` nach `self.` ändern.

Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Sonntag 28. Juni 2026, 20:23
von kiaralle
Ok, wunderbare Hilfe :-)

Hab alles umgeschrieben. Code funktioniert immer noch.

Die Sachen wie startbits, parity werden in diesen Fall nicht benötigt, weil es sich um einen HAT handelt?

Noch etwas, diese Sachen,

GPIO.output(TXDEN_1, GPIO.LOW) #send
GPIO.output(TXDEN_2, GPIO.HIGH) #read

steuern ob ich den Kanal zum lesen oder schreiben benutze. Hier hat also jeder Kanal seine feste Aufgabe.

Wenn ich also mit nur einem Kanal arbeiten muss, so muss ich jedesmal von HIGH auf LOW usw umschalten?

Gruß Ralf

Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Sonntag 28. Juni 2026, 22:25
von grubenfox
Sachen wie Startbits, Parity usw. müssen bei Sender und Empfänger identisch sein weil es eine serielle Schnittstelle ist... (wenn dafür nichts vorgegeben wird, dann wird das genommen was eben genommen wird wenn der Programmierer nichts vorgibt)

Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Montag 29. Juni 2026, 08:54
von kiaralle
Ok, dan integrier ich das.
Danke

Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Montag 29. Juni 2026, 11:17
von DeaD_EyE
Ganz vergessen auf die Namensgebung einzugehen. Normalerweise macht Blackjack das immer: https://peps.python.org/pep-0008/

Noch was zur Technik: RS485 ist Halb-Duplex. Zum Empfangen von Daten wird RE (Receiver Enable) auf Low gesetzt. Zum Senden muss DE (Driver Enable) auf High gesetzt werden. Viele Controller fassen RE und DE zusammen. Beim Waveshare ist das dann so, dass für den Empfang EN1/EN2 auf Low gezogen werden muss und zum Senden auf High.


Ich hab den Code mal etwas abgeändert (nicht getestet):

Code: Alles auswählen

import logging
from contextlib import contextmanager
from threading import Lock

import RPi.GPIO as GPIO
import serial

TXDEN_1 = 27
TXDEN_2 = 22


def setup_gpio():
    """
    GPIO einrichten
    """
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup((TXDEN_1, TXDEN_2), GPIO.OUT, value=True)


@contextmanager
def enable_send(channel):
    GPIO.output(channel, GPIO.HIGH)
    yield  # ab dann wird der Code im with-Block ausgeführt
    # ab hier ist der Code des Kontext-Managers abgearbeitet
    # output auf 0 setzen, um wieder empfangen zu können
    GPIO.output(channel, GPIO.LOW)


class RS485config(object):
    def __init__(self, dev, enable_gpio, baudrate=115200):
        self.serial = serial.Serial(dev, baudrate)
        self.enable_gpio = enable_gpio
        # soll gleichzeitiges Senden und Empfangen unterbinden
        self.send_receive_lock = Lock()

    def send(self, text):
        # zuerst wird der Lock abgefragt, danach der GPIO durch den Kontextmanager gesetzt
        # wenn er z.B. gerade Daten empfängt, wartet er, bis der Lock wieder freigegeben ist
        # danach wird erst der GPIO auf High gesetzt
        with (
            self.send_receive_lock,
            enable_send(self.enable_gpio),
        ):
            self.serial.write(text.encode("ascii"))

    def receive(self, size):
        with self.send_receive_lock:
            data = self.serial.read(size)
        return data.decode("ascii")

    def set_baudrate(self, baudrate):
        self.serial.close()
        self.serial = serial.Serial(self.serial.port, baudrate)


logging.basicConfig(level=logging.INFO)

# ist eigentlich nicht notwendig
# libdir = Path(__file__).parent.joinpath("lib")
# if libdir.exists():
#    sys.path.append(str(libdir))

# Wenn irgendwas in lib ist, dann importire es
# from lib.modul import funktion


setup_gpio()

# Signatur geändert: Port, Enable-GPIO, Baudrate
endat_clock = RS485config("/dev/ttySC0", TXDEN_1)
endat_data = RS485config("/dev/ttySC1", TXDEN_2)

clock = endat_clock.send("Hallo")
data = endat_data.receive(5)

print(data)


Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Dienstag 30. Juni 2026, 08:01
von kiaralle
Oh, danke für si viel Code.
Da steckt wieder viel interessantes drinnen.
Werde ich mir heute noch einverleiben.
Ziel soll eine Implementierung des Endat-Protokolls von Heidenhaingeber sein.

Man muss immer ein Projekt haben😁

Re: Raspberry mit Waveshare HAT 2-CH RS485

Verfasst: Donnerstag 2. Juli 2026, 19:24
von kiaralle
Kurze Rückinfo...
Der Code funktioniert wie erwartet.
Ich hab ihn mal testweise mit einer Abfrage aus einem anderen Projekt gefüttert, erweitert und auch das funktioniert.

Danke an die Runde :-)