Tuesday, October 5, 2021

16 Channel RS485 Modbus Relay Board

Controlling a 16 channel RS485 Modbus relay board is discussed in this post. The board needs to be powered with a 12V power supply. It has has a DIP switch to set its ID. If only the switch 1 is on and others are off, its ID will be 1. To communicate the board from a PC, a USB to RS485 converter can be used. The setup is illustrated in the following figure.


Figure 1. RS485 relay board using 12 V power supply, and a USB converter.


Alternatively, you can use a USB UART adapter together with a UART to RS485 converter. Wire connection for this setup is shown below.


Figure 2. Wire connection for UART to RS485 converter.


Unlike conventional RS485 devices, these devices do not have the control line for transmit or receive. They use autoflow control as shown below.


Figure 3. RS485 autoflow control.


Modbus

Commands for this relay board are based on Modbus RTU frame format used on asynchronous serial data lines such as RS-485 (See https://en.wikipedia.org/wiki/Modbus).

The payload for relay control command consists of following fields.
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8
Slave ID Function Address MSB Address LSB Action Delay CRC1 CRC2


The definitions for each field are listed as follows.
  • Slave ID (Board number [ 0 - 31 ] which is set by the DIP switch on the relay board)
  • Function (Value = 6 : control)
  • Address ( [ 1 - 16 ] relay number)
  • Action
    1. open (turn on the switch)
    2. close (turn off the switch)
    3. toggle (self locking)
    4. latch (interlocking)
    5. momentary (non locking)
    6. delay (set period accordingly)
    7. openall (open all relays)
    8. closeall relays (close all relays)
  • Delay (duration in seconds [ 0 - 255 ])
For example, commands to open, close or toggle relay 1 are as follows. The relay board replies back the same command for control.

01 06 00 01 01 00 D9 9A
01 06 00 01 02 00 D9 6A  
01 06 00 01 03 00 D8 FA 


The payload for relay read command consists of following fields.
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8
Slave ID Function Address MSB Address LSB Data MSB Data LSB CRC1 CRC2


The definitions for each field are listed as follows.
  • Slave ID (Board number [ 0 - 31 ] which is set by the DIP switch on the relay board)
  • Function (Value = 3 : read)
  • Address ( [ 1 - 16 ] relay number)
  • MSB of number of relays to read (for read function 3)
  • Number of relays to read [ 1 - 16 ]
For example, command to read relay 1 is as follows.

01 03 00 01 00 01 D5 CA


Relay board replies the following command assuming relay 1 is open.

01 03 02 00 01 79 84


The payload for read reply command consists of following fields.
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 ... Byte (Length*2 + 5) Byte (Length*2 + 5)
Slave ID Function Data Length Data MSB Data LSB ... CRC1 CRC2


Let us use a serial port utility Hercules SETUP utility to open the com port for the RS485 device attached to the computer using 9600 8N1, and to send the example control commands as shown in the following figure.


Figure 4. Sending control command using Hercules utility to open and close relay 1.


C++ Code

In this section, I will discuss some C++ code about sending modbus command frame. Modbus command needs CRC16 at the end of each command frame. The following C++ function shows an implementation for modbus CRC16 calculation.

//Inputs
//s : pointer to input char string
//len: string len (maximum 255)
//crc: initial CRC value

//Output
//Returns calculated CRC

// Ref: http://cool-emerald.blogspot.com/2009/09/crc-calculation-in-vb-and-c.html
uint16_t ceModbus::CRC16(char* s, size_t len, uint16_t crc)
{
	//CRC Order: 16
	//CRC Poly: 0x8005 <=> A001
	//Operational initial value:  0xFFFF
	//Final xor value: 0
	size_t i, j;
	for (i = 0; i < len; i++, s++) {
		crc ^= ((unsigned int)(*s)) & 0xFF;
		for (j = 0; j < 8; j++)	{
			if (crc & 0x0001) crc = (crc >> 1) ^ 0xA001;
			else crc >>= 1;
		}
	}
	return (crc & 0xFFFF);//truncate last 16 bit
}


I have written a class for sending and receiving modbus commands. The C++ source code is availabe at the following links.

ceModbus.h

ceModbus.cpp

Some example C++ programs using this class are availabe at the following links.

testModbus.cpp

ModbusCmd.cpp

You can find the compiled binary file for ModbusCmd program at the following release link also.

https://github.com/yan9a/ceutil/releases/tag/v0.1-alpha

Extract ModbusCmd.zip from the above link and run "ModbusCmd.exe" to send commands to the relay board as shown in the following figure.


Figure 5. Set serial port and open the port to send commands.


You can choose command parameters on drop down boxes and click send button. Alternatively, you can define custom command in Cmd text box, and the program will append CRC to that command and send when you click 'Send Cmd' button.

Arduino

To control the relay board from Arduino, the following is an example program using Arduino Due.

modbus-relay-control-arduino-due

It uses two serials - first serial to send control message from Serial monitor and the second serial, serail1, to send modbus command to relay through RS485 converter. From serial monitor on Arduino IDE, you can send 2 characters to control relay:

First char = o: open, c: close, t: toggle

Second char = 1 -9, a - g from relay 1 to 16

The setup is shown in the following figure.


Figure 6. Arduino Due connection for relay board control.


Arduino Relay Board Emulator

Additionally, you can also emulate an arduino as relay board, in case you needed to do so. The following setup shows Arduino Pro Mini using as a relay board with 4 relays.


Figure 7. Arduino Pro Mini as a relay board emulator.


The program is available at the following link.

modbus-relay-emulator-arduino-pro-mini

No comments:

Post a Comment

Comments are moderated and don't be surprised if your comment does not appear promptly.