0.2.3 RS485

This commit is contained in:
rob tillaart 2022-11-23 16:14:02 +01:00
parent b25fa79612
commit 13dd934f92
9 changed files with 252 additions and 137 deletions

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
# - mega2560
- rpipico

View File

@ -3,7 +3,6 @@
// FILE: ASCII_CONTROL.h
// AUTHOR: Rob Tillaart
// DATE: 2020-08-26
// VERSION: 0.1.0
// PURPOSE: ASCII control characters
// URL: https://github.com/RobTillaart/RS485
//

View File

@ -0,0 +1,30 @@
# Change Log RS485
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.3] - 2022-11-23
- add changelog.md
- add RP2040 to build-CI
- remove version from ASCII_CONTROL
- update keywords.txt
- minor edits
## [0.2.2] - 2022-05-25
- rewrite blocking write(uint8_t \* array, length).
- added write(char \* array, length). (convenience)
## [0.2.1] - 2022-05-24
- add setTXmode(), setRXmode(), getMode().
## [0.2.0] - 2022-05-24
- first published version
----
## [0.1.x] - 2017-10-30
- experimental versions.

View File

@ -108,10 +108,35 @@ on the baud rate. Use with care.
TODO: to be tested on ESP32 - RTOS .
#### Protocol design
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.
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).
#### Useful links
- https://www.ti.com/lit/an/snla049b/snla049b.pdf
- https://www.gammon.com.au/forum/?id=11428
- https://www.arduino.cc/reference/en/language/functions/communication/stream/
## Future
#### must
- improve documentation
- setUsPerByte() parameter does not feel 100%
#### should
- setUsPerByte() parameter does not feel 100% (investigate)
#### could
- add **send()** and **receive()** for longer messages.
- which handshake?
- dynamic buffer size?

View File

