{"id":4333,"date":"2026-04-04T12:41:40","date_gmt":"2026-04-04T12:41:40","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4333"},"modified":"2026-04-04T12:41:41","modified_gmt":"2026-04-04T12:41:41","slug":"modbus-sensor-emulation-part-7-handling-and-storing-register-write-requests-in-the-slave","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4333","title":{"rendered":"Modbus Sensor Emulation Part 7: Handling and Storing Register Write Requests in the Slave"},"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\/04\/image-1024x683.png\" alt=\"\" class=\"wp-image-4334\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Part 7 focuses on the slave firmware responsible for receiving and processing Modbus write requests. In this section, the slave parses the incoming frame and stores the transmitted register values into the internal register map so that they can be used by the application.<\/p>\n\n\n\n<p><\/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>Firmware Development.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Firmware Development:<\/h2>\n\n\n\n<p>Open the slave project. <\/p>\n\n\n\n<p>In main.c file, we start by declaring the following defines:<\/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>These are for single and multiple write to register, this is the same which has been used in part 6.<\/p>\n\n\n\n<p>Also, define how many registers does the slave should have 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 REGMAP_SIZE 2<\/pre><\/div>\n\n\n\n<p>This guide shall use 2 register.<\/p>\n\n\n\n<p>Next, declare the register array 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;}\">uint16_t regMap[REGMAP_SIZE]={0};<\/pre><\/div>\n\n\n\n<p>Next, declare variables to hold the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Starting address<\/li>\n\n\n\n<li>Number of data.<\/li>\n\n\n\n<li>Counts.<\/li>\n<\/ul>\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;}\">uint16_t startAdd=0;\nuint16_t NumberOfData=0;\nuint16_t ByteCount=0;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In <strong>HAL_UARTEx_RxEventCallback<\/strong> function:<\/p>\n\n\n\n<p>After checking if the packet is read request, we shall handle if it is write request.<\/p>\n\n\n\n<p>First if the function code is Write single or Write multiple 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;}\">if(rs485_buffer[1]==SingleWrite||rs485_buffer[1]==MultiWrite)<\/pre><\/div>\n\n\n\n<p>Within the if condition, first get starting address 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;}\">startAdd     = rs485_buffer[2] &lt;&lt; 8 | rs485_buffer[3];<\/pre><\/div>\n\n\n\n<p>Get number of data ( number of registers to write to):<\/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;}\">NumberOfData = rs485_buffer[4] &lt;&lt; 8 | rs485_buffer[5];<\/pre><\/div>\n\n\n\n<p>Number of total bytes 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;}\">ByteCount    = rs485_buffer[6];<\/pre><\/div>\n\n\n\n<p>Most important part is to check the boundaries to ensure no corruption to data will happen 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;}\">if(startAdd + NumberOfData - 1 &lt;= REGMAP_SIZE) \/\/Check the memory boundaries.<\/pre><\/div>\n\n\n\n<p>If it is within boundaries, fill the registers with the configuration data 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;}\">for (int i = 0; i &lt; NumberOfData; i++)\n{\n  regMap[startAdd - 1 + i] =\n    (rs485_buffer[7 + i*2] &lt;&lt; 8) |\n    rs485_buffer[8 + i*2];\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the updated 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 HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)\n\n{\tif(huart-&gt;Instance==USART1)\n\t{\n\t\tif(rs485_buffer[0]==address)\n\t\t{\n\t\t\tif(rs485_buffer[1]==Read)\n\t\t\t{\n\t\t\t\tmodbus_receive(rs485_buffer,&amp;modbusFrame);\n\n\t\t\t\tnewData=1;\n\t\t\t}\n\t\t\tif(rs485_buffer[1]==SingleWrite||rs485_buffer[1]==MultiWrite)\n\t\t\t{\n\t\t\t\tstartAdd     = rs485_buffer[2] &lt;&lt; 8 | rs485_buffer[3];\n\t\t\t\tNumberOfData = rs485_buffer[4] &lt;&lt; 8 | rs485_buffer[5];\n\t\t\t\tByteCount    = rs485_buffer[6];\n\n\n\t\t\t\tif(startAdd + NumberOfData - 1 &lt;= REGMAP_SIZE) \/\/Check the memory boundaries.\n\t\t\t\t{\n\n\t\t\t\t\tfor (int i = 0; i &lt; NumberOfData; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tregMap[startAdd - 1 + i] =\n\t\t\t\t\t\t\t(rs485_buffer[7 + i*2] &lt;&lt; 8) |\n\t\t\t\t\t\t\t rs485_buffer[8 + i*2];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n\n\n\t\t}\n\n\n\n\t}\n\n\tHAL_UARTEx_ReceiveToIdle_IT(&amp;huart1, rs485_buffer, bufferSize);\n}<\/pre><\/div>\n\n\n\n<p>Thats all for the slave configuration.<\/p>\n\n\n\n<p>Save the project, build it and run it in debugging mode on your board.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"38\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-1024x38.jpg\" alt=\"\" class=\"wp-image-3296\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-1024x38.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-300x11.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-768x29.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-1536x57.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-1150x43.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-750x28.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-400x15.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27-250x9.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/03\/2025-03-15_10-56-27.jpg 1878w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Results:<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"634\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-634x1024.gif\" alt=\"\" class=\"wp-image-4335\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-634x1024.gif 634w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-186x300.gif 186w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-768x1241.gif 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-950x1536.gif 950w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-750x1212.gif 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-400x646.gif 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Screen-Recording-2026-04-04-at-10.58.29-250x404.gif 250w\" sizes=\"(max-width: 634px) 100vw, 634px\" \/><\/figure>\n\n\n\n<p>Notice that when 1 register is being requested to write to, only one is being updated, for 2, both shall be updated. Once the master requested to write more than 2, 4 in this case, no update shall occur. This will ensure stable operation of the sensor.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Now, you can improve the code and feel free to comment with your feedback.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 7 focuses on the slave firmware responsible for receiving and processing Modbus write requests. In this section, the slave parses the incoming frame and stores the transmitted register values into the internal register map so that they can be used by the application. In this guide, we shall cover the following: 1. Firmware Development: [&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-4333","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\/4333"}],"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=4333"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4333\/revisions"}],"predecessor-version":[{"id":4336,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4333\/revisions\/4336"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4333"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4333"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}