Reverted back to delay-based send. Seems to work with single master. Needs to be tested in multi-drop environment
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
221
SoftRS485.cpp
221
SoftRS485.cpp
@@ -7,18 +7,11 @@
|
|||||||
#include "SoftRS485.h"
|
#include "SoftRS485.h"
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
|
||||||
#define MSG_LEN 64
|
#define MSG_LEN 64
|
||||||
#define IDLE 0
|
|
||||||
#define WAIT 1
|
|
||||||
#define SEND 2
|
|
||||||
#define SENT 3
|
|
||||||
|
|
||||||
#define TIMER 250
|
|
||||||
// Pins
|
// Pins
|
||||||
int _RO, _RE, _DE, _DI;
|
int _RO, _RE, _DE, _DI;
|
||||||
long _pulse_len = 850;
|
long _pulse_len = 105;
|
||||||
|
|
||||||
|
|
||||||
// Receive vars
|
// Receive vars
|
||||||
boolean _recv_bit = false;
|
boolean _recv_bit = false;
|
||||||
@@ -28,28 +21,6 @@ int _recv_pos = 0;
|
|||||||
int _recv_idx = 0;
|
int _recv_idx = 0;
|
||||||
boolean _avail = false;
|
boolean _avail = false;
|
||||||
|
|
||||||
// Send vars
|
|
||||||
char _send_message[MSG_LEN];
|
|
||||||
int _send_state = IDLE;
|
|
||||||
int _send_pos = 0;
|
|
||||||
int _send_idx = 0;
|
|
||||||
boolean _send_bit = false;
|
|
||||||
|
|
||||||
void enableSendTimer(){
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(F("Enabling send timer. Old Value: b"));
|
|
||||||
Serial.println(TIMSK1,BIN);
|
|
||||||
#endif
|
|
||||||
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
|
|
||||||
}
|
|
||||||
|
|
||||||
void disableSendTimer(){
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println("Disable send timer");
|
|
||||||
#endif
|
|
||||||
TIMSK1 = TIMSK1 & ~B00000010; // Enable Timer COMPA Interrupt
|
|
||||||
}
|
|
||||||
|
|
||||||
void interrupt485(){
|
void interrupt485(){
|
||||||
_recv_bit = !digitalRead(_RO); // HIGH level = logical zero and vice versa
|
_recv_bit = !digitalRead(_RO); // HIGH level = logical zero and vice versa
|
||||||
long now = micros();
|
long now = micros();
|
||||||
@@ -57,36 +28,22 @@ void interrupt485(){
|
|||||||
_last_flip = now;
|
_last_flip = now;
|
||||||
if (diff > 20*_pulse_len){ // we received a start bit
|
if (diff > 20*_pulse_len){ // we received a start bit
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
Serial.print(F("State changed to ")); Serial.println(_recv_bit);
|
||||||
Serial.println(F("received start bit"));
|
Serial.println(F("received start bit"));
|
||||||
#endif
|
#endif
|
||||||
_recv_pos = 0;
|
_recv_pos = 0;
|
||||||
_recv_idx = 0;
|
_recv_idx = 0;
|
||||||
_last_flip+=_pulse_len;
|
_last_flip+=_pulse_len;
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(diff);
|
|
||||||
Serial.println("µs");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
long count = diff/_pulse_len;
|
long count = diff/_pulse_len;
|
||||||
for (int i=0; i<count; i++){
|
for (int i=0; i<count; i++){
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(_recv_bit);
|
|
||||||
Serial.println(" <=");
|
|
||||||
#endif
|
|
||||||
if (_recv_idx == 0) {
|
if (_recv_idx == 0) {
|
||||||
_recv_msg[_recv_pos] = (_recv_bit);
|
_recv_msg[_recv_pos] = (!_recv_bit);
|
||||||
} else {
|
} else {
|
||||||
_recv_msg[_recv_pos] |= (_recv_bit)<<_recv_idx;
|
_recv_msg[_recv_pos] |= (!_recv_bit)<<_recv_idx;
|
||||||
}
|
}
|
||||||
_recv_idx++;
|
_recv_idx++;
|
||||||
if (_recv_idx == 8){
|
if (_recv_idx == 8){
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print("0x");
|
|
||||||
Serial.print(_recv_msg[_recv_pos],HEX);
|
|
||||||
Serial.print(" recevied / ");
|
|
||||||
Serial.println((char)_recv_msg[_recv_pos]);
|
|
||||||
#endif
|
|
||||||
_recv_idx = 0;
|
_recv_idx = 0;
|
||||||
if (_recv_msg[_recv_pos] == 0x00){
|
if (_recv_msg[_recv_pos] == 0x00){
|
||||||
_avail = _recv_pos != 0;
|
_avail = _recv_pos != 0;
|
||||||
@@ -98,102 +55,6 @@ void interrupt485(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ISR(TIMER1_COMPA_vect){
|
|
||||||
OCR1A += TIMER; // Advance The COMPA Register
|
|
||||||
|
|
||||||
boolean echo = digitalRead(_RO);
|
|
||||||
|
|
||||||
if (_send_state == SENT){
|
|
||||||
if (echo != _send_bit){
|
|
||||||
digitalWrite(_DE,LOW);
|
|
||||||
_send_state = WAIT;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("Collision"));
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
digitalWrite(_DE,LOW);
|
|
||||||
_send_message[0] = 0x00;
|
|
||||||
_send_state = IDLE;
|
|
||||||
disableSendTimer();
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("Transmission complete"));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_send_state == SEND){
|
|
||||||
if (echo != _send_bit){
|
|
||||||
digitalWrite(_DE,LOW);
|
|
||||||
_send_state = WAIT;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("Collision"));
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char c = _send_message[_send_pos];
|
|
||||||
_send_bit = c & (1 << _send_idx);
|
|
||||||
digitalWrite(_DI,_send_bit);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (!_send_idx) {
|
|
||||||
Serial.print("Sending "); Serial.print(c); Serial.print(" / 0x"); Serial.println(c,HEX);
|
|
||||||
}
|
|
||||||
Serial.print("<--- "); Serial.println(_send_bit);
|
|
||||||
#endif
|
|
||||||
_send_idx++;
|
|
||||||
if (_send_idx == 8) {
|
|
||||||
_send_idx = 0;
|
|
||||||
_send_pos++;
|
|
||||||
if (c == 0x00 || _send_pos == MSG_LEN){
|
|
||||||
_send_state = SENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_send_state == WAIT){
|
|
||||||
long diff = micros() - _last_flip; // µs
|
|
||||||
long idle_count = diff / _pulse_len;
|
|
||||||
if (idle_count > MSG_LEN){
|
|
||||||
_send_bit = LOW;
|
|
||||||
digitalWrite(_DE,HIGH);
|
|
||||||
digitalWrite(_DI,_send_bit);
|
|
||||||
_send_state = SEND;
|
|
||||||
_send_idx = 0;
|
|
||||||
_send_pos = 0;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("Sending start bit (1)"));
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("Bus busy"));
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo = digitalRead(_RO);
|
|
||||||
if (echo != _send_bit){
|
|
||||||
digitalWrite(_DE,LOW);
|
|
||||||
_send_state = WAIT;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.println(F("Collision"));
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void configureSendTimer(){
|
|
||||||
TCCR1A = 0; // Init Timer1A
|
|
||||||
TCCR1B = 0; // Init Timer1B
|
|
||||||
TCCR1B |= B00000011; // Prescaler = 1
|
|
||||||
OCR1A = TIMER; // Timer Compare1A Register
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void init485(int RO, int nRE, int DE, int DI){
|
void init485(int RO, int nRE, int DE, int DI){
|
||||||
_RO=RO;
|
_RO=RO;
|
||||||
_RE=nRE;
|
_RE=nRE;
|
||||||
@@ -212,7 +73,7 @@ void init485(int RO, int nRE, int DE, int DI){
|
|||||||
digitalWrite(_DI,LOW); // output line = LOW
|
digitalWrite(_DI,LOW); // output line = LOW
|
||||||
|
|
||||||
attachInterrupt(digitalPinToInterrupt(_RO),interrupt485,CHANGE);
|
attachInterrupt(digitalPinToInterrupt(_RO),interrupt485,CHANGE);
|
||||||
configureSendTimer();
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.print(F("RO = "));
|
Serial.print(F("RO = "));
|
||||||
@@ -236,29 +97,59 @@ String get485message(){
|
|||||||
return String((char*)_recv_msg);
|
return String((char*)_recv_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean writeBit(boolean bit){
|
||||||
boolean send485(String message){
|
digitalWrite(_DI,!bit);
|
||||||
if (_send_message[0] != 0x00) {
|
delayMicroseconds(5);
|
||||||
|
if (_recv_bit != bit){ // collision!
|
||||||
|
digitalWrite(_DE,LOW);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.println("Busy!");
|
Serial.println(F("Collision!"));
|
||||||
#endif
|
#endif
|
||||||
return false; // we already have a queued message, abort!
|
return false;
|
||||||
}
|
}
|
||||||
|
delayMicroseconds(_pulse_len-12);
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(F("Preparing to send ")); Serial.println(message);
|
|
||||||
#endif
|
|
||||||
const char* buf = message.c_str();
|
|
||||||
for (int idx = 0; idx<MSG_LEN; idx++){
|
|
||||||
_send_message[idx] = buf[idx]; // copy message
|
|
||||||
if (_send_message[idx] == 0x00) break;
|
|
||||||
}
|
|
||||||
if (_send_message[0] == 0x00) return false; // message is empty
|
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print(F("Message copied to send buffer: "));
|
|
||||||
Serial.println(_send_message);
|
|
||||||
#endif
|
|
||||||
_send_state = WAIT;
|
|
||||||
enableSendTimer();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean send485(char message[]){
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print(F("preparing to send "));
|
||||||
|
Serial.print(message);
|
||||||
|
Serial.print(F(": line state = "));
|
||||||
|
Serial.print(_recv_bit);
|
||||||
|
Serial.print(F(" / last_flip = "));
|
||||||
|
Serial.print(_last_flip);
|
||||||
|
Serial.print(F(" / micros = "));
|
||||||
|
Serial.println(micros());
|
||||||
|
#endif
|
||||||
|
while (_recv_bit || (micros() - _last_flip) < (20 * _pulse_len)) {
|
||||||
|
delayMicroseconds(20*_pulse_len);
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.println(F("enabling driver…"));
|
||||||
|
#endif
|
||||||
|
digitalWrite(_DE,HIGH); // enable driver
|
||||||
|
if (!writeBit(HIGH)) return false;
|
||||||
|
int pos = -1;
|
||||||
|
boolean good = true;
|
||||||
|
do {
|
||||||
|
pos++;
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print(F("sending character ")); Serial.println(message[pos]);
|
||||||
|
#endif
|
||||||
|
good = writeBit(message[pos] & 0x01)
|
||||||
|
&& writeBit(message[pos] & 0x02)
|
||||||
|
&& writeBit(message[pos] & 0x04)
|
||||||
|
&& writeBit(message[pos] & 0x08)
|
||||||
|
&& writeBit(message[pos] & 0x10)
|
||||||
|
&& writeBit(message[pos] & 0x20)
|
||||||
|
&& writeBit(message[pos] & 0x40)
|
||||||
|
&& writeBit(message[pos] & 0x80);
|
||||||
|
} while (good && message[pos]);
|
||||||
|
if (good) writeBit(1);
|
||||||
|
digitalWrite(_DE,LOW); // disable driver
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.println(F("disabled driver…"));
|
||||||
|
#endif
|
||||||
|
return good;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,5 +11,5 @@
|
|||||||
extern void init485(int RO, int nRE, int DE, int DI);
|
extern void init485(int RO, int nRE, int DE, int DI);
|
||||||
extern boolean available485();
|
extern boolean available485();
|
||||||
extern String get485message();
|
extern String get485message();
|
||||||
extern boolean send485(String message);
|
extern boolean send485(char message[]);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user