using modbus.end() in the same way as serial.end()

Hi all

(Working on a Mega 2560)

I am trying to figure how to end a Modbus RS485 serial transmission the same way as you would use Serial.end() to end the standard serial transmission.

I want to be able to completely disable the modbus communication protocol under certain conditions to free up the processor as much as possible. There seems to be the functionality to disable the TX pin, how ever from my understanding that will only disable transmission and not all the functions related to modbus communication. (or am I misunderstanding this)

To start the modbus transmission "master.begin(objects to begin)" is used to start the communication in the case of the library i am using(github).

How ever in the cpp and H files nothing has been defined for master.end().

TX enable/Disable from .cpp file

//-----------------------------------------------------------------------------------
/* Modbus enable transmission
 * @param: none
 * @return: none
 * @private
 * @comment: none
 */
void Modbus::TxEnable()
{
	digitalWrite(_TxEnablePin, HIGH);
}

//-----------------------------------------------------------------------------------
/* Modbus disable transmission
 * @param: none
 * @return: none
 * @private
 * @comment: none
 */
void Modbus::TxDisable()
{
	digitalWrite(_TxEnablePin, LOW);
}

Modbus enable from .cpp file

//-----------------------------------------------------------------------------------
/* Intitialize Modbus config
 * @param: Modbus config
 * 		- Mobus port
 *		- baud: baurate of transmission
 * 		- timeout: time to wait for returned packet
 * 		- polling:	time between two packet
 *		- retry: how many time packet is resent if it was failed
 *		- TxEnablePin: for RS485 only, pin to enable transmission
 * @return: size of packet
 * @private
 * @comment: none
 */
#if defined(__SAM3X8E__)
	void Modbus::begin(USARTClass* modbusPort, long baud, uint8_t byteFormat,long timeout, long polling, uint8_t retry, uint8_t TxEnablePin)
#else
	void Modbus::begin(HardwareSerial* modbusPort, long baud, uint8_t byteFormat, long timeout, long polling, uint8_t retry, uint8_t TxEnablePin)
#endif
{

	/*
	Modbus states that a baud rate higher than 19200 must use a fixed 750 us 
  	for inter character time out and 1.75 ms for a frame delay for baud rates
  	below 19200 the timing is more critical and has to be calculated.
  	E.g. 9600 baud in a 10 bit packet is 9600/10 (8E1) = 960 characters per second
  	In milliseconds this will be 960 characters per 1000ms. So for 1 character
  	1000ms/960 characters is 1.04167ms per character and finally modbus states
  	an inter-character must be 1.5T or 1.5 times longer than a character. Thus
  	1.5T = 1.04167ms * 1.5 = 1.5625ms. A frame delay is 3.5T.
	Thus the formula is T1.5(us) = (1000ms * 1000(us) * 1.5 * 10bits)/baud
	1000ms * 1000(us) * 1.5 * 10bits = 15000000 can be calculated as a constant
	*/

	_baud = baud;
	if (_baud > 19200)
		T1_5 = 750;	
	else
		T1_5 = 15000000/_baud; // 1T * 1.5 = T1.5

	/* 
	The modbus definition of a frame delay is a waiting period of 3.5 character times
	between packets. This is not quite the same as the frameDelay implemented in
	this library but does benifit from it.
	The frameDelay variable is mainly used to ensure that the last character is 
	transmitted without truncation. A value of 2 character times is chosen which
	should suffice without holding the bus line high for too long.
	*/
	
	_frame_delay = T1_5 * 2;

	_modbusPort = modbusPort;

	_byteFormat = byteFormat;
	_timeout = timeout;
	_polling = polling;
	_retry_count = retry;
	_TxEnablePin = TxEnablePin;
#if defined(__SAM3X8E__)
	(*_modbusPort).begin(_baud,SERIAL_8E1);
#else
	(*_modbusPort).begin(_baud,_byteFormat);
#endif

	TxEnableConfig();

	_transmission_ready_flag = true; //start 1st time
}

modbus enable from header file

 //-----------------------------------------------------------------------------------
        /* Config Modbus parameter and Initialize Modbus protocol
         * @param: none
         * @return: none
         * @api
         * @comment: none
         */
#if defined(__SAM3X8E__)
        void begin(USARTClass* modbusPort, long baud, uint8_t byteFormat, long timeout, long polling, uint8_t retry, uint8_t TxEnablePin);
#else
        void begin(HardwareSerial* modbusPort, long baud, uint8_t byteFormat, long timeout, long polling, uint8_t retry, uint8_t _TxEnablePin);
#endif

My code relating to using the library file:

#include "ModbusXT.h"

#define TIMEOUT 500   //Timeout for a failed packet. Timeout need to larger than polling
#define POLLING 2     //Wait time to next request

#define BAUD        57600  
#define RETRIES     10    //How many time to re-request packet frome slave if request is failed
#define BYTE_FORMAT SERIAL_8E1
#define TxEnablePin 2

void COMS_BEGIN(){
  //Config packets and register
 master.configure(packets, NO_OF_PACKET, regs);

  //Config individual packet: (packet, ID, Function, Address, Number of register or data, start register in master register array)
  master.construct(&packets[PACKET1], hmiID, READ_HOLDING_REGISTERS, 100, 15, 0);
  master.construct(&packets[PACKET2], hmiID, PRESET_MULTIPLE_REGISTERS, 120, 15, 15);
  master.construct(&packets[PACKET3], hmiID, PRESET_MULTIPLE_REGISTERS, 140, 7, 30);
  master.begin(&Serial3, BAUD, BYTE_FORMAT, TIMEOUT, POLLING, RETRIES, TxEnablePin);
  COMS_StartUp = 2;
  
}

