Modbus library change for RS485 transmission

Hi guys!

Almost there. i have the communications working. my problem is that the library i’m using doesn’t support enabling the transmit pin for the rs 485 connection. I have 2 options:

  • get a TTL to 485 converter that’s auto-sensing
  • change the library to enable a transmit pin in the code.

the code below is the "Run"command from the CPP file from the modbus library (Jason Vreeland). could anyone help me to build in an extra variable that i can give as an argument in the arduino code so it writes a pin high?

void modbusSlave::run(void)
{

	byte deviceId;
	byte funcType;
	word field1;
	word field2;
	
	int i;
	
	//initialize mesasge length
	_len = 0;

	//check for data in the recieve buffer
	this->checkSerial();

	//if there is nothing in the recieve buffer, bail.
	if(_len == 0)
	{
		return;
	}

	//retrieve the query message from the serial uart
	this->serialRx();
	
	//if the message id is not 255, and
	// and device id does not match bail
	if( (_msg[0] != 0xFF) && 
		(_msg[0] != _device->getId()) )
	{
		return;
	}
	//calculate the checksum of the query message minus the checksum it came with.
	this->calcCrc();

	//if the checksum does not match, ignore the message
	if ( _crc != ((_msg[_len - 2] << 8) + _msg[_len - 1]))
		return;
	
	//copy the function type from the incoming query
	funcType = _msg[1];

	//copy field 1 from the incoming query
	field1	= (_msg[2] << 8) | _msg[3];

	//copy field 2 from the incoming query
	field2  = (_msg[4] << 8) | _msg[5];
	
	//free the allocated memory for the query message
	free(_msg);
	//reset the message length;
	_len = 0;

	//generate query response based on function type
	switch(funcType)
	{
	case READ_DI:
		this->getDigitalStatus(funcType, field1, field2);
		break;
	case READ_DO:
		this->getDigitalStatus(funcType, field1, field2);
		break;
	case READ_AI:
		this->getAnalogStatus(funcType, field1, field2);
		break;
	case READ_AO:
		this->getAnalogStatus(funcType, field1, field2);
		break;
	case WRITE_DO:
		this->setStatus(funcType, field1, field2);
		break;
	case WRITE_AO:
		this->setStatus(funcType, field1, field2);
		break;
	default:
		return;
		break;
	}

	//if a reply was generated
	if(_len)
	{
		int i;
		//send the reply to the serial UART
		//Senguino doesn't support a bulk serial write command....
		for(i = 0 ; i < _len ; i++)
			Serial.write(_msg[i]);
		//free the allocated memory for the reply message
		free(_msg);
		//reset the message length
		_len = 0;
	}
}

For full duplex operation you can use 2 RS-485 converters, one for RX and one for TX, In half duplex mode you risk to miss characters.

Hello DrDiettrich,

I only need to run half duplex. but I need to get the library to make a pin high for the data transmit from the TTL side for the DE pin.

Do you have any idea's on this?

If you only need to receive, you can configure the converter for input only. This typically means to pull DE/RE permanently low, using e.g. a piece of wire or a pullup resistor. See your converter data sheet for the required levels.

In software you can switch these pins to the required transmit level only while sending bytes, and keep them for receive mode otherwise.

Well it's a modbus protocol so i have to send and receive. and changing this in the software is exactly what i wanted but it had to be done in the CPP file of the library.

However, i found a better modbus library which includes the function codes i need and supports a transmit pin :slight_smile: so problem solved.

Library used:

modbus.h and modbus.serial was the answer..

thanks for the help!