/* 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; const unsigned long _pulse_len = 1000; const unsigned long _break = _pulse_len * 20; unsigned long _last_flip = 0; // timestamp of last flip of line state boolean _line = LOW; // current state of the transmission line boolean _start = false; // indicates whether a start bit shall be ignored // Receive vars byte _recv_msg[MSG_LEN]; // message buffer boolean _avail = false; // indicates, wheter a message has been received int _pos = 0; // character position within the buffer int _idx = 0; // bit position within the current character // variables, that could be local, but are stored globally for speed optimization unsigned long _diff = 0; // time difference between last flips unsigned long _now = 0; // current time unsigned long _count = 0; // helper for bit iteration #if defined CONTROLLINO_MAXI ISR(PCINT1_vect){ #else void interrupt485(){ #endif _line = !digitalRead(_RO); // HIGH level = logical zero and vice versa _now = micros(); // get current time _diff = _now - _last_flip; // duration of the _previous_ bit _last_flip = _now; // store time of the current flip #ifdef RECV Serial.print(!_line); Serial.print("-("); Serial.print(_diff); Serial.print("µs)→"); Serial.print(_line); Serial.print(" "); #endif if (_diff > _break){ // long break means we are starting with a new transmission _start = true; // first bit will be ignored on the next edge _pos = 0; // start writing at the beginning of the message buffer _idx = 0; #ifdef RECV Serial.println("==RESET=="); #endif } else { _count = _pulse_len>>1; // bit lengths may vary in certain bounds. this makes sure we always are in the bounds while (_count < _diff){ // iterate though each bit _count += _pulse_len; if (_idx){ // not the first bit _recv_msg[_pos] |= !_line << _idx; // set the bit of the current character } else { // first bit _recv_msg[_pos] = !_line; // reset all bits, set the first bit of the current character } if (_start){ // current bit is start bit _start = false; // ignore by not increasing the bit index } else { // current bit is not a start bit _idx++; // advance to the next bit } #ifdef RECV Serial.print(_line); #endif if (_idx == 8){ // full byte received if (_pos == MSG_LEN || _recv_msg[_pos] == 0x00){ // received byte is string terminator _avail = true; // notify about complete transmission break; } _pos++; // advance to nect character of buffer _idx=0; // start with first bit of that character } } #ifdef RECV Serial.println(); #endif } } void init485(int RO, int nRE, int DE, int DI){ _RO=RO; // save the pin numbers _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); // we are reading on line _RO 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 #if defined CONTROLLINO_MAXI Serial.println("Setting up for Controllino MAXI!"); // https://forum.arduino.cc/t/enable-interrupt/259014/2 // pin change interrupt enable (PCIE) port 1 // in pin change interrupt control register (PCICR) PCICR |= (1<