Browse Source

neu-implementierung. Funktioniert einigermaßen, interferiert aber mit anderen timer-basierten bibliotheken

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
main
Stephan Richter 1 year ago
parent
commit
8a1b4685da
  1. 12
      README.md
  2. 198
      SoftRS485.cpp
  3. 24
      examples/ReceiveDemo/ReceiveDemo.ino
  4. 9
      examples/SendAndReceive/SendAndReceive.ino
  5. 33
      examples/SendButton/SendButton.ino

12
README.md

@ -0,0 +1,12 @@ @@ -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

198
SoftRS485.cpp

@ -7,121 +7,138 @@ @@ -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<MSG_LEN-1) {
_recv_pos++;
}
}
} else _recv_idx++;
}
boolean bit = LOW;
_recv_bit = !digitalRead(_RO); // LOW = 1
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;
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){ @@ -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){ @@ -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){ @@ -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(){ @@ -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<MSG_LEN; idx++){
_message_out[idx] = message[idx]; // copy message
_send_message[idx] = message[idx]; // copy message
if (message[idx] == 0x00) break;
}
if (_message_out[0] == 0x00) return false; // message is empty! abort
_send_pos = START;
if (_send_message[0] == 0x00) return false; // message is empty! abort
_send_state = START;
#ifdef DEBUG
Serial.print("sending ");
Serial.println(_message_out);
Serial.print("sending "); Serial.println(_send_message);
#endif
return true;
}

24
examples/ReceiveDemo/ReceiveDemo.ino

@ -0,0 +1,24 @@ @@ -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
}
}

9
examples/SendAndReceive/SendAndReceive.ino

@ -27,9 +27,6 @@ void setup() { @@ -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(){ @@ -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!");
}
}
}

33
examples/SendButton/SendButton.ino

@ -0,0 +1,33 @@ @@ -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");
}
}
}
Loading…
Cancel
Save