diff --git a/rs485_pingpong.py b/rs485_pingpong.py new file mode 100644 index 0000000..47e2527 --- /dev/null +++ b/rs485_pingpong.py @@ -0,0 +1,101 @@ +''' +A program supposed to run on two RP2040 connected over two channel of an RS485 bus over TTL-UART-to-RS485 converters, and illustrates a simple ping-pong. +Copyright (C) 2024 Benjamin Burkhardt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +''' + +from machine import UART, Pin +import time + +# CHANGE THIS to 'True' on one of the machines (as it +# tells the rp2040 to do the first step in ping-pong communication ;) +INITIALIZER = True + + +# define the UART in-/outputs, named after their usage as either send or receive channels... +# ...depending on wether this is the INITIALIZER or not. +# sure, the in and out pins could be defined in other ways also, but this allows easy customizability... +# ...as just one variable needs to be changed. +print('[UART] Initializing UART for two channels...') +if INITIALIZER: # then read on ch0 and write on ch1 + receiver = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1)) + sender = UART(1, baudrate=115200, tx=Pin(4), rx=Pin(5)) +else: + sender = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1)) + receiver = UART(1, baudrate=115200, tx=Pin(4), rx=Pin(5)) +print('[UART] Initialized UART for two channels.') + + +# initialize the read/write channels and set their value +print('[UART] Setting output/input for each channel...') +if INITIALIZER: # then enable read on ch0 and write on ch1 + receiver_channel_mode = Pin(2, Pin.OUT) # define pinout for the receiver/driver enable pins of channel 0 (shortened together) + sender_channel_mode = Pin(3, Pin.OUT) # define pinout for the receiver/driver enable pins of channel 1 (shortened together) +else: + sender_channel_mode = Pin(2, Pin.OUT) + receiver_channel_mode = Pin(3, Pin.OUT) +receiver_channel_mode.low() +sender_channel_mode.high() +print(f'[UART] Set output/input for each channel. Pin 2 is now {"low" if INITIALIZER else "high"} (CH0 as {"input" if INITIALIZER else "output"}), Pin 3 is now {"high" if INITIALIZER else "low"} (CH1 as {"output" if INITIALIZER else "input"}).') + +# some logging +print('[INFO] Set up RS485 ping-pong.') + + + +# now, the REAL PING-PONG mechanism begins + +# the counter variable will be increased with every ping +# received (which is a pong from the other side which resulted out of a ping there ;) +a = 0 + +# make the first step if INITIALIZER is True (see above at declaration) +if INITIALIZER: + sender.write(f'{a}\r\n') + sender.flush() + print(f'[UART] Sent initial ping: {a}') +print('[INFO] Now waiting for incoming pings/pongs.') + +# now listen for a pong from the other side and answer to it +rxDataConcatenated = '' # to combine partial received data to one full packet (actually just a string that ends with \n :) + +while True: + rxData = receiver.readline() + if rxData is not None: + rxDataDecoded = rxData.decode('utf-8') + if not '\n' in rxDataDecoded: # if the received data is not complete (does not end with a \n), just save the received part + rxDataConcatenated += rxDataDecoded + else: # if it's complete now, add the received part to the potentially saved parts and send the pong + rxDataConcatenated += rxDataDecoded + try: + a = int(rxDataConcatenated) + print(f"[UART] Received ping: {a}") + # send pong after some waiting (could also be left out completely!) + time.sleep(0.2) + a += 1 + sender.write(f'{a}\r\n') + sender.flush() + print(f'[UART] Sent pong: {a}') + except: + receiver_error_details = repr(rxDataConcatenated) + print(f'[UART] Received invalid data? Wait until something good comes in! (received "{receiver_error_details}")') + rxDataConcatenated = '' # reset the received parts storage (see comments above!) + + + + + + + diff --git a/rs485_receive.py b/rs485_receive.py new file mode 100644 index 0000000..86f8643 --- /dev/null +++ b/rs485_receive.py @@ -0,0 +1,57 @@ +''' +Simple program for receiving data over two UART channels to a TTL UART to RS485 converter, printing it out over Serial console. +Inspired by and partly based on Waveshare's example code to the 2 Channel RS485 HAT for the Pi Pico. +Copyright (C) 2024 Benjamin Burkhardt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +''' + +from machine import UART, Pin +import time + +uart0 = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1)) +uart1 = UART(1, baudrate=115200, tx=Pin(4), rx=Pin(5)) + +print('Starting RS485 simple receive...') + +module0_mode = Pin(2, Pin.OUT) # define pinout for the receiver/driver enable pins (shortened together) +module1_mode = Pin(3, Pin.OUT) # define pinout for the receiver/driver enable pins (shortened together) + +module0_mode.low() # logic 0 = receive; logic 1 = send +module1_mode.low() # logic 0 = receive; logic 1 = send + +rxData0concatenated = '' +rxData1concatenated = '' + +while True: + rxData0 = uart0.readline() + if rxData0 is not None: + rxData0decoded = rxData0.decode('utf-8') + if not '\n' in rxData0decoded: + rxData0concatenated += rxData0decoded + else: + rxData0concatenated += rxData0decoded + print(f"[CH0] Received data: {rxData0concatenated}", end="") + rxData0concatenated = '' + + rxData1 = uart1.readline() + if rxData1 is not None: + rxData1decoded = rxData1.decode('utf-8') + if not '\n' in rxData1decoded: + rxData1concatenated += rxData1decoded + else: + rxData1concatenated += rxData1decoded + print(f"[CH1] Received data: {rxData1concatenated}", end="") + rxData1concatenated = '' + diff --git a/rs485_send.py b/rs485_send.py new file mode 100644 index 0000000..ad1803b --- /dev/null +++ b/rs485_send.py @@ -0,0 +1,42 @@ +''' +Simple program sending an incrementing number over two UART channels to a TTL UART to RS485 converter. +Inspired by and partly based on Waveshare's example code to the 2 Channel RS485 HAT for the Pi Pico. +Copyright (C) 2024 Benjamin Burkhardt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +''' +from machine import UART, Pin +import time + +uart0 = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1)) +uart1 = UART(1, baudrate=115200, tx=Pin(4), rx=Pin(5)) + +print('Starting RS485 simple send...') +txData = b'Starting RS485 simple send...\r\n' +uart0.write(txData) +uart1.write(txData) + + +a=0 +time.sleep(0.1) +while True: + time.sleep(0.5) + a=a+1 + uart0.write("{}\r\n".format(a)) + print(f"[CH0]: Sent data: {a}")#shell output + time.sleep(0.5) + a=a+1 + uart1.write("{}\r\n".format(a)) + print(f"[CH1]: Sent data: {a}")#shell output +