{"id":4302,"date":"2026-03-21T09:35:49","date_gmt":"2026-03-21T09:35:49","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4302"},"modified":"2026-03-21T09:35:51","modified_gmt":"2026-03-21T09:35:51","slug":"modbus-sensor-emulation-part-6-master-sends-write-to-register","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4302","title":{"rendered":"Modbus Sensor Emulation Part 6: Master Sends Write to Register"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-1024x683.png\" alt=\"\" class=\"wp-image-4303\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/image-1.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Part 6 focuses on implementing the master-side firmware required to perform write operations to specific registers on the Modbus RTU slave. This section covers constructing valid write request frames, managing data payload formatting, and ensuring proper handling of slave acknowledgments for reliable configuration updates.<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Write to register.<\/li>\n\n\n\n<li>Firmware Implementation.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Write to Register:<\/h2>\n\n\n\n<p>Before we actually send the request to the slave device, we need to prepare our TxData buffer.<\/p>\n\n\n\n<p>The request pattern sent by the master to write multiple coils is shown in the picture below<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"818\" height=\"246\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1.avif\" alt=\"\" class=\"wp-image-4304\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1.avif 818w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1-300x90.avif 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1-768x231.avif 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1-750x226.avif 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1-400x120.avif 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/modbus6_1-250x75.avif 250w\" sizes=\"(max-width: 818px) 100vw, 818px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Here the DATA field consists of the start address, the coil address where the modification begins<\/li>\n\n\n\n<li>The no of points, the number of coils master wants to modify<\/li>\n\n\n\n<li>The Byte count, the number of bytes master will be sending<\/li>\n\n\n\n<li>The DATA itself (for the coils)<\/li>\n<\/ul>\n\n\n\n<p>The number of points and Byte count are different. Here in case of coils, the size of data for each coil is 1 Bit. We also know that the data can be only transferred in bytes.<\/p>\n\n\n\n<p>So if the master wants to write upto 8 coils, it needs to send 1 byte of data. Similarly if the master wants to write upto 16 coils it needs to send 2 Bytes of data.<\/p>\n\n\n\n<p>Even if the master wants to write 9 coils, it still need to send 2 bytes of data for the same.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Firmware Implementation:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>In master project, open modbus.h header file.<\/p>\n\n\n\n<p>Within the header, in <strong>modbusTypedefStruct<\/strong>, within the data structure, declare the following the element:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t  Byte_Count;<\/pre><\/div>\n\n\n\n<p>Hence, the updated <strong>modbusTypedefStruct<\/strong> is as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">typedef struct\n{\n\tuint8_t Slave_Address;\n\tuint8_t Function_Code;\n\tuint16_t Register_Address;\n\tuint16_t Number_of_Data;\n\tuint8_t  Byte_Count;\n\n}modbusTypedefStruct;<\/pre><\/div>\n\n\n\n<p>Furthermore, declare the following define statement to handle single and multiple write request as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define SingleWrite 0x06\n#define MultiWrite  0x10<\/pre><\/div>\n\n\n\n<p>Next, declare the following function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void Modbus_WriteRequest(modbusTypedefStruct *ModbusFrame, uint8_t *data);<\/pre><\/div>\n\n\n\n<p>This function shall send the modbus frame over RS485 bus.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the updated header file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef INC_MODBUS_H_\n#define INC_MODBUS_H_\n\n#include &quot;main.h&quot;\n\n#include &quot;stdint.h&quot;\n\n#define SingleWrite 0x06\n#define MultiWrite  0x10\n\n\ntypedef struct\n{\n\tuint8_t Slave_Address;\n\tuint8_t Function_Code;\n\tuint16_t Register_Address;\n\tuint16_t Number_of_Data;\n\tuint8_t  Byte_Count;\n\n}modbusTypedefStruct;\n\nvoid Modbus_ReadRequest(modbusTypedefStruct * ModbusFrame);\n\nvoid Modbus_WriteRequest(modbusTypedefStruct *ModbusFrame, uint8_t *data);\n\n#endif \/* INC_MODBUS_H_ *\/<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, open Modbus.c source file.<\/p>\n\n\n\n<p>Within the source file, declare the following function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void Modbus_WriteRequest(modbusTypedefStruct *ModbusFrame, uint8_t *data)<\/pre><\/div>\n\n\n\n<p>Within the function:<\/p>\n\n\n\n<p>Extract the needed informations such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Address<\/li>\n\n\n\n<li>Function code.<\/li>\n\n\n\n<li>Register address.<\/li>\n\n\n\n<li>Number of data.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t address = ModbusFrame-&gt;Slave_Address;\nuint8_t func    = ModbusFrame-&gt;Function_Code;\nuint16_t regAdd = ModbusFrame-&gt;Register_Address;\nuint16_t numData = ModbusFrame-&gt;Number_of_Data;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, calculate byte counts as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t byteCount = numData * 2;<\/pre><\/div>\n\n\n\n<p>Assuming the register can hold 2 bytes of data, hence the byte count shall be number of data*2.<\/p>\n\n\n\n<p>Create a buffer to hold the data to be transmitted as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t buffer[9 + byteCount];<\/pre><\/div>\n\n\n\n<p>Fill the buffer as shown in image in section 1 of this guide as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">buffer[0] = address;\nbuffer[1] = func;\nbuffer[2] = (regAdd &gt;&gt; 8) &amp; 0xFF;\nbuffer[3] = (regAdd) &amp; 0xFF;\nbuffer[4] = (numData &gt;&gt; 8) &amp; 0xFF;\nbuffer[5] = (numData) &amp; 0xFF;\nbuffer[6] = byteCount;<\/pre><\/div>\n\n\n\n<p>Copy the payload to the buffer as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/\/ Copy payload (external data buffer)\nfor (int i = 0; i &lt; byteCount; i++)\n{\n  buffer[7 + i] = data[i];\n}<\/pre><\/div>\n\n\n\n<p>Calculate the CRC value:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/\/ CRC calculation\nuint16_t crc = crc16(buffer, 7 + byteCount);<\/pre><\/div>\n\n\n\n<p>Fill the buffer with the CRC value as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">buffer[7 + byteCount] = crc &amp; 0xFF;          \/\/ CRC Low\nbuffer[8 + byteCount] = (crc &gt;&gt; 8) &amp; 0xFF;   \/\/ CRC High<\/pre><\/div>\n\n\n\n<p>Finally, send the data over RS485:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/\/ Enable RS-485 TX\nHAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);\n\n\/\/ Transmit frame\nHAL_UART_Transmit(&amp;huart1, buffer, 9 + byteCount, 100);\n\n\/\/ Enable RS-485 RX\nHAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);<\/pre><\/div>\n\n\n\n<p>Hence, the function as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void Modbus_WriteRequest(modbusTypedefStruct *ModbusFrame, uint8_t *data)\n{\n    uint8_t address = ModbusFrame-&gt;Slave_Address;\n    uint8_t func    = ModbusFrame-&gt;Function_Code;\n    uint16_t regAdd = ModbusFrame-&gt;Register_Address;\n    uint16_t numData = ModbusFrame-&gt;Number_of_Data;\n\n    uint8_t byteCount = numData * 2;\n\n    uint8_t buffer[9 + byteCount];\n\n    buffer[0] = address;\n    buffer[1] = func;\n    buffer[2] = (regAdd &gt;&gt; 8) &amp; 0xFF;\n    buffer[3] = (regAdd) &amp; 0xFF;\n    buffer[4] = (numData &gt;&gt; 8) &amp; 0xFF;\n    buffer[5] = (numData) &amp; 0xFF;\n    buffer[6] = byteCount;\n\n    \/\/ Copy payload (external data buffer)\n    for (int i = 0; i &lt; byteCount; i++)\n    {\n        buffer[7 + i] = data[i];\n    }\n\n    \/\/ CRC calculation\n    uint16_t crc = crc16(buffer, 7 + byteCount);\n\n    buffer[7 + byteCount] = crc &amp; 0xFF;          \/\/ CRC Low\n    buffer[8 + byteCount] = (crc &gt;&gt; 8) &amp; 0xFF;   \/\/ CRC High\n\n    \/\/ Enable RS-485 TX\n    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);\n\n    \/\/ Transmit frame\n    HAL_UART_Transmit(&amp;huart1, buffer, 9 + byteCount, 100);\n\n    \/\/ Enable RS-485 RX\n    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, open main.c of the master project.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In user code begin PV, declare the following array which will hold the data to be transmitted as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t TxBuffer[BufferSize];<\/pre><\/div>\n\n\n\n<p>In user code begin 3 in the while 1 function:<\/p>\n\n\n\n<p>Send data to multiple registers as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">DataFrame.Slave_Address   = 0x11;\nDataFrame.Function_Code   = MultiWrite;\nDataFrame.Register_Address = 0x0001;\nDataFrame.Number_of_Data   = 2;\n\nTxBuffer[0] = random()%255;  \/\/ Register 0x0001 High\nTxBuffer[1] = random()%255;  \/\/ 100\n\nTxBuffer[2] = random()%255;  \/\/ Register 0x0002 High\nTxBuffer[3] = random()%255;  \/\/ 200\n\nModbus_WriteRequest(&amp;DataFrame, TxBuffer);\n\nHAL_Delay(1000);<\/pre><\/div>\n\n\n\n<p>Currently, we are sending random data.<\/p>\n\n\n\n<p>For writing single register:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">DataFrame.Slave_Address   = 0x11;\nDataFrame.Function_Code   = SingleWrite;\nDataFrame.Register_Address = 0x0001;\nDataFrame.Number_of_Data   = 1;\n\n\nTxBuffer[0] = random()%255;  \/\/ Register 0x0001 High\nTxBuffer[1] = random()%255;  \/\/ 100\n\nModbus_WriteRequest(&amp;DataFrame, TxBuffer);\n\nHAL_Delay(1000);<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for the master firmware.<\/p>\n\n\n\n<p>Save, build and run the project as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"34\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-1024x34.jpg\" alt=\"\" class=\"wp-image-4132\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-1024x34.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-300x10.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-768x26.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-1536x51.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-1150x38.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-750x25.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-400x13.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13-250x8.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-31_11-12-13.jpg 1986w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Results:<\/h2>\n\n\n\n<p>By using either oscilloscope or logic analyzer, probe the TX line of the UART and you should get the following:<\/p>\n\n\n\n<p>For multiple register write:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9.png\" alt=\"\" class=\"wp-image-4306\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9-300x185.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9-768x473.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9-750x461.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9-400x246.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS9-250x154.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>For single register write:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10.png\" alt=\"\" class=\"wp-image-4307\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10-300x185.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10-768x473.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10-750x461.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10-400x246.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/03\/RigolDS10-250x154.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Thats all for this guide.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In next part, we shall develop the firmware for the slave to store the register data send by the master.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 6 focuses on implementing the master-side firmware required to perform write operations to specific registers on the Modbus RTU slave. This section covers constructing valid write request frames, managing data payload formatting, and ensuring proper handling of slave acknowledgments for reliable configuration updates. In this guide, we shall cover the following: 1. Write to [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-4302","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4302"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4302"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4302\/revisions"}],"predecessor-version":[{"id":4308,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4302\/revisions\/4308"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4302"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4302"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4302"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}