0.4.0 RS485

This commit is contained in:
Rob Tillaart 2023-12-18 11:35:35 +01:00
parent 623a49ac56
commit 5c04d36920
11 changed files with 393 additions and 23 deletions

View File

@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.4.0] - 2023-12-18
- fix **write(array, length)**
- add two examples (ack_nack + controller)
- updated experimental protocol, still experimental
- update readme.md
- minor edits
----
## [0.3.0] - 2023-12-05
- Fix #15 - use flush() instead of calculation.
- remove **setMicrosPerByte()** and **getMicrosPerByte()**

View File

@ -113,15 +113,21 @@ 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)**
- **size_t 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.
Two wrappers:
- **size_t send(uint8_t receiverID, char msg[], uint8_t len)**
- send a buffer of given length to a receiver.
- **bool receive(uint8_t &senderID, char 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.
See example sketches.
## Operation

View File

@ -2,7 +2,7 @@
// FILE: RS485.cpp
// AUTHOR: Rob Tillaart
// DATE: 30-okt-2017
// VERSION: 0.3.0
// VERSION: 0.4.0
// PURPOSE: Arduino library for RS485 modules (MAX485)
// URL: https://github.com/RobTillaart/RS485
@ -20,7 +20,8 @@ RS485::RS485(Stream * stream, uint8_t sendPin, uint8_t deviceID)
_deviceID = deviceID;
pinMode(_sendPin, OUTPUT);
setRXmode(); // receiver mode ==> _sendPin == LOW
// default receiver mode ==> _sendPin == LOW
setRXmode();
}
@ -87,12 +88,14 @@ size_t RS485::write(char * array, uint8_t length)
// smallest and slightly fastest.
size_t RS485::write(uint8_t * array, uint8_t length)
{
uint8_t n = 0;
setTXmode(); // transmit mode
size_t n = 0;
for (uint8_t i = 0; i < length; i++)
{
n += _stream->write(array[i]);
yield();
}
setRXmode(); // receiver mode
return n;
}
@ -146,25 +149,29 @@ size_t RS485::write(uint8_t * array, uint8_t length)
// EOT end of transmission
//
void RS485::send(uint8_t receiverID, uint8_t msg[], uint8_t len)
size_t RS485::send(uint8_t receiverID, uint8_t msg[], uint8_t len)
{
size_t n = 0;
uint8_t CHKSUM = 0;
setTXmode(); // transmit mode
_stream->write(SOH);
_stream->write(receiverID); // TO
_stream->write(_deviceID); // FROM
_stream->write(len); // LENGTH BODY
_stream->write(STX);
n += _stream->write(receiverID); // TO
n += _stream->write(_deviceID); // FROM
n += _stream->write(len); // LENGTH BODY
n += _stream->write(STX);
for (int i = 0; i < len; i++)
{
_stream->write(msg[i]);
n += _stream->write(msg[i]);
CHKSUM ^= msg[i]; // Simple XOR checksum.
}
_stream->write(CHKSUM);
_stream->write(ETX);
_stream->write(EOT);
n += _stream->write(CHKSUM);
n += _stream->write(ETX);
n += _stream->write(EOT);
_stream->flush();
setRXmode(); // receive mode
return n;
}
@ -276,6 +283,17 @@ bool RS485::receive(uint8_t &senderID, uint8_t msg[], uint8_t &msglen)
}
size_t RS485::send(uint8_t receiverID, char msg[], uint8_t len)
{
return send(receiverID, (uint8_t *)msg, len);
}
bool RS485::receive(uint8_t &senderID, char msg[], uint8_t &len)
{
return receive(senderID, (uint8_t*) msg, len);
}
//////////////////////////////////////////////////
//

View File

@ -3,7 +3,7 @@
// FILE: RS485.h
// AUTHOR: Rob Tillaart
// DATE: 30-okt-2017
// VERSION: 0.3.0
// VERSION: 0.4.0
// 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.3.0"))
#define RS485_LIB_VERSION (F("0.4.0"))
class RS485 : public Stream
@ -41,14 +41,19 @@ public:
uint8_t getMode() { return digitalRead(_sendPin) == HIGH; };
// EXPERIMENTAL
// - use at own risk.- (for 0.3.0)
// EXPERIMENTAL
// - in a derived class?
// - use at own risk
// send ASCII encoded messages from one master to multiple clients.
// msg[] = 32..127
// len = 1..48 ?
void send(uint8_t receiverID, uint8_t msg[], uint8_t len);
// len = 1.. 48 (internal receive buffer is 50)
size_t send(uint8_t receiverID, uint8_t msg[], uint8_t len);
bool receive(uint8_t &senderID, uint8_t msg[], uint8_t &len);
// EXPERIMENTAL
size_t send(uint8_t receiverID, char msg[], uint8_t len);
bool receive(uint8_t &senderID, char msg[], uint8_t &len);
private:
Stream * _stream;
@ -56,7 +61,7 @@ private:
uint8_t _deviceID = 0;
uint16_t _microsPerByte = 1000;
// EXPERIMENTAL (for 0.3.x)
// EXPERIMENTAL
uint8_t _bidx = 0;
uint8_t _buffer[50]; // internal receive buffer
};

