RS485
https://en.wikipedia.org/wiki/RS-485
RS485 is a very inexpensive way to wire devices together in a network. A single twisted pair (such as two wires from regular UTP network cable) at low speeds can operate over a kilometre.
Devices must be daisy-chained together, and long runs should be properly terminated typically with 120 ohm resistors at either end.
Connecting devices in star topology causes signal reflections and generally won’t work except for very short runs.
One solution is to use multiple MAX485 (or similar) transceivers to create multiple physical network segments. Only one UART is required unless you need concurrent requests.
This example allows for one transceiver to be in receive mode, with others in transmit. That means slave addresses must be unique across both segments. Resistors R2 and R8 are current limit resistors to guard against both transceivers being switched into receive mode at the same time.
The logic for controlling this would be in a callback registered via IO::RS485::Controller::onSetDirection()
.
For completeness, here’s example connections for a 3.3v transceiver:
R22 is optional, typically installed only on longer runs. D3 is additional transient protection - always a good idea as a first line of defence even if the transceiver itself has some built in.
-
namespace RS485
RS485/Controller.h
Copyright 2022 mikee47 mike@sillyhouse.net
This file is part of the IOControl Library
This library 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, version 3 or later.
This library 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 library. If not, see https://www.gnu.org/licenses/.
RS485/Device.h
Copyright 2022 mikee47 mike@sillyhouse.net
This file is part of the IOControl Library
This library 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, version 3 or later.
This library 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 library. If not, see https://www.gnu.org/licenses/.
RS485/Request.h
Copyright 2022 mikee47 mike@sillyhouse.net
This file is part of the IOControl Library
This library 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, version 3 or later.
This library 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 library. If not, see https://www.gnu.org/licenses/.
-
class Controller : public IO::Controller
- #include <Controller.h>
Public Types
-
using SetDirectionCallback = void (*)(uint8_t segment, Direction direction)
Callback to handle hardware transmit/receive selection Typically called from interrupt context so implementation MUST be marked IRAM_ATTR.
- Param segment:
Identifies physical connection for shared/multiplexed port
- Param direction:
Public Functions
-
inline virtual const FlashString &classname() const override
Get the class name for this Controller.
-
virtual void start() override
Start the controller.
Controllers may now initiate communications with registered devices. Typically they’ll query device status, etc.
-
virtual void stop() override
Stop all controllers.
This method is called by the Device Manager, applications shouldn’t need it.
Note
MUST call canStop() first to ensure it’s safe to stop!
-
inline void onSetDirection(SetDirectionCallback callback)
Set the transmit callback handler.
Typically with RS485 a GPIO is used to toggle between transmit/receive modes. Using a callback allows flexibility for your particular hardware implementation. You don’t need to set this up if your hardware handles the switch automatically.
- Parameters:
callback –
-
inline void setDirection(IO::Direction direction)
Whilst a port is acquired, call this method to being or end transmission.
Note
Port should normally be left in receive mode on request completion.
- Parameters:
direction –
-
using SetDirectionCallback = void (*)(uint8_t segment, Direction direction)
-
class Device : public IO::Device
- #include <Device.h>
Base device class for communicating with an RS485 slave.
Subclassed by IO::DMX512::Device, IO::Modbus::Device
Public Functions
-
inline virtual uint16_t address() const override
Devices with a numeric address should implement this method.
-
virtual void handleEvent(IO::Request *request, Event event) override
Implementations may override this method to customise event handling.
-
struct Config
- #include <Device.h>
RS485 configuration.
-
struct Slave
- #include <Device.h>
Public Members
-
uint16_t address
Network device address or ‘slave ID’
-
uint8_t segment
Application-defined value for multiplexed serial ports. For example, several MAX485 transceivers can be connected to one serial port with appropriate multiplexing logic.
-
unsigned baudrate
Serial link speed
-
unsigned timeout
Max time between command/response in milliseconds.
-
uint16_t address
-
struct Slave
-
template<class DeviceClass>
class FactoryTemplate : public IO::Device::Factory - #include <Device.h>
Subclassed by IO::DMX512::Device::Factory, IO::Modbus::Device::Factory, IO::Modbus::NT18B07::Device::Factory, IO::Modbus::R421A::Device::Factory, IO::Modbus::RID35::Device::Factory, IO::Modbus::STM8Relay::Device::Factory, IO::Modbus::STS::Fan::Device::Factory
Public Functions
-
inline virtual IO::Device *createDevice(IO::Controller &controller, const char *id) const override
Create a new device instance.
Called by
DeviceManager::createDevice()
- Parameters:
controller – The owning controller
id – Unique identifier for the device
- Return values:
Device* – The constructed instance
-
inline virtual const FlashString &controllerClass() const override
Return the expected controller type for this device class, e.g. ‘rs485’.
The Device Manager uses this value to verify that devices are constructed using the correct controller.
-
inline virtual IO::Device *createDevice(IO::Controller &controller, const char *id) const override
-
inline virtual uint16_t address() const override
-
class Request : public IO::Request
- #include <Request.h>
Subclassed by IO::Modbus::Request
-
class Controller : public IO::Controller