@ -9,136 +9,50 @@
//#define DEBUG
//#define DEBUG
# define MSG_LEN 64
# define MSG_LEN 64
# define IDLE 0
# define START 1
# define RECEIVING 2
# define SENDING 3
# define COMPLETE 4
// Pins
// Pins
int _RO , _RE , _DE , _DI ;
int _RO , _RE , _DE , _DI ;
int _idle_cycles = 0 ;
long _pulse_len = 100 ;
/* INCOMING */
// Receive vars
char _recv_message [ MSG_LEN ] ;
byte _recv_byte = 0x00 ;
byte _recv_state = IDLE ;
boolean _recv_bit = false ;
boolean _recv_bit = false ;
byte _recv_idx = 0 ;
long _last_flip ; // this is the time when the bus switched to logical zero
int _recv_pos = 0 ;
byte _recv_msg [ MSG_LEN ] ;
int _recv_pos = 0 ;
int _recv_idx = 0 ;
boolean _avail = false ;
/* OUTGOING */
char _send_message [ MSG_LEN ] ;
void interrupt485 ( ) {
boolean _send_bit = false ;
_recv_bit = ! digitalRead ( _RO ) ; // HIGH level = logical zero and vice versa
byte _send_state = IDLE ;
long now = micros ( ) ;
byte _send_wait = 0 ;
long diff = now - _last_flip ;
byte _send_idx = 0 ;
_last_flip = now ;
int _send_pos = 0 ;
if ( diff > 20 * _pulse_len ) { // we received a start bit
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 ) ;
# ifdef DEBUG
Serial . print ( " Sending bit " ) ; Serial . print ( _send_idx ) ; Serial . print ( " of " ) ; Serial . print ( c ) ; Serial . print ( " : " ) ; Serial . print ( _send_bit ) ; Serial . print ( " / " ) ;
# 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
# ifdef DEBUG
Serial . print ( " Sent start bit: " ) ; Serial . print ( _send_bit ) ; Serial . print ( " / " ) ;
Serial . print ( F ( " State changed to " ) ) ; Serial . println ( _recv_bit ) ;
Serial . println ( F ( " received start bit " ) ) ;
# endif
# 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 ( " \n COLLISION " ) ;
# 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_pos = 0 ;
_recv_idx = 0 ;
_recv_idx = 0 ;
_recv_state = RECEIVING ;
_last_flip + = _pulse_len ;
# ifdef DEBUG
} else {
Serial . print ( " Start reception / " ) ;
long count = diff / _pulse_len ;
# endif
for ( int i = 0 ; i < count ; i + + ) {
}
if ( _recv_idx = = 0 ) {
_recv_msg [ _recv_pos ] = ( ! _recv_bit ) ;
if ( _recv_bit & & _recv_state = = IDLE ) {
} else {
_recv_state = START ;
_recv_msg [ _recv_pos ] | = ( ! _recv_bit ) < < _recv_idx ;
}
}
_recv_idx + + ;
if ( _recv_state = = RECEIVING ) {
if ( _recv_idx = = 8 ) {
_recv_byte | = _recv_bit < < _recv_idx ; // set bit
_recv_idx = 0 ;
_recv_idx + + ; // increase bit index
if ( _recv_msg [ _recv_pos ] = = 0x00 ) {
if ( _recv_idx = = 8 ) { // byte full
_avail = _recv_pos ! = 0 ;
# ifdef DEBUG
return ;
Serial . print ( " pushing " ) ; Serial . print ( ( char ) _recv_byte ) ; Serial . print ( " / " ) ;
}
# endif
_recv_pos + + ;
_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 ) {
@ -146,8 +60,7 @@ void init485(int RO, int nRE, int DE, int DI){
_RE = nRE ;
_RE = nRE ;
_DE = DE ;
_DE = DE ;
_DI = DI ;
_DI = DI ;
_recv_message [ 0 ] = 0x00 ; // empty
_send_message [ 0 ] = 0x00 ; // empty
pinMode ( _RO , INPUT ) ;
pinMode ( _RO , INPUT ) ;
pinMode ( _RE , OUTPUT ) ;
pinMode ( _RE , OUTPUT ) ;
@ -159,46 +72,93 @@ void init485(int RO, int nRE, int DE, int DI){
pinMode ( _DI , OUTPUT ) ;
pinMode ( _DI , OUTPUT ) ;
digitalWrite ( _DI , LOW ) ; // output line = LOW
digitalWrite ( _DI , LOW ) ; // output line = LOW
TCCR1A = 0 ; // Init Timer1A
attachInterrupt ( digitalPinToInterrupt ( _RO ) , interrupt485 , CHANGE ) ;
TCCR1B = 0 ; // Init Timer1B
TCCR1B | = B00000001 ; // Prescaler = 1
OCR1A = 3328 ; // Timer Compare1A Register
TIMSK1 | = B00000010 ; // Enable Timer COMPA Interrupt
# ifdef DEBUG
# ifdef DEBUG
Serial . begin ( 115200 ) ;
Serial . begin ( 115200 ) ;
Serial . println ( " Started timer! " ) ;
Serial . print ( F ( " RO = " ) ) ;
Serial . print ( " RO = " ) ;
Serial . println ( _RO ) ;
Serial . println ( _RO ) ;
Serial . print ( " ^RE = " ) ;
Serial . print ( F ( " ^RE = " ) ) ;
Serial . println ( _RE ) ;
Serial . println ( _RE ) ;
Serial . print ( " DE = " ) ;
Serial . print ( F ( " DE = " ) ) ;
Serial . println ( _DE ) ;
Serial . println ( _DE ) ;
Serial . print ( " DI = " ) ;
Serial . print ( F ( " DI = " ) ) ;
Serial . println ( _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
# endif
}
}
boolean available485 ( ) {
boolean available485 ( ) {
return _recv_state = = IDLE & & _recv_message [ 0 ] ! = 0 ;
return _avail ;
}
}
String get485Message ( ) {
String get485message ( ) {
String res = String ( _recv_message ) ;
_avail = false ;
_recv_message [ 0 ] = 0 ;
return String ( ( char * ) _recv_msg ) ;
return res ;
}
}
boolean send485 ( char message [ ] ) {
boolean writeBit ( boolean bit ) {
if ( _send_message [ 0 ] ! = 0x00 ) return false ; // we already have a queued message, abort!
digitalWrite ( _DI , ! bit ) ;
for ( int idx = 0 ; idx < MSG_LEN ; idx + + ) {
delayMicroseconds ( 5 ) ;
_send_message [ idx ] = message [ idx ] ; // copy message
if ( _recv_bit ! = bit ) { // collision!
if ( message [ idx ] = = 0x00 ) break ;
digitalWrite ( _DE , LOW ) ;
# ifdef DEBUG
Serial . println ( F ( " Collision! " ) ) ;
# endif
return false ;
}
}
if ( _send_message [ 0 ] = = 0x00 ) return false ; // message is empty! abort
delayMicroseconds ( _pulse_len - 5 ) ;
_send_state = START ;
return true ;
}
boolean send485 ( char message [ ] ) {
# ifdef DEBUG
# 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
# 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 ;
}
}