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 @@
# 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 @@
#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; char _recv_message[MSG_LEN];
byte _recv_byte = 0x00;
byte _recv_state = IDLE;
boolean _recv_bit = false; boolean _recv_bit = false;
char _recv_message[MSG_LEN]; byte _recv_idx = 0;
int _recv_idx = 0; // used as bit-index for _recv_byte int _recv_pos = 0;
int _recv_pos = IDLE; // used as char-index for _recv_message
/* 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 #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; if (_send_state == START && _idle_cycles > 9){
#ifdef DEBUG _send_bit = HIGH;
Serial.print(F("received bit #")); digitalWrite(_DE,HIGH);
Serial.print(_recv_idx); digitalWrite(_DI,!_send_bit);
Serial.print(": "); _send_state = SENDING;
Serial.println(_recv_bit); _send_idx = 0;
Serial.print(F("byte is now ")); _send_pos = 0;
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 #ifdef DEBUG
Serial.print(F("got 0-byte!\nmessage reception complete: ")); Serial.print("Sent start bit: "); Serial.print(_send_bit); Serial.print(" / ");
Serial.println(_recv_message);
#endif #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){ if (_recv_bit) {
char c = _message_out[_send_pos]; _idle_cycles = 0;
if (c == 0x00) { // end of message } else if (_idle_cycles<1000) {
digitalWrite(_DI,HIGH); _idle_cycles++;
digitalWrite(_DE,LOW); }
_send_pos = IDLE;
_send_idx = 0;
_message_out[0] = 0x00;
#ifdef DEBUG #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 #endif
} else {
bit = !(c & 1<<_send_idx); if (_send_bit != _recv_bit && _send_state == SENDING){ // collision while sending
digitalWrite(_DI,bit); digitalWrite(_DE,LOW); // disable driver
_send_state = START; // start over
_idle_cycles = 0;
#ifdef DEBUG #ifdef DEBUG
Serial.print("Sending bit #"); Serial.println("\nCOLLISION");
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++;
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 if (_send_state == COMPLETE){
digitalWrite(_DE,HIGH); // enable driver digitalWrite(_DE,LOW); // disable driver
_send_message[0]=0x00; // clear message
_send_state = IDLE;
_idle_cycles =0;
#ifdef DEBUG #ifdef DEBUG
Serial.println(F("starting transmission")); Serial.print("transmission complete / ");
#endif #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 #ifdef DEBUG
Serial.println(F("collision!")); Serial.print("Start reception / ");
#endif #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

@ -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() {
} }
} }
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

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