197 lines
4.2 KiB
C++
197 lines
4.2 KiB
C++
/*
|
|
Library for Software Serial over RS485 connection
|
|
Created by Stepan Richter, November 2023
|
|
*/
|
|
|
|
#include "Arduino.h"
|
|
#include "SoftRS485.h"
|
|
|
|
//#define SEND
|
|
#define MSG_LEN 64
|
|
|
|
// Pins
|
|
int _RO, _RE, _DE, _DI;
|
|
long _pulse_len = 616;// 1232; // Pulslänge von 1250µs - 18µs Zeit für Operationen
|
|
long _break = _pulse_len * 20;
|
|
// Receive vars
|
|
boolean _line = LOW;
|
|
long _last_flip = 0; // this is the time when the bus switched to logical zero
|
|
byte _recv_msg[MSG_LEN];
|
|
boolean _avail = false;
|
|
long _diff = 0;
|
|
long _now = 0;
|
|
int _pos = 0;
|
|
int _idx = 0;
|
|
long _count = 0;
|
|
boolean _reset = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void interrupt485(){
|
|
_line = !digitalRead(_RO); // HIGH level = logical zero and vice versa
|
|
_now = micros();
|
|
_diff = _now - _last_flip;
|
|
_last_flip = _now;
|
|
|
|
#ifdef RECV
|
|
Serial.print(!_line);
|
|
Serial.print("-(");
|
|
Serial.print(_diff);
|
|
Serial.print("µs)→");
|
|
Serial.print(_line);
|
|
Serial.print(" ");
|
|
#endif
|
|
|
|
if (_diff > _break){
|
|
_pos = 0;
|
|
_idx = 0;
|
|
_reset = true;
|
|
#ifdef RECV
|
|
Serial.println("==RESET==");
|
|
#endif
|
|
} else {
|
|
_count = _pulse_len>>1;
|
|
while (_count < _diff){
|
|
_count += _pulse_len;
|
|
if (_idx){
|
|
_recv_msg[_pos] |= !_line << _idx;
|
|
} else {
|
|
_recv_msg[_pos] = !_line;
|
|
}
|
|
if (_reset){
|
|
_reset = false;
|
|
} else {
|
|
_idx++;
|
|
}
|
|
#ifdef RECV
|
|
Serial.print(_line);
|
|
#endif
|
|
if (_idx == 8){
|
|
if (_recv_msg[_pos] == 0x00){
|
|
_avail = true;
|
|
}
|
|
_pos++;
|
|
_idx=0;
|
|
}
|
|
}
|
|
#ifdef RECV
|
|
Serial.println();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void init485(int RO, int nRE, int DE, int DI){
|
|
_RO=RO;
|
|
_RE=nRE;
|
|
_DE=DE;
|
|
_DI=DI;
|
|
_avail = false;
|
|
|
|
|
|
#if defined SEND || defined RECV
|
|
Serial.begin(115200);
|
|
Serial.print(F("RO = "));
|
|
Serial.println(_RO);
|
|
Serial.print(F("^RE = "));
|
|
Serial.println(_RE);
|
|
Serial.print(F("DE = "));
|
|
Serial.println(_DE);
|
|
Serial.print(F("DI = "));
|
|
Serial.println(_DI);
|
|
#endif
|
|
|
|
#ifdef RECV
|
|
Serial.println("RECV enabled");
|
|
#endif
|
|
#ifdef SEND
|
|
Serial.println("SEND enabled");
|
|
#endif
|
|
|
|
pinMode(_RO,INPUT);
|
|
|
|
pinMode(_RE,OUTPUT);
|
|
digitalWrite(_RE,LOW); // enable reading
|
|
|
|
pinMode(_DE,OUTPUT);
|
|
digitalWrite(_DE,LOW); // disable writing
|
|
|
|
pinMode(_DI,OUTPUT);
|
|
digitalWrite(_DI,LOW); // output line = LOW
|
|
|
|
attachInterrupt(digitalPinToInterrupt(_RO),interrupt485,CHANGE);
|
|
_last_flip = micros();
|
|
}
|
|
|
|
boolean available485(){
|
|
return _avail;
|
|
}
|
|
|
|
String get485message(){
|
|
_avail = false;
|
|
return String((char*)_recv_msg);
|
|
}
|
|
|
|
boolean writeBit(boolean bit){
|
|
digitalWrite(_DI,!bit);
|
|
delayMicroseconds(5);
|
|
if (_line != bit){ // collision!
|
|
digitalWrite(_DE,LOW);
|
|
#ifdef SEND
|
|
Serial.println(F("Collision!"));
|
|
#endif
|
|
return false;
|
|
}
|
|
delayMicroseconds(_pulse_len-5);
|
|
return true;
|
|
}
|
|
|
|
boolean writeByte(byte b){
|
|
return writeBit(b & 0x01)
|
|
&& writeBit(b & 0x02)
|
|
&& writeBit(b & 0x04)
|
|
&& writeBit(b & 0x08)
|
|
&& writeBit(b & 0x10)
|
|
&& writeBit(b & 0x20)
|
|
&& writeBit(b & 0x40)
|
|
&& writeBit(b & 0x80);
|
|
}
|
|
|
|
boolean send485(char message[]){
|
|
#ifdef SEND
|
|
Serial.print(F("preparing to send "));
|
|
Serial.print(message);
|
|
Serial.print(F(": line state = "));
|
|
Serial.print(_line);
|
|
Serial.print(F(" / last_flip = "));
|
|
Serial.print(_last_flip);
|
|
Serial.print(F(" / micros = "));
|
|
Serial.println(micros());
|
|
#endif
|
|
while (_line || (micros() - _last_flip) < (20 * _pulse_len)) {
|
|
delayMicroseconds(20*_pulse_len);
|
|
}
|
|
#ifdef SEND
|
|
Serial.println(F("enabling driver…"));
|
|
#endif
|
|
digitalWrite(_DI,LOW);
|
|
digitalWrite(_DE,HIGH); // enable driver
|
|
int pos = -1; // increment pos prior to sending char!
|
|
boolean sync = writeBit(0);
|
|
do {
|
|
pos++;
|
|
sync = sync && writeByte(message[pos]);
|
|
} while (sync && message[pos]);
|
|
digitalWrite(_DI,LOW);
|
|
digitalWrite(_DE,LOW); // disable driver
|
|
#ifdef SEND
|
|
Serial.println(F("disabled driver…"));
|
|
#endif
|
|
return sync;
|
|
}
|