What I would like to put in the code to stop modbus protocol when needed

master.end(&Serial3, BAUD, BYTE_FORMAT, TIMEOUT, POLLING, RETRIES, TxEnablePin);//Must all the objects be listed here as when master.begin is used?

How should I go about modifying the library to give this functionality? (is it possible?). I have written a separate function from the writing of data to and from the modbus holding registers so that I can disable that when needed.

EDIT: Obviously if I just shove master.end() in then I get Arduino: 'class Modbus' has no member named 'end' ERROR.

I want to be able to completely disable the modbus communication protocol under certain conditions to free up the processor as much as possible.

There is no end() method because it's not necessary. If you don't want processor time to be used, just stop calling the update() method (or any other method of the class).

Maybe I misunderstood your intention but if your goal is to free the processor from the task, not calling any method of the class is the best way to achieve it.

pylon:
There is no end() method because it's not necessary. If you don't want processor time to be used, just stop calling the update() method (or any other method of the class).

Maybe I misunderstood your intention but if your goal is to free the processor from the task, not calling any method of the class is the best way to achieve it.

Thanks if that is all it takes then hopefully I have it covered already, I call the Modbus functions only at certain times using the code like this>

void COMS_BEGIN(){
  //Config packets and register
 master.configure(packets, NO_OF_PACKET, regs);

  //Config individual packet: (packet, ID, Function, Address, Number of register or data, start register in master register array)
  master.construct(&packets[PACKET1], hmiID, READ_HOLDING_REGISTERS, 100, 15, 0);
  master.construct(&packets[PACKET2], hmiID, PRESET_MULTIPLE_REGISTERS, 120, 15, 15);
  master.construct(&packets[PACKET3], hmiID, PRESET_MULTIPLE_REGISTERS, 140, 7, 30);
  master.begin(&Serial3, BAUD, BYTE_FORMAT, TIMEOUT, POLLING, RETRIES, TxEnablePin);
  COMS_StartUp = 2;
  
}
void COMS(){
  if(COMS_StartUp < 2){
  ComsStartmillis = millis();
   if(COMS_StartUp == 0){
    ComsStartmillis1 = millis();
    COMS_StartUp = 1;
    }
   if((COMS_StartUp == 1) && (ComsStartmillis - ComsStartmillis1 > 30000)){//Allow HMI time to boot after power up before enabling coms
    COMS_BEGIN();
    }
  }
     
   master.update();  //polling
   sm = millis();
   //READS
   holding1 = regs[PPR1];
   holding2 = regs[PPR2];
   holding3 = regs[LEFTMAX1];
   holding4 = regs[LEFTMAX2];
   holding5 = regs[RIGHTMAX1];
   holding6 = regs[RIGHTMAX2];
   holding7 = regs[TOOLLEAD];
   holding8 = regs[PULSEWIDTH];
   holding9 = regs[HOMESETZERO];
   holding10 = regs[BACKLASH];
   holding11 = regs[SETSPINDLEZERO];
   holding12 = regs[SETUPCOMPLETE];
   holding13 = regs[READYFORPASS];
   holding14 = regs[PASSDIRECTION];
   holding15 = regs[GOTOSTART];
   sppsr = holding2;
   sppsr = (sppsr << 16) | holding1;
   BackLash = holding10;
   LeadScrewReturnToLead = holding7;
   LeadScrewLeftMAX = holding4;
   LeadScrewLeftMAX = (LeadScrewLeftMAX << 16) | holding3;
   LeadScrewRightMAX = holding6;
   LeadScrewRightMAX = (LeadScrewRightMAX << 16) | holding5;
   //WRITES
   holding16 = (int)DriveCurrentPos;
   holding17 = (int)(DriveCurrentPos >> 16);
   holding18 = (int)SpindleDeg;
   holding19 = (int)(SpindleDeg >> 16);
   holding20 = (int)SpindleRPM;
   holding21 = (int)(SpindleRPM >> 16);
   holding22 = PassComplete;
   holding23 = (int)DriveCurrentPos;
   holding24 = (int)(DriveCurrentPos >> 16);
   holding25 = (int)LeadScrewLeftMAX;
   holding26 = (int)(LeadScrewLeftMAX >> 16);
   holding27 = (int)LeadScrewRightMAX;
   holding28 = (int)(LeadScrewRightMAX >> 16);
   regs[LEADSCREWPOS1] = holding16;
   regs[LEADSCREWPOS2] = holding17;
   regs[SPINDLE_DEG1] = holding18;
   regs[SPINDLE_DEG2] = holding19;
   regs[SPINDLE_RPM1] = holding20;
   regs[SPINDLE_RPM2] = holding21;
   regs[PASSCOMPLETE] = holding22;
   regs[TOOLPOSITION1] = holding23;
   regs[TOOLPOSITION2] = holding24;
   regs[LEFTMAXWRITE1] = holding25;
   regs[LEFTMAXWRITE2] = holding26;
   regs[RIGHTMAXWRITE1] = holding27;
   regs[RIGHTMAXWRITE2] = holding28;
   regs[INPOSITION] = holding29;
   regs[PASSNUMBER] = holding30;
   regs[total_packets] = NO_OF_PACKET;            
   regs[total_requests] = master.total_requests();
   regs[total_failed] = master.total_failed(); 
   regs[DRIVEJOG] = holding31;    
  if ( (sm-dm) > 1000) //update 1s
   {
     dm = sm;
     regs[transfer_rate] = regs[total_requests] - temp;
     temp = regs[total_requests];
     regs[transfer_delay] = (unsigned int) ((NO_OF_PACKET*100000UL)/regs[transfer_rate]);
   }
}

Elsewhere in my code the COMS function is called when needed. Each time it is called it calls the coms start up function again.