@ -2,16 +2,9 @@
// FILE: RS485.cpp
// AUTHOR: Rob Tillaart
// DATE: 30-okt-2017
// VERSION: 0.2.2
// VERSION: 0.2.3
// PURPOSE: Arduino library for RS485 modules (MAX485)
// URL: https://github.com/RobTillaart/RS485
//
// HISTORY:
// 0.1.x 2017-10-30 experimental versions.
// 0.2.0 2022-05-24 first published version
// 0.2.1 2022-05-24 add setTXmode(), setRXmode(), getMode().
// 0.2.2 2022-05-25 rewrite blocking write(uint8_t * array, length).
// added write(char * array, length). (convenience)
#include "RS485.h"
@ -36,21 +29,25 @@ int RS485::available()
return _stream->available();
}
int RS485::read()
{
return _stream->read();
}
int RS485::peek()
{
return _stream->peek();
}
void RS485::flush()
{
_stream->flush();
}
size_t RS485::write(uint8_t c)
{
setTXmode(); // transmit mode
@ -142,36 +139,38 @@ void RS485::setMicrosPerByte(uint32_t baudRate)
// message idem
// CHECKSUM idem, message only!
// ETX end of text
// EOT end of transmission
//
/*
void RS485::send(uint8_t deviceID, uint8_t msg[], uint8_t len)
void RS485::send(uint8_t receiverID, uint8_t msg[], uint8_t len)
{
uint8_t CHKSUM = 0;
digitalWrite(_enablePin, HIGH);
setTXmode(); // transmit mode
_stream->write(SOH);
_stream->write(deviceID); // TO
_stream->write(receiverID); // TO
_stream->write(_deviceID); // FROM
_stream->write(len); // LENGTH BODY
_stream->write(STX);
for (int i = 0; i < len; i++)
{
_stream->write(msg[i]);
CHKSUM ^= msg[i]; // TODO good for now => CRC8 ?
delayMicroseconds(_microsPerByte);
CHKSUM ^= msg[i]; // Simple XOR checksum.
}
_stream->write(CHKSUM);
delayMicroseconds(_microsPerByte);
_stream->write(ETX);
delayMicroseconds(_microsPerByte);
digitalWrite(_enablePin, LOW);
_stream->write(EOT);
delayMicroseconds((len + 8 + 2) * _microsPerByte); // + 2 to be sure...
setRXmode();
}
// returns true if complete message is captured.
// multiple calls needed as it should be non-blocking.
bool RS485::receive(uint8_t &deviceID, 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;
@ -179,68 +178,93 @@ bool RS485::receive(uint8_t &deviceID, uint8_t msg[], uint8_t &len)
if (_stream->available() == 0) return false;
uint8_t v = _stream->read();
// if (debug) Serial.print(v, HEX);
switch(state)
{
// waiting for new packet
case 0:
if (v == SOH)
{
_bidx = 0; // start new packet
state = 1;
}
break;
// extract receiver
case 1:
forMe = ((v == _deviceID) || (v == 255)); // PM or broadcast?
if (not forMe) state = 99;
else state = 2;
break;
// extract sender
case 2:
sender = v;
state = 3;
break;
// extract length
case 3:
msglen = v;
state = 3;
break;
// expect STX
case 4:
if (v == STX) state = 5;
else state = 99;
break;
// extract message
case 5:
if (length == 0)
{
state = 6;
break;
}
// error handling if v not ascii ?
_buffer[_bidx++] = v;
forMe = true;
return false;
}
CHKSUM ^= v;
length--;
break;
if (_bidx == 1) // expect TO
{
forMe = (v == _deviceID);
_buffer[_bidx++] = v;
return false;
}
// expect checksum
case 6:
if (CHKSUM == v) state = 7;
else state = 99;
break;
if (!forMe) return false;
// expect STX
case 7:
if (v == STX) state = 8;
else state = 99;
break;
if (_bidx == 2) // expect SENDER
// expect EOT
case 8:
if (v == EOT)
{
_buffer[_bidx++] = v;
return false;
senderID = sender;
msglen = _bidx -1;
for (int i = 0; i < msglen; i++)
{
msg[i] = _buffer[i];
}
if (_bidx == 3) // expect LEN
{
length = v;
_buffer[_bidx++] = v;
return false;
}
if (_bidx == 4) // expect STX
{
_buffer[_bidx++] = v;
return false;
}
if (_bidx >= 48) // prevent buffer overflow
{
len = 0;
forMe = false;
_bidx = 0;
return false;
}
if (v == ETX)
{
for (int i = 0, j = 5; i < length; i++, j++)
{
msg[i] = _buffer[j]; // copy buffer
CHKSUM ^= _buffer[j];
}
if (CHKSUM != _buffer[_bidx - 1])
len = length; // copy length
deviceID = _buffer[2]; // copy sender
forMe = false;
_bidx = 0;
return true;
}
return false;
state = 0;
break;
// SKIP until next packet
case 99: // wait for EOT in case of error
if (v == EOT) state = 0;
break;
}
return false;
}
*/
//////////////////////////////////////////////////

View File

@ -3,7 +3,7 @@
// FILE: RS485.h
// AUTHOR: Rob Tillaart
// DATE: 30-okt-2017
// VERSION: 0.2.2
// VERSION: 0.2.3
// 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.2"))
#define RS485_LIB_VERSION (F("0.2.3"))
class RS485 : public Stream
@ -44,9 +44,15 @@ public:
uint8_t getMode() { return digitalRead(_sendPin) == HIGH; };
// TODO TEST 0.3.0
// void send(uint8_t deviceID, uint8_t msg[], uint8_t len);
// bool receive(uint8_t &deviceID, uint8_t msg[], uint8_t &len);
// 0.3.0 EXPERIMENTAL
// send ASCII encoded messages from one master to multiple clients.
// msg[] = 32..127
// len = 1..48 ?
//
// should be a p2p network option.
void send(uint8_t receiverID, uint8_t msg[], uint8_t len);
bool receive(uint8_t &senderID, uint8_t msg[], uint8_t &len);
private:
Stream * _stream;
@ -54,11 +60,9 @@ private:
uint8_t _deviceID = 0;
uint16_t _microsPerByte = 1000;
// TODO TEST
// uint8_t _bidx = 0;
// uint8_t _buffer[50]; // internal receive buffer
// 0.3.0
uint8_t _bidx = 0;
uint8_t _buffer[50]; // internal receive buffer
};

View File

@ -11,8 +11,12 @@ setMicrosPerByte KEYWORD2
getMicrosPerByte KEYWORD2
getDeviceID KEYWORD2
setTXmode KEYWORD2
setRXmode KEYWORD2
getMode KEYWORD2
# TODO
# EXPERIMENTAL
send KEYWORD2
receive KEYWORD2

View File

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

View File

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