55 * @author Samuel Marco i Armengol
6677 * @contribution Helium6072
8+ * @contribution gabrielsan
89 *
910 * @description
1011 * Arduino library for communicating with Modbus devices
@@ -167,7 +168,7 @@ class Modbus
167168 uint16_t *au16regs;
168169 uint16_t u16InCnt, u16OutCnt, u16errCnt;
169170 uint16_t u16timeOut;
170- uint32_t u32time, u32timeOut;
171+ uint32_t u32time, u32timeOut, u32overTime ;
171172 uint8_t u8regsize;
172173
173174 void init (uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
@@ -194,9 +195,9 @@ class Modbus
194195 Modbus (uint8_t u8id);
195196 void begin (long u32speed);
196197 void begin (SoftwareSerial *sPort , long u32speed);
197- void begin (long u32speed, uint8_t u8config);
198+ // void begin(long u32speed, uint8_t u8config);
198199 void begin ();
199- void setTimeOut ( uint16_t u16timeout ); // !<write communication watch-dog timer
200+ void setTimeOut ( uint16_t u16timeOut ); // !<write communication watch-dog timer
200201 uint16_t getTimeOut (); // !<get communication watch-dog timer value
201202 boolean getTimeOutState (); // !<get communication watch-dog timer state
202203 int8_t query ( modbus_t telegram ); // !<only for master
@@ -209,6 +210,7 @@ class Modbus
209210 uint8_t getState ();
210211 uint8_t getLastError (); // !<get last error message
211212 void setID ( uint8_t u8id ); // !<write new ID for the slave
213+ void setTxendPinOverTime ( uint32_t u32overTime );
212214 void end (); // !<finish any communication and release serial communication port
213215};
214216
@@ -372,7 +374,7 @@ void Modbus::begin(SoftwareSerial *sPort, long u32speed)
372374 * @param config data frame settings (data length, parity and stop bits)
373375 * @ingroup setup
374376 */
375- void Modbus::begin (long u32speed,uint8_t u8config)
377+ /* void Modbus::begin(long u32speed,uint8_t u8config)
376378{
377379
378380 switch( u8serno )
@@ -411,7 +413,7 @@ void Modbus::begin(long u32speed,uint8_t u8config)
411413 while(port->read() >= 0);
412414 u8lastRec = u8BufferSize = 0;
413415 u16InCnt = u16OutCnt = u16errCnt = 0;
414- }
416+ } */
415417
416418/* *
417419 * @brief
@@ -443,6 +445,21 @@ void Modbus::setID( uint8_t u8id)
443445 }
444446}
445447
448+ /* *
449+ * @brief
450+ * Method to write the overtime count for txend pin.
451+ * It waits until count reaches 0 after the transfer is done.
452+ * With this, you can extend the time between txempty and
453+ * the falling edge if needed.
454+ *
455+ * @param uint32_t overtime count for txend pin
456+ * @ingroup setup
457+ */
458+ void Modbus::setTxendPinOverTime ( uint32_t u32overTime )
459+ {
460+ this ->u32overTime = u32overTime;
461+ }
462+
446463/* *
447464 * @brief
448465 * Method to read current slave ID address
@@ -481,7 +498,7 @@ void Modbus::setTimeOut( uint16_t u16timeOut)
481498 */
482499boolean Modbus::getTimeOutState ()
483500{
484- return (millis () > u32timeOut );
501+ return (( unsigned long )( millis () -u32timeOut) > ( unsigned long )u16timeOut );
485502}
486503
487504/* *
@@ -668,7 +685,7 @@ int8_t Modbus::poll()
668685 else
669686 u8current = softPort->available ();
670687
671- if (millis () > u32timeOut )
688+ if (( unsigned long )( millis () -u32timeOut) > ( unsigned long )u16timeOut )
672689 {
673690 u8state = COM_IDLE;
674691 u8lastError = NO_REPLY;
@@ -682,10 +699,10 @@ int8_t Modbus::poll()
682699 if (u8current != u8lastRec)
683700 {
684701 u8lastRec = u8current;
685- u32time = millis () + T35 ;
702+ u32time = millis ();
686703 return 0 ;
687704 }
688- if (millis () < u32time ) return 0 ;
705+ if (( unsigned long )( millis () -u32time) < ( unsigned long )T35 ) return 0 ;
689706
690707 // transfer Serial buffer frame to auBuffer
691708 u8lastRec = 0 ;
@@ -764,10 +781,10 @@ int8_t Modbus::poll( uint16_t *regs, uint8_t u8size )
764781 if (u8current != u8lastRec)
765782 {
766783 u8lastRec = u8current;
767- u32time = millis () + T35 ;
784+ u32time = millis ();
768785 return 0 ;
769786 }
770- if (millis () < u32time ) return 0 ;
787+ if (( unsigned long )( millis () -u32time) < ( unsigned long )T35 ) return 0 ;
771788
772789 u8lastRec = 0 ;
773790 int8_t i8state = getRxBuffer ();
@@ -790,7 +807,7 @@ int8_t Modbus::poll( uint16_t *regs, uint8_t u8size )
790807 return u8exception;
791808 }
792809
793- u32timeOut = millis () + long (u16timeOut) ;
810+ u32timeOut = millis ();
794811 u8lastError = 0 ;
795812
796813 // process message
@@ -827,9 +844,10 @@ int8_t Modbus::poll( uint16_t *regs, uint8_t u8size )
827844void Modbus::init (uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin)
828845{
829846 this ->u8id = u8id;
830- this ->u8serno = (u8serno > 3 ) ? 0 : u8serno;
847+ this ->u8serno = u8serno;
831848 this ->u8txenpin = u8txenpin;
832849 this ->u16timeOut = 1000 ;
850+ this ->u32overTime = 0 ;
833851}
834852
835853void Modbus::init (uint8_t u8id)
@@ -838,6 +856,7 @@ void Modbus::init(uint8_t u8id)
838856 this ->u8serno = 4 ;
839857 this ->u8txenpin = 0 ;
840858 this ->u16timeOut = 1000 ;
859+ this ->u32overTime = 0 ;
841860}
842861
843862/* *
@@ -902,72 +921,28 @@ void Modbus::sendTxBuffer()
902921 u8BufferSize++;
903922 au8Buffer[ u8BufferSize ] = u16crc & 0x00ff ;
904923 u8BufferSize++;
905-
906- // set RS485 transceiver to transmit mode
924+
907925 if (u8txenpin > 1 )
908926 {
909- switch ( u8serno )
910- {
911- #if defined(UBRR1H)
912- case 1 :
913- UCSR1A=UCSR1A |(1 << TXC1);
914- break ;
915- #endif
916-
917- #if defined(UBRR2H)
918- case 2 :
919- UCSR2A=UCSR2A |(1 << TXC2);
920- break ;
921- #endif
922-
923- #if defined(UBRR3H)
924- case 3 :
925- UCSR3A=UCSR3A |(1 << TXC3);
926- break ;
927- #endif
928- case 0 :
929- default :
930- UCSR0A=UCSR0A |(1 << TXC0);
931- break ;
932- }
927+ // set RS485 transceiver to transmit mode
933928 digitalWrite ( u8txenpin, HIGH );
934929 }
935930
936931 // transfer buffer to serial line
937- if (u8serno< 4 )
932+ if (u8serno < 4 )
938933 port->write ( au8Buffer, u8BufferSize );
939934 else
940935 softPort->write ( au8Buffer, u8BufferSize );
941936
942- // keep RS485 transceiver in transmit mode as long as sending
943937 if (u8txenpin > 1 )
944938 {
945- switch ( u8serno )
946- {
947- #if defined(UBRR1H)
948- case 1 :
949- while (!(UCSR1A & (1 << TXC1)));
950- break ;
951- #endif
952-
953- #if defined(UBRR2H)
954- case 2 :
955- while (!(UCSR2A & (1 << TXC2)));
956- break ;
957- #endif
958-
959- #if defined(UBRR3H)
960- case 3 :
961- while (!(UCSR3A & (1 << TXC3)));
962- break ;
963- #endif
964- case 0 :
965- default :
966- while (!(UCSR0A & (1 << TXC0)));
967- break ;
968- }
969-
939+ // must wait transmission end before changing pin state
940+ // soft serial does not need it since it is blocking
941+ if (u8serno < 4 )
942+ port->flush ();
970943 // return RS485 transceiver to receive mode
944+ volatile uint32_t u32overTimeCountDown = u32overTime;
945+ while ( u32overTimeCountDown-- > 0 );
971946 digitalWrite ( u8txenpin, LOW );
972947 }
973948 if (u8serno<4 )
@@ -978,7 +953,7 @@ void Modbus::sendTxBuffer()
978953 u8BufferSize = 0 ;
979954
980955 // set time-out for master
981- u32timeOut = millis () + ( unsigned long ) u16timeOut ;
956+ u32timeOut = millis ();
982957
983958 // increase message counter
984959 u16OutCnt++;
0 commit comments