re-implemented library. needs to be tested!
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
250
SoftRS485.cpp
250
SoftRS485.cpp
@@ -9,136 +9,50 @@
|
||||
//#define DEBUG
|
||||
#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;
|
||||
long _pulse_len = 100;
|
||||
|
||||
/* INCOMING */
|
||||
char _recv_message[MSG_LEN];
|
||||
byte _recv_byte = 0x00;
|
||||
byte _recv_state = IDLE;
|
||||
// Receive vars
|
||||
boolean _recv_bit = false;
|
||||
byte _recv_idx = 0;
|
||||
int _recv_pos = 0;
|
||||
long _last_flip; // this is the time when the bus switched to logical zero
|
||||
byte _recv_msg[MSG_LEN];
|
||||
int _recv_pos = 0;
|
||||
int _recv_idx = 0;
|
||||
boolean _avail = false;
|
||||
|
||||
|
||||
|
||||
/* OUTGOING */
|
||||
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 += 3228; // Advance The COMPA Register
|
||||
|
||||
if (_send_state == SENDING){
|
||||
char c = _send_message[_send_pos];
|
||||
_send_bit = c & 1<<_send_idx;
|
||||
digitalWrite(_DI,!_send_bit);
|
||||
void interrupt485(){
|
||||
_recv_bit = !digitalRead(_RO); // HIGH level = logical zero and vice versa
|
||||
long now = micros();
|
||||
long diff = now - _last_flip;
|
||||
_last_flip = now;
|
||||
if (diff > 20*_pulse_len){ // we received a start bit
|
||||
#ifdef DEBUG
|
||||
Serial.print("Sending bit "); Serial.print(_send_idx); Serial.print(" of "); Serial.print(c); Serial.print(": "); Serial.print(_send_bit); Serial.print(" / ");
|
||||
Serial.print(F("State changed to ")); Serial.println(_recv_bit);
|
||||
Serial.println(F("received start bit"));
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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("Sent start bit: "); Serial.print(_send_bit); Serial.print(" / ");
|
||||
#endif
|
||||
}
|
||||
|
||||
_recv_bit = !digitalRead(_RO); // LOW = 1
|
||||
|
||||
if (_recv_bit) {
|
||||
_idle_cycles = 0;
|
||||
} else if (_idle_cycles<1000) {
|
||||
_idle_cycles++;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
Serial.print("idle cycles: "); Serial.print(_idle_cycles); Serial.print(" / ");
|
||||
Serial.print("received: "); Serial.print(_recv_bit); Serial.print(" / ");
|
||||
#endif
|
||||
|
||||
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.println("\nCOLLISION");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_send_state == COMPLETE){
|
||||
digitalWrite(_DE,LOW); // disable driver
|
||||
_send_message[0]=0x00; // clear message
|
||||
_send_state = IDLE;
|
||||
_idle_cycles =0;
|
||||
#ifdef DEBUG
|
||||
Serial.print("transmission complete / ");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (_recv_state == START){
|
||||
_recv_byte = 0x00;
|
||||
_recv_pos = 0;
|
||||
_recv_idx = 0;
|
||||
_recv_state = RECEIVING;
|
||||
#ifdef DEBUG
|
||||
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
|
||||
_last_flip+=_pulse_len;
|
||||
} else {
|
||||
long count = diff/_pulse_len;
|
||||
for (int i=0; i<count; i++){
|
||||
if (_recv_idx == 0) {
|
||||
_recv_msg[_recv_pos] = (!_recv_bit);
|
||||
} else {
|
||||
_recv_msg[_recv_pos] |= (!_recv_bit)<<_recv_idx;
|
||||
}
|
||||
_recv_idx++;
|
||||
if (_recv_idx == 8){
|
||||
_recv_idx = 0;
|
||||
if (_recv_msg[_recv_pos] == 0x00){
|
||||
_avail = _recv_pos != 0;
|
||||
return;
|
||||
}
|
||||
_recv_pos++;
|
||||
}
|
||||
_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){
|
||||
@@ -146,8 +60,7 @@ void init485(int RO, int nRE, int DE, int DI){
|
||||
_RE=nRE;
|
||||
_DE=DE;
|
||||
_DI=DI;
|
||||
_recv_message[0] = 0x00; // empty
|
||||
_send_message[0] = 0x00; // empty
|
||||
|
||||
pinMode(_RO,INPUT);
|
||||
|
||||
pinMode(_RE,OUTPUT);
|
||||
@@ -159,46 +72,93 @@ void init485(int RO, int nRE, int DE, int DI){
|
||||
pinMode(_DI,OUTPUT);
|
||||
digitalWrite(_DI,LOW); // output line = LOW
|
||||
|
||||
TCCR1A = 0; // Init Timer1A
|
||||
TCCR1B = 0; // Init Timer1B
|
||||
TCCR1B |= B00000001; // Prescaler = 1
|
||||
OCR1A = 3328; // Timer Compare1A Register
|
||||
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
|
||||
attachInterrupt(digitalPinToInterrupt(_RO),interrupt485,CHANGE);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.begin(115200);
|
||||
Serial.println("Started timer!");
|
||||
Serial.print("RO = ");
|
||||
Serial.print(F("RO = "));
|
||||
Serial.println(_RO);
|
||||
Serial.print("^RE = ");
|
||||
Serial.print(F("^RE = "));
|
||||
Serial.println(_RE);
|
||||
Serial.print("DE = ");
|
||||
Serial.print(F("DE = "));
|
||||
Serial.println(_DE);
|
||||
Serial.print("DI = ");
|
||||
Serial.print(F("DI = "));
|
||||
Serial.println(_DI);
|
||||
#endif
|
||||
_last_flip = micros();
|
||||
}
|
||||
|
||||
void speed485(long baudrate){
|
||||
#ifndef DEBUG
|
||||
_pulse_len = 1e6 / baudrate;
|
||||
#else
|
||||
_pulse_len = 1000;
|
||||
Serial.print(F("Set pulse_len to ")); Serial.print(_pulse_len); Serial.println(F("µs"));
|
||||
#endif
|
||||
}
|
||||
|
||||
boolean available485(){
|
||||
return _recv_state == IDLE && _recv_message[0] != 0;
|
||||
return _avail;
|
||||
}
|
||||
|
||||
String get485Message(){
|
||||
String res = String(_recv_message);
|
||||
_recv_message[0] = 0;
|
||||
return res;
|
||||
String get485message(){
|
||||
_avail = false;
|
||||
return String((char*)_recv_msg);
|
||||
}
|
||||
|
||||
boolean writeBit(boolean bit){
|
||||
digitalWrite(_DI,!bit);
|
||||
delayMicroseconds(5);
|
||||
if (_recv_bit != bit){ // collision!
|
||||
digitalWrite(_DE,LOW);
|
||||
#ifdef DEBUG
|
||||
Serial.println(F("Collision!"));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
delayMicroseconds(_pulse_len-5);
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean send485(char message[]){
|
||||
if (_send_message[0] != 0x00) return false; // we already have a queued message, abort!
|
||||
for (int idx = 0; idx<MSG_LEN; idx++){
|
||||
_send_message[idx] = message[idx]; // copy message
|
||||
if (message[idx] == 0x00) break;
|
||||
}
|
||||
if (_send_message[0] == 0x00) return false; // message is empty! abort
|
||||
_send_state = START;
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("sending "); Serial.println(_send_message);
|
||||
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
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
extern void init485(int RO, int nRE, int DE, int DI);
|
||||
extern void speed485(long pulse_length);
|
||||
extern boolean available485();
|
||||
extern String get485Message();
|
||||
extern String get485message();
|
||||
extern boolean send485(char message[]);
|
||||
#endif
|
||||
|
||||
@@ -1,45 +1,18 @@
|
||||
/*
|
||||
This sketch demonstrates, how to use the SoftRS485 library.
|
||||
This library makes use of Arduinos timer 1
|
||||
*/
|
||||
|
||||
#include <SoftRS485.h>
|
||||
|
||||
int count = 0;
|
||||
String message = "Message ";
|
||||
|
||||
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
|
||||
|
||||
if (send485("Test")) {
|
||||
// This should send "Test" if the line is free.
|
||||
Serial.println("Test sent!");
|
||||
}
|
||||
if (!send485("Test2")) {
|
||||
// This shoult fail, as transmission of "Test" should still be on the way
|
||||
Serial.println("Test2 failed!");
|
||||
init485(2,3,4,5);
|
||||
speed485(8000);
|
||||
boolean sent = false;
|
||||
while (!sent) {
|
||||
sent = send485("This message is sent and received!");
|
||||
}
|
||||
}
|
||||
|
||||
void loop(){
|
||||
if (available485()){ // check if we have received anything
|
||||
Serial.print("messageReceived: ");
|
||||
Serial.println(get485Message()); // read the received message
|
||||
|
||||
// send another message everytime we have received one
|
||||
count++;
|
||||
char msg[128];
|
||||
(message+count).toCharArray(msg,128);
|
||||
if (!send485(msg)){
|
||||
Serial.print("Sending ");
|
||||
Serial.print(msg);
|
||||
Serial.println(" failed!");
|
||||
}
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
if (available485()){
|
||||
Serial.println("Received "+get485message());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user