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:
2023-10-31 21:21:57 +01:00
parent 900e4e436e
commit 8a1b4685da
5 changed files with 191 additions and 105 deletions

12
README.md Normal file
View 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

View File

@@ -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;
} }

View 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
}
}

View File

@@ -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!");
}
} }
} }

View 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");
}
}
}