From 8a1b4685dab13c35942140469adfa4c6765d1dff Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Tue, 31 Oct 2023 21:21:57 +0100 Subject: [PATCH] =?UTF-8?q?neu-implementierung.=20Funktioniert=20einigerma?= =?UTF-8?q?=C3=9Fen,=20interferiert=20aber=20mit=20anderen=20timer-basiert?= =?UTF-8?q?en=20bibliotheken?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephan Richter --- README.md | 12 ++ SoftRS485.cpp | 198 +++++++++++---------- examples/ReceiveDemo/ReceiveDemo.ino | 24 +++ examples/SendAndReceive/SendAndReceive.ino | 9 +- examples/SendButton/SendButton.ino | 33 ++++ 5 files changed, 181 insertions(+), 95 deletions(-) create mode 100644 README.md create mode 100644 examples/ReceiveDemo/ReceiveDemo.ino create mode 100644 examples/SendButton/SendButton.ino diff --git a/README.md b/README.md new file mode 100644 index 0000000..a412464 --- /dev/null +++ b/README.md @@ -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 \ No newline at end of file diff --git a/SoftRS485.cpp b/SoftRS485.cpp index 92e9948..3483bcf 100644 --- a/SoftRS485.cpp +++ b/SoftRS485.cpp @@ -7,121 +7,138 @@ #include "SoftRS485.h" //#define DEBUG -#define IDLE -1 -#define START -2 #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 _idle_cycles = 0; /* INCOMING */ -byte _recv_byte = 0x0; +char _recv_message[MSG_LEN]; +byte _recv_byte = 0x00; +byte _recv_state = IDLE; boolean _recv_bit = false; -char _recv_message[MSG_LEN]; -int _recv_idx = 0; // used as bit-index for _recv_byte -int _recv_pos = IDLE; // used as char-index for _recv_message +byte _recv_idx = 0; +int _recv_pos = 0; + + /* OUTGOING */ -char _message_out[MSG_LEN]; -int _send_pos = IDLE; -int _send_idx = 0; +char _send_message[MSG_LEN]; +boolean _send_bit = false; +byte _send_state = IDLE; +byte _send_wait = 0; +byte _send_idx = 0; +int _send_pos = 0; 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 (_recv_pos == IDLE){ - if (_recv_bit) { // first 1 indicates incoming message - _recv_pos = 0; + if (_send_state == SENDING){ + char c = _send_message[_send_pos]; + _send_bit = c & 1<<_send_idx; + digitalWrite(_DI,!_send_bit); #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 + _send_idx++; + 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; + } } - } 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! + } + if (_send_state == START && _idle_cycles > 9){ + _send_bit = HIGH; + digitalWrite(_DE,HIGH); + digitalWrite(_DI,!_send_bit); + _send_state = SENDING; + _send_idx = 0; + _send_pos = 0; #ifdef DEBUG - Serial.print(F("got 0-byte!\nmessage reception complete: ")); - Serial.println(_recv_message); + Serial.print("Sent start bit: "); Serial.print(_send_bit); Serial.print(" / "); #endif - _recv_idx = 0; - _recv_pos = IDLE; - } else { - _recv_byte = 0x00; - if (_recv_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; + if (_recv_bit) { + _idle_cycles = 0; + } else if (_idle_cycles<1000) { + _idle_cycles++; + } #ifdef DEBUG - Serial.println("Message transmission completed!"); + Serial.print("idle cycles: "); Serial.print(_idle_cycles); Serial.print(" / "); + Serial.print("received: "); Serial.print(_recv_bit); Serial.print(" / "); #endif - } else { - bit = !(c & 1<<_send_idx); - digitalWrite(_DI,bit); + + 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.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(")"); + Serial.println("\nCOLLISION"); #endif - _send_idx++; - if (_send_idx>7){ - _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 + if (_send_state == COMPLETE){ + digitalWrite(_DE,LOW); // disable driver + _send_message[0]=0x00; // clear message + _send_state = IDLE; + _idle_cycles =0; #ifdef DEBUG - Serial.println(F("starting transmission")); + Serial.print("transmission complete / "); #endif - digitalWrite(_DI,bit); // send start bit - _send_pos = 0; } - if (_send_pos != IDLE && digitalRead(_RO) != bit){ // driver output state mismatch! - digitalWrite(_DE,LOW); // disable driver - _send_pos = START; + + + if (_recv_state == START){ + _recv_byte = 0x00; + _recv_pos = 0; + _recv_idx = 0; + _recv_state = RECEIVING; #ifdef DEBUG - Serial.println(F("collision!")); + 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){ @@ -130,7 +147,7 @@ void init485(int RO, int nRE, int DE, int DI){ _DE=DE; _DI=DI; _recv_message[0] = 0x00; // empty - _message_out[0] = 0x00; // empty + _send_message[0] = 0x00; // empty pinMode(_RO,INPUT); pinMode(_RE,OUTPUT); @@ -144,8 +161,8 @@ void init485(int RO, int nRE, int DE, int DI){ TCCR1A = 0; // Init Timer1A TCCR1B = 0; // Init Timer1B - TCCR1B |= B00000001; // Prescaler = 512 - OCR1A = 500; // Timer Compare1A Register + TCCR1B |= B00000001; // Prescaler = 1 + OCR1A = 3328; // Timer Compare1A Register TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt #ifdef DEBUG Serial.begin(115200); @@ -162,7 +179,7 @@ void init485(int RO, int nRE, int DE, int DI){ } boolean available485(){ - return _recv_pos == IDLE && _recv_message[0] != 0; + return _recv_state == IDLE && _recv_message[0] != 0; } String get485Message(){ @@ -172,17 +189,16 @@ String get485Message(){ } 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 + +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 + } +} diff --git a/examples/SendAndReceive/SendAndReceive.ino b/examples/SendAndReceive/SendAndReceive.ino index 3919337..0d6aefa 100644 --- a/examples/SendAndReceive/SendAndReceive.ino +++ b/examples/SendAndReceive/SendAndReceive.ino @@ -27,9 +27,6 @@ void setup() { } } -void messageReceived(String message){ -} - void loop(){ if (available485()){ // check if we have received anything Serial.print("messageReceived: "); @@ -39,6 +36,10 @@ void loop(){ count++; char msg[128]; (message+count).toCharArray(msg,128); - send485(msg); + if (!send485(msg)){ + Serial.print("Sending "); + Serial.print(msg); + Serial.println(" failed!"); + } } } diff --git a/examples/SendButton/SendButton.ino b/examples/SendButton/SendButton.ino new file mode 100644 index 0000000..50e85a0 --- /dev/null +++ b/examples/SendButton/SendButton.ino @@ -0,0 +1,33 @@ +/* + This sketch demonstrates, how to use the SoftRS485 library. + This library makes use of Arduinos timer 1 + */ + +#include + +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"); + } + } +}