neu-implementierung. Funktioniert einigermaßen, interferiert aber mit anderen timer-basierten bibliotheken
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
12
README.md
Normal file
12
README.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Library to interact with RS485 serial
|
||||||
|
|
||||||
|
Ist im Moment so implementiert, dass ein timer läuft und der Bus permanent überwacht wird.
|
||||||
|
|
||||||
|
Funktioniert einigermaßen, interferiert aber mit anderen Libs, die Timer benutzen.
|
||||||
|
|
||||||
|
Also doch nochmal neu schreiben, so dass
|
||||||
|
|
||||||
|
* zum Lesen Flanken erkannt und Zeiten zwischen diesen interpretiert werden
|
||||||
|
* das Schreiben timer-basiert erfolgt
|
||||||
|
|
||||||
|
Zur Orientierung kann das alte Protokoll, wie es noch beim Controllino verwendet wird, herangezogen werden
|
||||||
220
SoftRS485.cpp
220
SoftRS485.cpp
@@ -7,121 +7,138 @@
|
|||||||
#include "SoftRS485.h"
|
#include "SoftRS485.h"
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
#define IDLE -1
|
|
||||||
#define START -2
|
|
||||||
#define MSG_LEN 64
|
#define MSG_LEN 64
|
||||||
|
|
||||||
|
#define IDLE 0
|
||||||
|
#define START 1
|
||||||
|
#define RECEIVING 2
|
||||||
|
#define SENDING 3
|
||||||
|
#define COMPLETE 4
|
||||||
|
|
||||||
|
// Pins
|
||||||
int _RO, _RE, _DE, _DI;
|
int _RO, _RE, _DE, _DI;
|
||||||
|
int _idle_cycles = 0;
|
||||||
|
|
||||||
/* INCOMING */
|
/* INCOMING */
|
||||||
byte _recv_byte = 0x0;
|
|
||||||
boolean _recv_bit = false;
|
|
||||||
char _recv_message[MSG_LEN];
|
char _recv_message[MSG_LEN];
|
||||||
int _recv_idx = 0; // used as bit-index for _recv_byte
|
byte _recv_byte = 0x00;
|
||||||
int _recv_pos = IDLE; // used as char-index for _recv_message
|
byte _recv_state = IDLE;
|
||||||
|
boolean _recv_bit = false;
|
||||||
|
byte _recv_idx = 0;
|
||||||
|
int _recv_pos = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* OUTGOING */
|
/* OUTGOING */
|
||||||
char _message_out[MSG_LEN];
|
char _send_message[MSG_LEN];
|
||||||
int _send_pos = IDLE;
|
boolean _send_bit = false;
|
||||||
int _send_idx = 0;
|
byte _send_state = IDLE;
|
||||||
|
byte _send_wait = 0;
|
||||||
|
byte _send_idx = 0;
|
||||||
|
int _send_pos = 0;
|
||||||
|
|
||||||
ISR(TIMER1_COMPA_vect){
|
ISR(TIMER1_COMPA_vect){
|
||||||
OCR1A += 62500; // Advance The COMPA Register
|
OCR1A += 3228; // Advance The COMPA Register
|
||||||
|
|
||||||
_recv_bit = !digitalRead(_RO); // input line is HIGH by default
|
if (_send_state == SENDING){
|
||||||
if (_recv_pos == IDLE){
|
char c = _send_message[_send_pos];
|
||||||
if (_recv_bit) { // first 1 indicates incoming message
|
_send_bit = c & 1<<_send_idx;
|
||||||
_recv_pos = 0;
|
digitalWrite(_DI,!_send_bit);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.println(F("start of message reception"));
|
Serial.print("Sending bit "); Serial.print(_send_idx); Serial.print(" of "); Serial.print(c); Serial.print(": "); Serial.print(_send_bit); Serial.print(" / ");
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else { // we are reading!
|
|
||||||
_recv_byte |= _recv_bit << _recv_idx;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(F("received bit #"));
|
|
||||||
Serial.print(_recv_idx);
|
|
||||||
Serial.print(": ");
|
|
||||||
Serial.println(_recv_bit);
|
|
||||||
Serial.print(F("byte is now "));
|
|
||||||
Serial.println(_recv_byte,BIN);
|
|
||||||
#endif
|
|
||||||
if (_recv_idx == 7){ // byte complete
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(F("byte complete: "));
|
|
||||||
Serial.println(_recv_byte);
|
|
||||||
#endif
|
|
||||||
_recv_idx = 0;
|
|
||||||
_recv_message[_recv_pos] = _recv_byte;
|
|
||||||
if (_recv_byte == 0x00){ // we encountered a 0-byte! End of message!
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(F("got 0-byte!\nmessage reception complete: "));
|
|
||||||
Serial.println(_recv_message);
|
|
||||||
#endif
|
|
||||||
_recv_idx = 0;
|
|
||||||
_recv_pos = IDLE;
|
|
||||||
} else {
|
|
||||||
_recv_byte = 0x00;
|
|
||||||
if (_recv_pos<MSG_LEN-1) {
|
|
||||||
_recv_pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else _recv_idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean bit = LOW;
|
|
||||||
|
|
||||||
if (_send_pos >= 0){
|
|
||||||
char c = _message_out[_send_pos];
|
|
||||||
if (c == 0x00) { // end of message
|
|
||||||
digitalWrite(_DI,HIGH);
|
|
||||||
digitalWrite(_DE,LOW);
|
|
||||||
_send_pos = IDLE;
|
|
||||||
_send_idx = 0;
|
|
||||||
_message_out[0] = 0x00;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println("Message transmission completed!");
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
bit = !(c & 1<<_send_idx);
|
|
||||||
digitalWrite(_DI,bit);
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print("Sending bit #");
|
|
||||||
Serial.print(_send_idx);
|
|
||||||
Serial.print(" (");
|
|
||||||
Serial.print(bit);
|
|
||||||
Serial.print(") of ");
|
|
||||||
Serial.print(c);
|
|
||||||
Serial.print(" (");
|
|
||||||
Serial.print(c,BIN);
|
|
||||||
Serial.println(")");
|
|
||||||
#endif
|
#endif
|
||||||
_send_idx++;
|
_send_idx++;
|
||||||
if (_send_idx>7){
|
if (_send_idx==8){ // byte completed
|
||||||
|
_send_pos++; // advance to next byte
|
||||||
|
_send_idx = 0; // start with first bit
|
||||||
|
if (c == 0x00 || _send_idx == MSG_LEN){ // we just send a 0-byte
|
||||||
|
_send_state = COMPLETE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_send_state == START && _idle_cycles > 9){
|
||||||
|
_send_bit = HIGH;
|
||||||
|
digitalWrite(_DE,HIGH);
|
||||||
|
digitalWrite(_DI,!_send_bit);
|
||||||
|
_send_state = SENDING;
|
||||||
_send_idx = 0;
|
_send_idx = 0;
|
||||||
_send_pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_send_pos == START && _recv_pos == IDLE && _message_out[0] != 0x00) { // outgoig message awaits, line is idle
|
|
||||||
digitalWrite(_DE,HIGH); // enable driver
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("starting transmission"));
|
|
||||||
#endif
|
|
||||||
digitalWrite(_DI,bit); // send start bit
|
|
||||||
_send_pos = 0;
|
_send_pos = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("Sent start bit: "); Serial.print(_send_bit); Serial.print(" / ");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_send_pos != IDLE && digitalRead(_RO) != bit){ // driver output state mismatch!
|
_recv_bit = !digitalRead(_RO); // LOW = 1
|
||||||
digitalWrite(_DE,LOW); // disable driver
|
|
||||||
_send_pos = START;
|
if (_recv_bit) {
|
||||||
|
_idle_cycles = 0;
|
||||||
|
} else if (_idle_cycles<1000) {
|
||||||
|
_idle_cycles++;
|
||||||
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.println(F("collision!"));
|
Serial.print("idle cycles: "); Serial.print(_idle_cycles); Serial.print(" / ");
|
||||||
|
Serial.print("received: "); Serial.print(_recv_bit); Serial.print(" / ");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_send_bit != _recv_bit && _send_state == SENDING){ // collision while sending
|
||||||
|
digitalWrite(_DE,LOW); // disable driver
|
||||||
|
_send_state = START; // start over
|
||||||
|
_idle_cycles = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.println("\nCOLLISION");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_send_state == COMPLETE){
|
||||||
|
digitalWrite(_DE,LOW); // disable driver
|
||||||
|
_send_message[0]=0x00; // clear message
|
||||||
|
_send_state = IDLE;
|
||||||
|
_idle_cycles =0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("transmission complete / ");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (_recv_state == START){
|
||||||
|
_recv_byte = 0x00;
|
||||||
|
_recv_pos = 0;
|
||||||
|
_recv_idx = 0;
|
||||||
|
_recv_state = RECEIVING;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("Start reception / ");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_recv_bit && _recv_state == IDLE){
|
||||||
|
_recv_state = START;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_recv_state == RECEIVING){
|
||||||
|
_recv_byte |= _recv_bit << _recv_idx; // set bit
|
||||||
|
_recv_idx++; // increase bit index
|
||||||
|
if (_recv_idx == 8){ // byte full
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("pushing "); Serial.print((char)_recv_byte); Serial.print(" / ");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_recv_message[_recv_pos] = _recv_byte; // push character to string
|
||||||
|
if (_recv_byte == 0x00) { // end of message
|
||||||
|
_recv_state = IDLE;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("reception complete: "); Serial.print(_recv_message);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
_recv_idx=0; // start new byte
|
||||||
|
_recv_byte = 0;
|
||||||
|
_recv_pos++; // goto next string pos
|
||||||
|
if (_recv_pos == MSG_LEN) _recv_pos--; // avoid overflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void init485(int RO, int nRE, int DE, int DI){
|
void init485(int RO, int nRE, int DE, int DI){
|
||||||
@@ -130,7 +147,7 @@ void init485(int RO, int nRE, int DE, int DI){
|
|||||||
_DE=DE;
|
_DE=DE;
|
||||||
_DI=DI;
|
_DI=DI;
|
||||||
_recv_message[0] = 0x00; // empty
|
_recv_message[0] = 0x00; // empty
|
||||||
_message_out[0] = 0x00; // empty
|
_send_message[0] = 0x00; // empty
|
||||||
pinMode(_RO,INPUT);
|
pinMode(_RO,INPUT);
|
||||||
|
|
||||||
pinMode(_RE,OUTPUT);
|
pinMode(_RE,OUTPUT);
|
||||||
@@ -144,8 +161,8 @@ void init485(int RO, int nRE, int DE, int DI){
|
|||||||
|
|
||||||
TCCR1A = 0; // Init Timer1A
|
TCCR1A = 0; // Init Timer1A
|
||||||
TCCR1B = 0; // Init Timer1B
|
TCCR1B = 0; // Init Timer1B
|
||||||
TCCR1B |= B00000001; // Prescaler = 512
|
TCCR1B |= B00000001; // Prescaler = 1
|
||||||
OCR1A = 500; // Timer Compare1A Register
|
OCR1A = 3328; // Timer Compare1A Register
|
||||||
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
|
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@@ -162,7 +179,7 @@ void init485(int RO, int nRE, int DE, int DI){
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean available485(){
|
boolean available485(){
|
||||||
return _recv_pos == IDLE && _recv_message[0] != 0;
|
return _recv_state == IDLE && _recv_message[0] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get485Message(){
|
String get485Message(){
|
||||||
@@ -172,17 +189,16 @@ String get485Message(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean send485(char message[]){
|
boolean send485(char message[]){
|
||||||
if (_message_out[0] != 0x00) return false; // we already have a queued message, abort!
|
if (_send_message[0] != 0x00) return false; // we already have a queued message, abort!
|
||||||
for (int idx = 0; idx<MSG_LEN; idx++){
|
for (int idx = 0; idx<MSG_LEN; idx++){
|
||||||
_message_out[idx] = message[idx]; // copy message
|
_send_message[idx] = message[idx]; // copy message
|
||||||
if (message[idx] == 0x00) break;
|
if (message[idx] == 0x00) break;
|
||||||
}
|
}
|
||||||
if (_message_out[0] == 0x00) return false; // message is empty! abort
|
if (_send_message[0] == 0x00) return false; // message is empty! abort
|
||||||
_send_pos = START;
|
_send_state = START;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.print("sending ");
|
Serial.print("sending "); Serial.println(_send_message);
|
||||||
Serial.println(_message_out);
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
24
examples/ReceiveDemo/ReceiveDemo.ino
Normal file
24
examples/ReceiveDemo/ReceiveDemo.ino
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
This sketch demonstrates, how to use the SoftRS485 library.
|
||||||
|
This library makes use of Arduinos timer 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SoftRS485.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
init485(2,3,4,5); // library initialization:
|
||||||
|
// connect pin 2 to RO of Max485
|
||||||
|
// connect pin 3 to ^RE of Max485
|
||||||
|
// connect pin 4 to DE of Max485
|
||||||
|
// connect pin 5 to DI of Max485
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
if (available485()){ // check if we have received anything
|
||||||
|
Serial.print("messageReceived: ");
|
||||||
|
Serial.println(get485Message()); // read the received message
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,9 +27,6 @@ void setup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void messageReceived(String message){
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
void loop(){
|
||||||
if (available485()){ // check if we have received anything
|
if (available485()){ // check if we have received anything
|
||||||
Serial.print("messageReceived: ");
|
Serial.print("messageReceived: ");
|
||||||
@@ -39,6 +36,10 @@ void loop(){
|
|||||||
count++;
|
count++;
|
||||||
char msg[128];
|
char msg[128];
|
||||||
(message+count).toCharArray(msg,128);
|
(message+count).toCharArray(msg,128);
|
||||||
send485(msg);
|
if (!send485(msg)){
|
||||||
|
Serial.print("Sending ");
|
||||||
|
Serial.print(msg);
|
||||||
|
Serial.println(" failed!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
examples/SendButton/SendButton.ino
Normal file
33
examples/SendButton/SendButton.ino
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
This sketch demonstrates, how to use the SoftRS485 library.
|
||||||
|
This library makes use of Arduinos timer 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SoftRS485.h>
|
||||||
|
|
||||||
|
const int buttonPin = 10; // the number of the pushbutton pin
|
||||||
|
boolean button_state = true;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
init485(2,3,4,5); // library initialization:
|
||||||
|
// connect pin 2 to RO of Max485
|
||||||
|
// connect pin 3 to ^RE of Max485
|
||||||
|
// connect pin 4 to DE of Max485
|
||||||
|
// connect pin 5 to DI of Max485
|
||||||
|
|
||||||
|
pinMode(buttonPin, INPUT_PULLUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
boolean new_state = digitalRead(buttonPin);
|
||||||
|
if (new_state != button_state){
|
||||||
|
button_state = new_state;
|
||||||
|
if (new_state == LOW){
|
||||||
|
send485("Button pressed");
|
||||||
|
} else {
|
||||||
|
send485("Button released");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user