Arduino library for RS485 communication.
RS485 is an experimental library to make half duplex communication easier. The library implements the Stream interface so the user can use print() and write() calls just like one does with Serial.
Preferably the library is to be used with a hardwareSerial as these can buffer incoming characters in the background. A software Serial that uses pin interrupts would also work quite well, needs to be tested.
The 0.2.0 version of the library has no (tested) protocol for multi-byte messages so the user must implement such on top of this class.
The 0.5.0 version uses new defines for the ASCII_CONTROL.h to fix a name conflict on the ESP32 platform. The new defines all have got an ASCII_ prefix, e.g. ASCII_FS
Processor MAX485
+------------------+ +-------------+
| | | |
| RX |<-----------| RO |
| TX |----------->| DI |
| | | |
| | +--->| RE |
| sendPin |-------+--->| DE |
| | | |
| VCC |------------| VCC |
| GND |------------| GND |
| | | |
+------------------+ +-------------+
RX = Receive Serial RO = Receiver Output
TX = Transmit Serial DI = Driver Input
sendPin = IO.pin RE = Receiver Output Enable
DE = Driver Output Enable
#include "RS485.h"
The most important commands of the Stream interface are:
All variations of print(), println() and write() can be used, the library calculates the time needed to set the RS485 chip in transmit mode.
An important command from the stream interface is the setTimeOut() as this allows reads on the RS485 bus that are limited.
Experimental
To add a small delay after flush() to be sure that the last byte in the TX register has time to be sent. It prevents a premature switching from transmit to receive mode. The default value is 1100 (9600 baud time) and can be tuned, e.g. when high baud rates are used it can be smaller.
Work in progress. The library has an experimental protocol implemented to send and receive larger messages between the nodes in the network. This network consists of one master that can poll multiple slaves.
In 0.2.5 this protocol has been tested and some bugs in the receive parser have been fixed. It still is experimental and it needs more testing.
The library functions are:
Two wrappers:
Current implementation limits messages up to 48 bytes (hardcoded buffer size) which is in many cases enough.
See example sketches.
A RS485 controlled device is typically waiting for a command or message and is therefore default in listening or receiving mode. Only when the device needs to answer the library will automatically set the RS485 chip in sending mode, wait for enough time to "flush the buffer" and resumes with listening.
Since 0.2.5 an example is added that sniffs the bytes on the RS485 bus and prints them as a HEX dump.
Can be used for debugging.
Do not forget to use one pull up (A line) and one pull down (B line) at only one end of the bus. Values depend on the length of the cables, start with 1 KΩ (kilo ohm)
Note Ω = alt-234.
Preferred wire for RS485 is STP (Shielded Twisted Pair), however UTP (Unshielded) will works in many cases. Typical for most applications CAT5 (100 Mbit) will do the job. Do not forget to connect GND to the shield later of the STP.
Note CAT5 has 4 x 2 twisted wires so there are 6 cables to spare. These could be used e.g. to build a FULL DUPLEX version in which every slave has 2 RS485 ports, one for receiving and one for sending. Another application is to use these as power lines e.g 5 and 12 V.
For RTOS environments the yield() function needs to be called when code might be blocking. As the RS485 baud rate can be pretty low, the write(array, length) function can be blocking for too long so the function can call yield() every 4 milliseconds if enabled.
To enable yield() uncomment the following line in RS485.cpp
// #define RS485_YIELD_ENABLE 1
or set this flag in the command line compile option.
Note: the yield() calling version is substantial slower, depending on the baud rate. Use with care.
TODO: to be tested on ESP32 - RTOS.
An error I made in one of my first RS485 experiments was that a possible response of one module would trigger another module to also send a response. Of course these two responses interacted quite consistent but wrong. It took some time to find the cause and to redesign the protocol used.
Lesson learned was to spend more time designing the protocol up front. And keep commands and responses 100% disjunct.
An example of a simple byte protocol could use commands all with bit 7 set to 1, and all responses with bit 7 set to 0 (E.g ASCII). Would allow 127 different 1 byte commands.
If you appreciate my libraries, you can support the development and maintenance. Improve the quality of the libraries by providing issues and Pull Requests, or donate through PayPal or GitHub sponsors.
Thank you,