mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.2.5 RS485
This commit is contained in:
parent
da7349212d
commit
3fa1723780
@ -6,13 +6,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.2.5] - 2023-04-28
|
||||
- fix send / receive protocol bugs (as far as known)
|
||||
- add **RS485_master_send_receive.ino** demo
|
||||
- add **RS485_slave_send_receive.ino** demo
|
||||
- add **RS485_sniffer.ino** debug tool
|
||||
- add **EXPERIMENTAL** SoftwareSerial examples.
|
||||
- update examples.
|
||||
- move some code from .h to .cpp
|
||||
- update readme.md
|
||||
|
||||
|
||||
## [0.2.4] - 2023-02-05
|
||||
- update readme.md
|
||||
- added messages.md to give som ideas about handshakes/protocols.
|
||||
- update GitHub actions
|
||||
- update license 2023
|
||||
|
||||
|
||||
## [0.2.3] - 2022-11-23
|
||||
- add changelog.md
|
||||
- add RP2040 to build-CI
|
||||
|
@ -1,13 +1,30 @@
|
||||
|
||||
# Messages
|
||||
|
||||
Examples of command/answer protocols.
|
||||
Examples of command/answer protocols over RS485.
|
||||
(to be elaborated)
|
||||
|
||||
This is part of the RS485 class - https://github.com/RobTillaart/RS485
|
||||
|
||||
|
||||
#### Guidelines
|
||||
|
||||
Designing a protocol is most often not trivial and might need more
|
||||
than one iteration.
|
||||
|
||||
- Keep protocols as simple as possible.
|
||||
- be aware of implications of future expansion.
|
||||
- Make sure that baud rates match between the nodes in the network.
|
||||
- Software Serial can work when time between requests is long enough.
|
||||
It depends on how much processing is needed.
|
||||
- Be aware of implications of future expansion.
|
||||
Design your protocol with room for additional commands.
|
||||
Or even a version number in it.
|
||||
- In designing a protocol be aware of ambiguities.
|
||||
An request or answer may contain bytes (sequences)
|
||||
that might trigger other nodes.
|
||||
- If you request data from a node, it might happen
|
||||
that it won't answer or that the answer fails to
|
||||
arrive in correct state (missing bytes, flipped bits etc.)
|
||||
|
||||
|
||||
#### ASCII codes
|
||||
@ -24,6 +41,7 @@ Possible useful char codes.
|
||||
| NAK | 0x15 | Not Acknowledge
|
||||
| CAN | 0x18 | CANcel
|
||||
|
||||
See also **ASCII_CONTROL.h**
|
||||
|
||||
|
||||
----
|
||||
@ -42,10 +60,11 @@ requirement:
|
||||
- All devices listen to a disjunct command set.
|
||||
|
||||
|
||||
----
|
||||
|
||||
## example 2
|
||||
|
||||
using a device id to send the command to.
|
||||
Using a device id to send the command to.
|
||||
|
||||
|
||||
command :=
|
||||
@ -60,9 +79,11 @@ answer :=
|
||||
bytes requested bytes (send them back)
|
||||
|
||||
|
||||
----
|
||||
|
||||
## example 3
|
||||
|
||||
command and answer have same layout.
|
||||
Command and answer have same layout.
|
||||
Uses device ID's to address specific device.
|
||||
|
||||
SOH start of header 0x01
|
||||
@ -76,6 +97,8 @@ optional extend with:
|
||||
EOT optional (end of transmission)
|
||||
|
||||
|
||||
----
|
||||
|
||||
## example 4
|
||||
|
||||
More complex package with multiple fields and crc per message.
|
||||
@ -99,8 +122,22 @@ More complex package with multiple fields and crc per message.
|
||||
|
||||
----
|
||||
|
||||
## example 5 (still alive)
|
||||
|
||||
Maybe most simple protocol, just send an ID,
|
||||
and if the slave is alive it responds with its ID.
|
||||
Think of it as the **PING** command
|
||||
|
||||
command = ID
|
||||
answer = ID
|
||||
|
||||
Could be embedded in other protocols too,
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
- binary protocols
|
||||
- example code
|
||||
|
||||
|
||||
|
@ -17,14 +17,39 @@ 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
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
#### Connection schema
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
```cpp
|
||||
@ -38,7 +63,8 @@ messages so the user must implement such on top of this class.
|
||||
The default device ID is 0 (typically master uses this, or if deviceID is not used).
|
||||
The stream is typically Serial, and the baud rate, timeout etc. should be set
|
||||
via the Serial class.
|
||||
The sendPin is the pin that connects to the transmit/receive enable pins.
|
||||
The sendPin is the pin that connects to the transmit/receive enable (DE/RE) pins.
|
||||
See connection schema above.
|
||||
The library sets the pinMode and defaults it to LOW (receiving mode).
|
||||
- **void setMicrosPerByte(uint32_t baudRate)** set the delay per character needed.
|
||||
This gives the hardware enough time to flush the buffer.
|
||||
@ -67,6 +93,27 @@ An important command from the stream interface is the **setTimeOut()** as
|
||||
this allows reads on the RS485 bus that are limited.
|
||||
|
||||
|
||||
#### Experimental
|
||||
|
||||
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:
|
||||
- **void send(uint8_t receiverID, uint8_t msg[], uint8_t len)**
|
||||
- send a buffer of given length to a receiver.
|
||||
- **bool receive(uint8_t &senderID, uint8_t msg[], uint8_t &len)**
|
||||
- receive a packet, senderID identifies the sender.
|
||||
|
||||
Current implementation limits messages up to 48 bytes (hardcoded buffer size)
|
||||
which is in many cases enough.
|
||||
|
||||
See two example sketches.
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
A RS485 controlled device is typically waiting for a command or message
|
||||
@ -76,6 +123,14 @@ chip in sending mode, wait for enough time to "flush the buffer" and
|
||||
resumes with listening.
|
||||
|
||||
|
||||
#### Sniffer hex dump
|
||||
|
||||
Since 0.2.5 an example is added that snifs the bytes on the RS485 bus
|
||||
and prints them as a HEX dump.
|
||||
|
||||
Can be used for debugging.
|
||||
|
||||
|
||||
#### Pull up resistors
|
||||
|
||||
Do not forget to use one pull up (A line) and one pull down (B line)
|
||||
@ -104,7 +159,9 @@ so the function can call **yield()** every 4 milliseconds if enabled.
|
||||
|
||||
To enable **yield()** uncomment the following line in **RS485.cpp**
|
||||
|
||||
```cpp
|
||||
// #define RS485_YIELD_ENABLE 1
|
||||
```
|
||||
|
||||
or set this flag in the command line compile option.
|
||||
|
||||
@ -142,20 +199,30 @@ Would allow 127 different 1 byte commands.
|
||||
|
||||
- improve documentation
|
||||
|
||||
|
||||
#### Should
|
||||
|
||||
- setUsPerByte() parameter does not feel 100% (investigate)
|
||||
- improve **send()** and **receive()** for longer messages.
|
||||
- should be a message class.
|
||||
- extract from this lib (for now in the library).
|
||||
- dynamic receive buffer size?
|
||||
- investigate error handling?
|
||||
- expand write to other data types?
|
||||
- test other platforms
|
||||
- ESP32.
|
||||
|
||||
|
||||
#### Could
|
||||
|
||||
- add **send()** and **receive()** for longer messages.
|
||||
- which handshake?
|
||||
- dynamic buffer size?
|
||||
- should this be a sort of message class / struct. fixed size?
|
||||
- add examples
|
||||
- setUsPerByte() parameter does not feel 100% (investigate)
|
||||
- rename to begin().
|
||||
- improve the examples.
|
||||
- add binary protocol example
|
||||
- multi-master?
|
||||
- add unit tests
|
||||
- investigate yield() on ESP32/RTOS behaviour
|
||||
|
||||
|
||||
#### Wont
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// FILE: RS485.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 30-okt-2017
|
||||
// VERSION: 0.2.4
|
||||
// VERSION: 0.2.5
|
||||
// PURPOSE: Arduino library for RS485 modules (MAX485)
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
@ -24,6 +24,37 @@ RS485::RS485(Stream * stream, uint8_t sendPin, uint8_t deviceID)
|
||||
}
|
||||
|
||||
|
||||
// 0.3.0
|
||||
// void RS485::begin(uint32_t baudRate)
|
||||
// {
|
||||
// _stream->begin(baudRate);
|
||||
// setMicrosPerByte(baudRate);
|
||||
// }
|
||||
|
||||
|
||||
void RS485::setMicrosPerByte(uint32_t baudRate)
|
||||
{
|
||||
// count 11 bits time per byte
|
||||
_microsPerByte = (11 * 1000000) / baudRate ;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RS485::getMicrosPerByte()
|
||||
{
|
||||
return _microsPerByte;
|
||||
}
|
||||
|
||||
|
||||
uint8_t RS485::getDeviceID()
|
||||
{
|
||||
return _deviceID;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// STREAM INTERFACE
|
||||
//
|
||||
int RS485::available()
|
||||
{
|
||||
return _stream->available();
|
||||
@ -102,17 +133,10 @@ size_t RS485::write(uint8_t * array, uint8_t length)
|
||||
#endif
|
||||
|
||||
|
||||
void RS485::setMicrosPerByte(uint32_t baudRate)
|
||||
{
|
||||
// count 11 bits / byte
|
||||
_microsPerByte = (11 * 1000000UL) / baudRate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// EXPERIMENTAL - to be tested - use at own risk.
|
||||
// EXPERIMENTAL - use at own risk.
|
||||
//
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
@ -170,15 +194,17 @@ void RS485::send(uint8_t receiverID, uint8_t msg[], uint8_t len)
|
||||
bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
|
||||
{
|
||||
static uint8_t state = 0;
|
||||
static uint8_t sender = 255; // unknown / anonymous.
|
||||
static uint8_t length = 0;
|
||||
static bool forMe = false;
|
||||
uint8_t CHKSUM = 0;
|
||||
static uint8_t CHKSUM = 0;
|
||||
|
||||
if (_stream->available() == 0) return false;
|
||||
|
||||
uint8_t v = _stream->read();
|
||||
// if (debug) Serial.print(v, HEX);
|
||||
// Serial.print(state, HEX);
|
||||
// Serial.print('\t');
|
||||
// Serial.println(v, HEX);
|
||||
|
||||
switch(state)
|
||||
{
|
||||
@ -187,6 +213,7 @@ bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
|
||||
if (v == SOH)
|
||||
{
|
||||
_bidx = 0; // start new packet
|
||||
CHKSUM = 0;
|
||||
state = 1;
|
||||
}
|
||||
break;
|
||||
@ -200,14 +227,15 @@ bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
|
||||
|
||||
// extract sender
|
||||
case 2:
|
||||
sender = v;
|
||||
senderID = v;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
// extract length
|
||||
case 3:
|
||||
msglen = v;
|
||||
state = 3;
|
||||
length = v;
|
||||
state = 4;
|
||||
break;
|
||||
|
||||
// expect STX
|
||||
@ -220,7 +248,16 @@ bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
|
||||
case 5:
|
||||
if (length == 0)
|
||||
{
|
||||
state = 6;
|
||||
// expect checksum
|
||||
if (CHKSUM == v) state = 6;
|
||||
else
|
||||
{
|
||||
// debug failing checksum
|
||||
// Serial.print(CHKSUM, HEX);
|
||||
// Serial.print('\t');
|
||||
// Serial.println(v, HEX);
|
||||
state = 99; // for debug change to state = 6;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// error handling if v not ASCII ?
|
||||
@ -229,31 +266,25 @@ bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
|
||||
length--;
|
||||
break;
|
||||
|
||||
// expect checksum
|
||||
// expect ETX
|
||||
case 6:
|
||||
if (CHKSUM == v) state = 7;
|
||||
else state = 99;
|
||||
break;
|
||||
|
||||
// expect STX
|
||||
case 7:
|
||||
if (v == STX) state = 8;
|
||||
if (v == ETX) state = 7;
|
||||
else state = 99;
|
||||
break;
|
||||
|
||||
// expect EOT
|
||||
case 8:
|
||||
case 7:
|
||||
if (v == EOT)
|
||||
{
|
||||
senderID = sender;
|
||||
msglen = _bidx -1;
|
||||
msglen = _bidx;
|
||||
for (int i = 0; i < msglen; i++)
|
||||
{
|
||||
msg[i] = _buffer[i];
|
||||
}
|
||||
state = 0;
|
||||
return true;
|
||||
}
|
||||
state = 0;
|
||||
state = 99;
|
||||
break;
|
||||
|
||||
// SKIP until next packet
|
||||
@ -266,6 +297,7 @@ bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
|
@ -3,7 +3,7 @@
|
||||
// FILE: RS485.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 30-okt-2017
|
||||
// VERSION: 0.2.4
|
||||
// VERSION: 0.2.5
|
||||
// PURPOSE: Arduino library for RS485 modules
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
#include "Arduino.h"
|
||||
#include "ASCII_CONTROL.h"
|
||||
|
||||
#define RS485_LIB_VERSION (F("0.2.4"))
|
||||
#define RS485_LIB_VERSION (F("0.2.5"))
|
||||
|
||||
|
||||
class RS485 : public Stream
|
||||
@ -19,13 +19,18 @@ class RS485 : public Stream
|
||||
public:
|
||||
RS485(Stream * stream, uint8_t sendPin, uint8_t deviceID = 0);
|
||||
|
||||
// sets the baud rate of the stream.
|
||||
// 0.3.0
|
||||
// void begin(uint32_t baudRate);
|
||||
|
||||
// baudRate must match Serial baudRate
|
||||
// micros are needed before RS485 stream may be reset
|
||||
// to (default) receiving mode.
|
||||
void setMicrosPerByte(uint32_t baudRate);
|
||||
uint32_t getMicrosPerByte() { return _microsPerByte; };
|
||||
uint32_t getMicrosPerByte();
|
||||
|
||||
uint8_t getDeviceID();
|
||||
|
||||
uint8_t getDeviceID() { return _deviceID; };
|
||||
|
||||
// Stream interface
|
||||
int available();
|
||||
@ -33,23 +38,23 @@ public:
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
|
||||
// Write
|
||||
size_t write(uint8_t c);
|
||||
size_t write(char * array, uint8_t length); // wrapper
|
||||
size_t write(uint8_t * array, uint8_t length);
|
||||
|
||||
|
||||
// Mode functions
|
||||
inline void setTXmode() { digitalWrite(_sendPin, HIGH); };
|
||||
inline void setRXmode() { digitalWrite(_sendPin, LOW); };
|
||||
uint8_t getMode() { return digitalRead(_sendPin) == HIGH; };
|
||||
|
||||
|
||||
// 0.3.0 EXPERIMENTAL
|
||||
// EXPERIMENTAL - use at own risk.- (for 0.3.0)
|
||||
// send ASCII encoded messages from one master to multiple clients.
|
||||
// msg[] = 32..127
|
||||
// len = 1..48 ?
|
||||
//
|
||||
// should be a p2p network option.
|
||||
// len = 1..48 ?
|
||||
void send(uint8_t receiverID, uint8_t msg[], uint8_t len);
|
||||
bool receive(uint8_t &senderID, uint8_t msg[], uint8_t &len);
|
||||
|
||||
@ -60,9 +65,9 @@ private:
|
||||
uint8_t _deviceID = 0;
|
||||
uint16_t _microsPerByte = 1000;
|
||||
|
||||
// 0.3.0
|
||||
// EXPERIMENTAL (for 0.3.0)
|
||||
uint8_t _bidx = 0;
|
||||
uint8_t _buffer[50]; // internal receive buffer
|
||||
uint8_t _buffer[50]; // internal receive buffer
|
||||
};
|
||||
|
||||
|
||||
|
@ -0,0 +1,29 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
# selected only those that work
|
||||
platforms:
|
||||
# - uno
|
||||
# - due
|
||||
# - zero
|
||||
# - leonardo
|
||||
# - m4
|
||||
# - esp32
|
||||
# - esp8266
|
||||
- mega2560
|
||||
# - rpipico
|
||||
|
@ -0,0 +1,83 @@
|
||||
// FILE: RS485_MEGA_master_send_receive.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo master of send / receive
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// This is the code for a master (to be used with slave example)
|
||||
// Best is it to use on a MEGA or another board with multiple hardware Serials.
|
||||
// The master should be connected with two slaves
|
||||
// slave 2 is requested for temperature
|
||||
// slave 1 is requested for humidity
|
||||
//
|
||||
// Note that Serial is used for debugging messages, so better use
|
||||
// a 2nd Serial for the RS485 bus.
|
||||
// otherwise some binary messages will show up in the Serial monitor.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 0;
|
||||
|
||||
|
||||
// use a 2nd Serial port.
|
||||
RS485 rs485(&Serial2, sendPin, deviceID);
|
||||
|
||||
|
||||
// times of last requests.
|
||||
uint32_t lastT = 0;
|
||||
uint32_t lastH = 0;
|
||||
|
||||
|
||||
// for receiving (must be global)
|
||||
uint8_t ID;
|
||||
uint8_t arr[32];
|
||||
uint8_t len;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
Serial2.begin(38400);
|
||||
rs485.setMicrosPerByte(38400);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (millis() - lastT >= 3000)
|
||||
{
|
||||
lastT = millis();
|
||||
char msg[] = "Get Temperature";
|
||||
rs485.send(1, (uint8_t *)msg, strlen(msg));
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(msg);
|
||||
}
|
||||
|
||||
if (millis() - lastH >= 7000)
|
||||
{
|
||||
lastH = millis();
|
||||
char msg[] = "Get Humidity";
|
||||
rs485.send(1, (uint8_t *)msg, strlen(msg));
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(msg);
|
||||
}
|
||||
|
||||
if (rs485.receive(ID, arr, len))
|
||||
{
|
||||
arr[len] = 0;
|
||||
Serial.print("RECV:\t");
|
||||
Serial.print(ID);
|
||||
Serial.print("\t");
|
||||
Serial.println((char*) arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,29 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
# selected only those that work
|
||||
platforms:
|
||||
# - uno
|
||||
# - due
|
||||
# - zero
|
||||
# - leonardo
|
||||
# - m4
|
||||
# - esp32
|
||||
# - esp8266
|
||||
- mega2560
|
||||
# - rpipico
|
||||
|
@ -0,0 +1,71 @@
|
||||
// FILE: RS485_MEGA_slave_send_receive.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo slave of send / receive
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// This is the code for a slave (to be used with master example)
|
||||
// Best is it to use on a MEGA or another board with multiple hardware Serials.
|
||||
// The master should be connected with two slaves
|
||||
// slave 2 is waiting for temperature requests.
|
||||
// slave 1 is waiting for humidity requests.
|
||||
//
|
||||
// Note that Serial is used for debugging messages, so better use
|
||||
// a 2nd Serial for the RS485 bus.
|
||||
// otherwise some binary messages will show up in the Serial monitor.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 1;
|
||||
|
||||
|
||||
// use a 2nd Serial port.
|
||||
RS485 rs485(&Serial2, sendPin, deviceID);
|
||||
|
||||
|
||||
// for receiving (must be global)
|
||||
uint8_t ID;
|
||||
uint8_t buffer[32];
|
||||
uint8_t len;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
Serial2.begin(38400);
|
||||
rs485.setMicrosPerByte(38400);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (rs485.receive(ID, buffer, len))
|
||||
{
|
||||
buffer[len] = 0;
|
||||
Serial.print("RECV: ");
|
||||
Serial.println((char*) buffer);
|
||||
|
||||
if (strcmp((char*)buffer, "Get Humidity") == 0)
|
||||
{
|
||||
int humidity = 50 + random(10);
|
||||
sprintf((char*)buffer, "HUM: %d", humidity);
|
||||
rs485.send(ID, buffer, strlen((char*)buffer));
|
||||
}
|
||||
if (strcmp((char*)buffer, "Get Temperature") == 0)
|
||||
{
|
||||
int temperature = 15 + random(10);
|
||||
sprintf((char*)buffer, "TEM: %d", temperature);
|
||||
rs485.send(ID, buffer, strlen((char*)buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,29 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
# selected only those that work
|
||||
platforms:
|
||||
- uno
|
||||
# - due
|
||||
# - zero
|
||||
# - leonardo
|
||||
# - m4
|
||||
# - esp32
|
||||
- esp8266
|
||||
# - mega2560
|
||||
- rpipico
|
||||
|
@ -0,0 +1,86 @@
|
||||
// FILE: RS485_SWS_master_send_receive.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo master of send / receive
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// VERY EXPERIMENTAL
|
||||
|
||||
// This is the code for a master (to be used with slave example)
|
||||
// Best is it to use on a MEGA or another board with multiple hardware Serials.
|
||||
// The master should be connected with two slaves
|
||||
// slave 2 is requested for temperature
|
||||
// slave 1 is requested for humidity
|
||||
//
|
||||
// Note that Serial is used for debugging messages, so better use
|
||||
// a 2nd Serial for the RS485 bus.
|
||||
// otherwise some binary messages will show up in the Serial monitor.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 0;
|
||||
|
||||
SoftwareSerial SWS(6,7); // RX, TX
|
||||
|
||||
|
||||
// use Software Serial
|
||||
RS485 rs485(&SWS, sendPin, deviceID);
|
||||
|
||||
|
||||
// times of last requests.
|
||||
uint32_t lastT = 0;
|
||||
uint32_t lastH = 2000;
|
||||
|
||||
|
||||
// for receiving (must be global)
|
||||
uint8_t ID;
|
||||
uint8_t buffer[32];
|
||||
uint8_t len;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
SWS.begin(38400);
|
||||
|
||||
rs485.setMicrosPerByte(38400);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (millis() - lastT >= 5000)
|
||||
{
|
||||
lastT = millis();
|
||||
char msg[] = "Get Temperature";
|
||||
rs485.send(2, (uint8_t *)msg, strlen(msg));
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(msg);
|
||||
}
|
||||
|
||||
if (millis() - lastH >= 5000)
|
||||
{
|
||||
lastH = millis();
|
||||
char msg[] = "Get Humidity";
|
||||
rs485.send(1, (uint8_t *)msg, strlen(msg));
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(msg);
|
||||
}
|
||||
|
||||
if (rs485.receive(ID, buffer, len))
|
||||
{
|
||||
buffer[len] = 0;
|
||||
Serial.print("RECV: ");
|
||||
Serial.println((char*) buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,29 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
# selected only those that work
|
||||
platforms:
|
||||
- uno
|
||||
# - due
|
||||
# - zero
|
||||
# - leonardo
|
||||
# - m4
|
||||
# - esp32
|
||||
- esp8266
|
||||
# - mega2560
|
||||
- rpipico
|
||||
|
@ -0,0 +1,80 @@
|
||||
// FILE: RS485_slave_send_receive.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo slave of send / receive
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// VERY EXPERIMENTAL
|
||||
|
||||
// This is the code for a slave (to be used with master example)
|
||||
// Best is it to use on a MEGA or another board with multiple hardware Serials.
|
||||
// The master should be connected with two slaves
|
||||
// slave 2 is waiting for temperature requests.
|
||||
// slave 1 is waiting for humidity requests.
|
||||
//
|
||||
// Note that Serial is used for debugging messages, so better use
|
||||
// a 2nd Serial for the RS485 bus.
|
||||
// otherwise some binary messages will show up in the Serial monitor.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 1;
|
||||
|
||||
SoftwareSerial SWS(6,7); // RX, TX
|
||||
|
||||
|
||||
// use Software Serial
|
||||
RS485 rs485(&SWS, sendPin, deviceID);
|
||||
|
||||
|
||||
// for receiving (must be global)
|
||||
uint8_t ID;
|
||||
uint8_t buffer[32];
|
||||
uint8_t len;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
SWS.begin(38400);
|
||||
|
||||
rs485.setMicrosPerByte(38400);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (rs485.receive(ID, buffer, len))
|
||||
{
|
||||
buffer[len] = 0;
|
||||
Serial.print("RECV: ");
|
||||
Serial.println((char*) buffer);
|
||||
|
||||
if (strcmp((char*)buffer, "Get Humidity") == 0)
|
||||
{
|
||||
int humidity = 50 + random(10);
|
||||
sprintf((char*)buffer, "HUM: %d", humidity);
|
||||
rs485.send(ID, buffer, strlen((char*)buffer));
|
||||
// tidy up output
|
||||
Serial.println();
|
||||
}
|
||||
if (strcmp((char*)buffer, "Get Temperature") == 0)
|
||||
{
|
||||
int temperature = 15 + random(10);
|
||||
sprintf((char*)buffer, "TEM: %d", temperature);
|
||||
rs485.send(ID, buffer, strlen((char*)buffer));
|
||||
// tidy up output
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,83 @@
|
||||
// FILE: RS485_master_send_receive.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo master of send / receive
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// This is the code for a master (to be used with slave example)
|
||||
// Best is it to use on a MEGA or another board with multiple hardware Serials.
|
||||
// The master should be connected with two slaves
|
||||
// slave 2 is requested for temperature
|
||||
// slave 1 is requested for humidity
|
||||
//
|
||||
// Note that Serial is used for debugging messages, so better use
|
||||
// a 2nd Serial for the RS485 bus.
|
||||
// otherwise some binary messages will show up in the Serial monitor.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 0;
|
||||
|
||||
|
||||
// use a 2nd Serial port.
|
||||
RS485 rs485(&Serial, sendPin, deviceID);
|
||||
|
||||
|
||||
// times of last requests.
|
||||
uint32_t lastT = 0;
|
||||
uint32_t lastH = 0;
|
||||
|
||||
|
||||
// for receiving (must be global)
|
||||
uint8_t ID;
|
||||
uint8_t arr[32];
|
||||
uint8_t len;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(38400);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
rs485.setMicrosPerByte(38400);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (millis() - lastT >= 3000)
|
||||
{
|
||||
lastT = millis();
|
||||
char msg[] = "Get Temperature";
|
||||
rs485.send(1, (uint8_t *)msg, strlen(msg));
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(msg);
|
||||
}
|
||||
|
||||
if (millis() - lastH >= 7000)
|
||||
{
|
||||
lastH = millis();
|
||||
char msg[] = "Get Humidity";
|
||||
rs485.send(1, (uint8_t *)msg, strlen(msg));
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(msg);
|
||||
}
|
||||
|
||||
if (rs485.receive(ID, arr, len))
|
||||
{
|
||||
arr[len] = 0;
|
||||
Serial.print("RECV:\t");
|
||||
Serial.print(ID);
|
||||
Serial.print("\t");
|
||||
Serial.println((char*) arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -3,13 +3,18 @@
|
||||
// PURPOSE: simple performance test for write(array, length)
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// minimal test to see how fast data can be send over the
|
||||
// RS485 bus at a given baud rate of 4800. (adjust if needed).
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
RS485 rs485(&Serial, 4); // uses default deviceID
|
||||
|
||||
RS485 rs485(&Serial, 4); // uses default deviceID 0
|
||||
|
||||
uint32_t start, stop = 0;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(4800);
|
||||
@ -17,8 +22,11 @@ void setup()
|
||||
// Serial.println(__FILE__);
|
||||
|
||||
test(4800);
|
||||
|
||||
Serial.println("\ndone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
@ -26,13 +34,18 @@ void loop()
|
||||
|
||||
void test(uint32_t baudrate)
|
||||
{
|
||||
delay(10);
|
||||
char buffer[64] = "123456789012345678901234567890123456789012345678901234567890";
|
||||
rs485.setMicrosPerByte(baudrate);
|
||||
start = micros();
|
||||
rs485.write((uint8_t *)buffer, 60);
|
||||
stop = micros();
|
||||
Serial.print("\nTIME: ");
|
||||
Serial.print("BAUD:\t");
|
||||
Serial.print(baudrate);
|
||||
Serial.print("\tTIME: ");
|
||||
Serial.println(stop - start);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -3,16 +3,31 @@
|
||||
// PURPOSE: simple master
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// this is the code of a simple master (needs simple slave)
|
||||
// it send one of 3 (single char) commands to the slave
|
||||
// '0' == set LED LOW
|
||||
// '1' == set LED HIGH
|
||||
// '2' == request status.
|
||||
//
|
||||
// print debug messages SEND and RECV with data.
|
||||
// Note that one needs a 2nd Serial port for nice debugging.
|
||||
// (or an LCD screen whatever).
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 0;
|
||||
|
||||
|
||||
RS485 rs485(&Serial, sendPin); // uses default deviceID
|
||||
|
||||
|
||||
uint32_t lastCommand = 0;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
@ -22,20 +37,25 @@ void setup()
|
||||
rs485.setMicrosPerByte(115200);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (millis() - lastCommand >= 2000)
|
||||
{
|
||||
lastCommand = millis();
|
||||
char cmd = random(3); // 0,1,2
|
||||
char cmd = '0' + random(3); // sends 0, 1, 2 as character (not as value)
|
||||
rs485.print(cmd);
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(cmd);
|
||||
}
|
||||
if (rs485.available() > 0)
|
||||
{
|
||||
int status = rs485.read();
|
||||
Serial.print("RECV: ");
|
||||
Serial.println(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -3,17 +3,32 @@
|
||||
// PURPOSE: simple listening slave
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// this is the code of a simple slave (needs simple master)
|
||||
// it receives one of 3 (single char) commands to the slave
|
||||
// '0' == set LED LOW.
|
||||
// '1' == set LED HIGH.
|
||||
// '2' == return status to master.
|
||||
//
|
||||
// print debug messages SEND and RECV with data.
|
||||
// Note that one needs a 2nd Serial port for nice debugging.
|
||||
// (or an LCD screen whatever).
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 1;
|
||||
|
||||
|
||||
RS485 rs485(&Serial, sendPin, deviceID);
|
||||
|
||||
|
||||
const uint8_t LED = 13;
|
||||
uint8_t status = LOW;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
@ -26,17 +41,27 @@ void setup()
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (rs485.available() > 0)
|
||||
{
|
||||
int c = rs485.read();
|
||||
Serial.print("RECV: ");
|
||||
Serial.println(c);
|
||||
|
||||
if (c == '0') status = LOW;
|
||||
if (c == '1') status = HIGH;
|
||||
if (c == '2') rs485.print(status);
|
||||
if (c == '2')
|
||||
{
|
||||
Serial.print("SEND: ");
|
||||
Serial.println(status);
|
||||
rs485.print(status);
|
||||
}
|
||||
digitalWrite(LED, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
// FILE: RS485_slave_send_receive.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo slave of send / receive
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// This is the code for a slave (to be used with master example)
|
||||
// Best is it to use on a MEGA or another board with multiple hardware Serials.
|
||||
// The master should be connected with two slaves
|
||||
// slave 2 is waiting for temperature requests.
|
||||
// slave 1 is waiting for humidity requests.
|
||||
//
|
||||
// Note that Serial is used for debugging messages, so better use
|
||||
// a 2nd Serial for the RS485 bus.
|
||||
// otherwise some binary messages will show up in the Serial monitor.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4;
|
||||
const uint8_t deviceID = 1;
|
||||
|
||||
|
||||
// use a 2nd Serial port.
|
||||
RS485 rs485(&Serial, sendPin, deviceID);
|
||||
|
||||
|
||||
// for receiving (must be global)
|
||||
uint8_t ID;
|
||||
uint8_t buffer[32];
|
||||
uint8_t len;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(38400);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
rs485.setMicrosPerByte(38400);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (rs485.receive(ID, buffer, len))
|
||||
{
|
||||
buffer[len] = 0;
|
||||
// Serial.print("RECV: ");
|
||||
// Serial.println((char*) buffer);
|
||||
if (strcmp((char*)buffer, "Get Humidity") == 0)
|
||||
{
|
||||
int humidity = 50 + random(10);
|
||||
sprintf((char*)buffer, "HUM: %d", humidity);
|
||||
rs485.send(ID, buffer, strlen((char*)buffer));
|
||||
}
|
||||
if (strcmp((char*)buffer, "Get Temperature") == 0)
|
||||
{
|
||||
int temperature = 15 + random(10);
|
||||
sprintf((char*)buffer, "TEM: %d", temperature);
|
||||
rs485.send(ID, buffer, strlen((char*)buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
90
libraries/RS485/examples/RS485_sniffer/RS485_sniffer.ino
Normal file
90
libraries/RS485/examples/RS485_sniffer/RS485_sniffer.ino
Normal file
@ -0,0 +1,90 @@
|
||||
// FILE: RS485_sniffer.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: simple sniffer prints data as hex dump
|
||||
// URL: https://github.com/RobTillaart/RS485
|
||||
|
||||
// use a 2nd Serial port.
|
||||
// or only connect the RX of the MAX485.
|
||||
//
|
||||
// Note this sniffer if not 100% fool proof, known issues are
|
||||
// - no detection of buffer overrun etc
|
||||
// - ASCII output is only printed after 16 bytes are decoded.
|
||||
// - still might be useful for debugging.
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "RS485.h"
|
||||
|
||||
|
||||
const uint8_t sendPin = 4; // not used, listening only.
|
||||
const uint8_t deviceID = 250; // not used, maybe in future.
|
||||
|
||||
|
||||
// use a 2nd Serial port.
|
||||
// or only connect the RX of the MAX485.
|
||||
RS485 rs485(&Serial, sendPin, deviceID);
|
||||
|
||||
|
||||
const uint8_t LED = 13;
|
||||
uint8_t status = LOW;
|
||||
|
||||
uint32_t count = 0;
|
||||
|
||||
char buffer[17];
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
rs485.setMicrosPerByte(115200);
|
||||
|
||||
pinMode(LED, OUTPUT);
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (rs485.available() > 0)
|
||||
{
|
||||
// toggle on receive
|
||||
digitalWrite(LED, !digitalRead(LED));
|
||||
|
||||
if (count % 4 == 0)
|
||||
{
|
||||
Serial.print(' ');
|
||||
}
|
||||
if (count % 16 == 0)
|
||||
{
|
||||
Serial.print(" ");
|
||||
Serial.println(buffer);
|
||||
if (count % 160 == 0)
|
||||
{
|
||||
Serial.println();
|
||||
}
|
||||
Serial.print(count, HEX);
|
||||
Serial.print('\t');
|
||||
}
|
||||
|
||||
|
||||
int x = rs485.read();
|
||||
|
||||
// HEX DUMP PART
|
||||
if (x < 0x10) Serial.print('0');
|
||||
Serial.print(x, HEX);
|
||||
Serial.print(" ");
|
||||
|
||||
// fill ASCII buffer
|
||||
buffer[count % 16] = isprint(x) ? x : '.';
|
||||
buffer[count % 16 + 1] = 0;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/RS485"
|
||||
},
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.5",
|
||||
"license": "MIT",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=RS485
|
||||
version=0.2.4
|
||||
version=0.2.5
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=RS485 library for Arduino.
|
||||
|
Loading…
Reference in New Issue
Block a user