View File

@ -0,0 +1,68 @@
// FILE: RS485_master_ACK_NACK.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// 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 one slave e.g. an UNO
//
// The application is (too) simple,
// if the slave receives a printable char it returns an ACK
// else an NACK
#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);
RS485 rs485(&Serial, sendPin, deviceID);
void setup()
{
Serial.begin(38400);
while (!Serial);
Serial.println();
Serial.println(__FILE__);
Serial.print("RS485_LIB_VERSION: ");
Serial.println(RS485_LIB_VERSION);
}
void loop()
{
if (Serial.available())
{
char c = Serial.read();
rs485.setTXmode();
rs485.write(c);
rs485.setRXmode();
}
if (rs485.available())
{
uint8_t answer = rs485.read();
switch (answer)
{
case ACK:
Serial.println(" ACK");
break;
case NAK:
Serial.println(" NAK");
break;
default:
Serial.print("0x");
if (answer < 16) Serial.print("0");
Serial.println(answer, HEX);
break;
}
}
}
// -- END OF FILE --

View File

@ -0,0 +1,86 @@
// FILE: RS485_master_controller.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// 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 one slave e.g. an UNO
#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);
RS485 rs485(&Serial, sendPin, deviceID);
// 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__);
Serial.print("RS485_LIB_VERSION: ");
Serial.println(RS485_LIB_VERSION);
}
void loop()
{
if (Serial.available())
{
char c = Serial.read();
switch(c)
{
// digital read
case '2':
rs485.send(1, "DR2", 3);
break;
case '3':
rs485.send(1, "DR3", 3);
break;
case '4':
rs485.send(1, "DR4", 3);
break;
// digital write
case 'H':
rs485.send(1, "DW7H", 4);
break;
case 'L':
rs485.send(1, "DW7L", 4);
break;
// analog read
case 'A':
rs485.send(1, "AR0", 3);
break;
case 'B':
rs485.send(1, "AR1", 3);
break;
}
}
// 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 --

View File

@ -0,0 +1,57 @@
// FILE: RS485_slave_controller.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// 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 one slave e.g. an UNO
//
// The application is (too) simple,
// if the slave receives a printable char it returns an ACK
// else an NACK
#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);
RS485 rs485(&Serial, sendPin, deviceID);
void setup()
{
Serial.begin(38400);
while (!Serial);
Serial.println();
Serial.println(__FILE__);
Serial.print("RS485_LIB_VERSION: ");
Serial.println(RS485_LIB_VERSION);
}
void loop()
{
if (rs485.available())
{
char c = rs485.read();
if (isPrintable(c))
{
rs485.write(ACK);
}
else
{
rs485.write(NAK);
}
}
}
// -- END OF FILE --

View 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 # does not support A1 analog
# - mega2560
- rpipico

View File

@ -0,0 +1,92 @@
// FILE: RS485_slave_controller.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// 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 one slave e.g. an UNO
#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);
// 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__);
Serial.print("RS485_LIB_VERSION: ");
Serial.println(RS485_LIB_VERSION);
}
void loop()
{
if (rs485.receive(ID, buffer, len))
{
buffer[len] = 0;
// DIGITAL READ
if (strcmp((char*)buffer, "DR2") == 0)
{
int value = digitalRead(2);
sprintf((char*)buffer, "DR2: %d", value);
}
else if (strcmp((char*)buffer, "DR3") == 0)
{
int value = digitalRead(3);
sprintf((char*)buffer, "DR3: %d", value);
}
else if (strcmp((char*)buffer, "DR4") == 0)
{
int value = digitalRead(4);
sprintf((char*)buffer, "DR4: %d", value);
}
// DIGITAL WRITE
else if (strcmp((char*)buffer, "DW7H") == 0)
{
digitalWrite(7, HIGH);
sprintf((char*)buffer, "DW7: H");
}
else if (strcmp((char*)buffer, "DW7L") == 0)
{
digitalWrite(7, LOW);
sprintf((char*)buffer, "DW7: L");
}
// ANALOG READ
else if (strcmp((char*)buffer, "AR0") == 0)
{
int value = analogRead(A0);
sprintf((char*)buffer, "AR0: %d", value);
}
else if (strcmp((char*)buffer, "AR1") == 0)
{
int value = analogRead(A1);
sprintf((char*)buffer, "AR1: %d", value);
}
else
{
sprintf((char*)buffer, "INVALID");
}
rs485.send(ID, buffer, strlen((char*)buffer));
}
}
// -- END OF FILE --

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/RS485"
},
"version": "0.3.0",
"version": "0.4.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=RS485
version=0.3.0
version=0.4.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=RS485 library for Arduino.