Master Writes single Coil and Holding Register

This is 3rd tutorial in the Modbus series and today we will see how to use the STM32 as the master, which will Write a single coil and Holding Register. I have already covered reading holding and input Registers in the This tutorial, and Reading coils and discrete Inputs in This one.

Basically we will be covering the function codes FC05 and FC06 in this tutorial.

We will continue with where we left in the previous tutorial. You must see it first as I am going to skip few explanation in this tutorial.

Let’s start with the cubeMX configuration.

The Connection

Below is the connection diagram of the module with the STM32F103C8 controller.

As shown above, The RO pin is connected to the PA10 (UART1 RX) and DI pin is connected to the PA9 (UART1 TX).

The RE and DE are connected together with the pin PA8, which we have set as the output in the MCU.

The CubeMX configuration is shown below

The UART1 is configured to it’s default setup with the baud rate of 115200 and 8-N-1. Also I have enabled the interrupt to receive the data from the second controller.

The pin PA8 is set as output and I have renamed it to the TX_EN pin.

In this tutorial the STM32 will act as a master and since I don’t actually have a slave device, I am going to use a software in the computer that will make the computer to act as a slave device.

The communication will take place using the RS485 standard. STM32 is connected to the RS485 to TTL converter and the computer is connected via the RS485 to USB converter.

This is it for the connection, let’s see the code now.



The Slave Software

As I mentioned above I am going to use a software so the computer can act as a slave device.

The software can be downloaded from https://www.simplymodbus.ca/RTUslave.htm

Some components of the software are explained below

  • We have the Slave ID, which we can set manually.
  • The window in the Green box shows the request sent by the slave (in hex format)
  • The Blue box is the Port configuration. make sure that the master and slave are configured similarly
  • The yellow box shows the data sent by the slave (in hex format)

Since this is a slave device, it already have the memory areas (coils and registers). We can access them by clicking the DATA button (in Black box)

Below is the image of the registers and coils available

Here we are only concerned about the Red box and Green box

  • I have enabled the function code 3 and 1 i.e Reading Holding Registers and coils.
    • This is because the software specifically don’t have the function codes 5 and 6
    • But since I have enabled the Read/Write, we can use the FC 5 and 6.
  • The memory size for the coils is 1 bit and that for the Registers is 16 bit.


Some insight into the code

First We will create a function to send the data via the UART. The modbus module need to be put in the transmit mode before sending the data.

uint8_t RxData[10];
uint8_t TxData[8];

void sendData (uint8_t *data)
{
  HAL_GPIO_WritePin(TX_EN_GPIO_Port, TX_EN_Pin, GPIO_PIN_SET);
  HAL_UART_Transmit(&huart2, data, 8, 1000);
  HAL_GPIO_WritePin(TX_EN_GPIO_Port,TX_EN_Pin , GPIO_PIN_RESET);
}
  • Here I have first defined the RX and TX buffers.
  • The sendData function will be used by the master to send the request to the slave device.
  • Here we will first pull the TX_EN pin (RE and DE Pins) High. This will put the module in the transmitter mode.
  • Then we will send the data via the UART.
  • After sending the data, we will again pull the TX_EN pin LOW, so to put the module in the receive mode.

Writing single coil

Before we actually send the request to the slave device, we need to prepare our TxData buffer.

The request pattern sent by the master to write a single coil is shown in the picture below

As you can see above, the master required to send 8 bytes in total. These contains:

  • 1 Byte for the slave address
  • 1 byte for the function code
  • 2 bytes for the coil Address
  • 2 bytes for the Data
    • If the master want to set the coil, the 2 Data bytes will be 0xFF and 0x00
    • If the master wants to reset the coil, the 2 Data bytes will be 0x00 and 0x00
    • Any other data does not affect the coil state
  • 2 bytes for the CRC at the end.

This is shown in the example below.


TxData[0] = 0x05;  // slave address
TxData[1] = 0x05;  // Force single coil

TxData[2] = 0;  // coil address high
TxData[3] = 0;  // coil address low
//The coil address will be 00000000 00000000 = 0 + 1 = 1

TxData[4] = 0xFF;  // force data high
TxData[5] = 0;  // force data low

uint16_t crc = crc16(TxData, 6);
TxData[6] = crc&0xFF;   // CRC LOW
TxData[7] = (crc>>8)&0xFF;  // CRC HIGH

sendData(TxData);
  • Here the coil address is 0, which means the actual address is 1
  • The data is 0xFF00, which means we are setting the coil at the above address.

Below is the image showing the output.

You can see the coil at the location 1. It was in Reset state, and after the code was executed, the coil was SET.

Similarly, to Reset the coil we have to send the Data 0x00 0x00.


Writing single Register

The request pattern sent by the master to write a single Register is shown in the picture below

As you can see above, the master required to send 8 bytes in total. These contains:

  • 1 Byte for the slave address
  • 1 byte for the function code
  • 2 bytes for the Register Address
  • 2 bytes for the Data
  • 2 bytes for the CRC at the end.

This is shown in the example below


The code to Preset single Register is shown below

TxData[0] = 0x05;  // slave address
TxData[1] = 0x06;  // Preset single Register

TxData[2] = 0;  // Register address high
TxData[3] = 2;  // Register address low
//The coil address will be 00000000 00000101 = 2 + 40001 = 40003

TxData[4] = 0x12;  // Preset data high
TxData[5] = 0x34;  // Preset data low

uint16_t crc = crc16(TxData, 6);
TxData[6] = crc&0xFF;   // CRC LOW
TxData[7] = (crc>>8)&0xFF;  // CRC HIGH

sendData(TxData);
  • Here the Register address, where we want to write the data, is 2. This makes the actual Register address as 40003.
  • The Data we want to write is going to be 0x12 and 0x34.
  • This makes the 16 bit data 0x1234.

Below is the image showing the output

As shown above the Register at the address 40003. The data stored initially at this address was 0.

We have a new data after the code was executed.


Check out the Video Below




Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

Subscribe
Notify of

0 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
keyboard_arrow_up