{"id":4237,"date":"2026-02-26T08:55:46","date_gmt":"2026-02-26T08:55:46","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4237"},"modified":"2026-02-26T08:55:49","modified_gmt":"2026-02-26T08:55:49","slug":"modbus-sensor-emulation-part-4-slave-response-to-read-request","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4237","title":{"rendered":"Modbus Sensor Emulation Part 4: Slave Response to Read Request"},"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\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-1024x683.png\" alt=\"\" class=\"wp-image-4238\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/ChatGPT-Image-Jan-6-2026-at-09_38_15-AM.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Part 4 focuses on implementing the slave-side response to a Modbus RTU read request issued by the master. In this section, the STM32-based slave processes the received frame, validates the CRC and addressing, and returns a properly formatted response containing the requested register data in full compliance with the Modbus RTU specification.<\/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>Slave response to read request.<\/li>\n\n\n\n<li>Slave Firmware.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Slave Response to Read Request:<\/h2>\n\n\n\n<p>When the slave device receives the read request, it sends the response to the master. The response is shown below<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"775\" height=\"237\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3.avif\" alt=\"\" class=\"wp-image-4239\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3.avif 775w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3-300x92.avif 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3-768x235.avif 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3-750x229.avif 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3-400x122.avif 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/modbus6_3-250x76.avif 250w\" sizes=\"(max-width: 775px) 100vw, 775px\" \/><\/figure>\n\n\n\n<p>The pattern remains the same with slave address and function code occupying 1 byte each and CRC occupying 2 bytes.<\/p>\n\n\n\n<p>The only change is again in the Data field. It consists of the following:<\/p>\n\n\n\n<p>The actual\u00a0<strong>data<\/strong>\u00a0itself. The occupancy here depends on how many data bytes the slave is sending. <\/p>\n\n\n\n<p><strong>Byte count<\/strong>\u00a0(The number of data bytes slave is going to send) occupying 1 Byte<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Slave Firmware:<\/h2>\n\n\n\n<p>First, we shall create header and source file for crc calculation.<\/p>\n\n\n\n<p>Create header and and source file with name of modbus_crc.h and modbus_crc.c respectively as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"922\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-922x1024.jpg\" alt=\"\" class=\"wp-image-4240\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-922x1024.jpg 922w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-270x300.jpg 270w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-768x853.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-750x833.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-400x444.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58-250x278.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-29-58.jpg 1034w\" sizes=\"(max-width: 922px) 100vw, 922px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In modbus_crc.h file, within headerfile guard, 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;}\">uint16_t crc16(uint8_t *buffer, uint16_t buffer_length);<\/pre><\/div>\n\n\n\n<p>This function shall calculate the CRC value on the fly.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the entire header file 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;}\">#ifndef INC_MODBUS_CRC_H_\n#define INC_MODBUS_CRC_H_\n\nuint16_t crc16(uint8_t *buffer, uint16_t buffer_length);\n\n#endif \/* INC_MODBUS_CRC_H_ *\/<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in modbus_crc, include the following header files:<\/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;}\">#include &quot;stdint.h&quot;\n#include &quot;modbus_crc.h&quot;<\/pre><\/div>\n\n\n\n<p>Declare the following crc high table:<\/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;}\">static const uint8_t table_crc_hi[] = {\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,\n    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,\n    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,\n    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,\n    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,\n    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,\n    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,\n    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,\n    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,\n    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,\n    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,\n    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,\n    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,\n    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,\n    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40\n};<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>For the low:<\/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;}\">static const uint8_t table_crc_lo[] = {\n    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,\n    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,\n    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,\n    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,\n    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,\n    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,\n    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,\n    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,\n    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,\n    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,\n    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,\n    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,\n    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,\n    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,\n    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,\n    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,\n    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,\n    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,\n    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,\n    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,\n    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,\n    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,\n    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,\n    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,\n    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,\n    0x43, 0x83, 0x41, 0x81, 0x80, 0x40\n};<\/pre><\/div>\n\n\n\n<p>Next, the function shall calculate 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;}\">uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)\n{\n    uint8_t crc_hi = 0xFF; \/* high CRC byte initialized *\/\n    uint8_t crc_lo = 0xFF; \/* low CRC byte initialized *\/\n    unsigned int i; \/* will index into CRC lookup *\/\n\n    \/* pass through message buffer *\/\n    while (buffer_length--) {\n        i = crc_lo ^ *buffer++; \/* calculate the CRC  *\/\n        crc_lo = crc_hi ^ table_crc_hi[i];\n        crc_hi = table_crc_lo[i];\n    }\n\n    return (crc_hi &lt;&lt; 8 | crc_lo);\n}<\/pre><\/div>\n\n\n\n<p>This function computes a&nbsp;<strong>16-bit Modbus CRC (CRC-16\/IBM)<\/strong>&nbsp;over a byte buffer, which is mandatory for Modbus RTU frames to detect transmission errors.<\/p>\n\n\n\n<p>Here is what each part does:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Function Purpose<\/strong><\/h3>\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 crc16(uint8_t *buffer, uint16_t buffer_length)\n<\/pre><\/div>\n\n\n\n<p>Takes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>buffer<\/code>&nbsp;\u2192 pointer to the data bytes<\/li>\n\n\n\n<li><code>buffer_length<\/code>&nbsp;\u2192 number of bytes to process<\/li>\n<\/ul>\n\n\n\n<p>Returns:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The final 16-bit CRC value appended to Modbus frames.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>CRC Initialization<\/strong><\/h3>\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 crc_hi = 0xFF;\nuint8_t crc_lo = 0xFF;\n<\/pre><\/div>\n\n\n\n<p>Modbus RTU specifies that the CRC register starts at&nbsp;<strong>0xFFFF<\/strong>, so both high and low bytes are initialized to&nbsp;<code>0xFF<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Processing Each Byte<\/strong><\/h3>\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;}\">while (buffer_length--) {\n<\/pre><\/div>\n\n\n\n<p>Iterates through every byte in the message.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Index Calculation<\/strong><\/h3>\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;}\">i = crc_lo ^ *buffer++;\n<\/pre><\/div>\n\n\n\n<p>The incoming data byte is XORed with the current&nbsp;<strong>low CRC byte<\/strong>.<br>The result forms an index into the lookup tables.<\/p>\n\n\n\n<p>This avoids doing slow bit-by-bit polynomial calculations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Lookup Table Update<\/strong><\/h3>\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_lo = crc_hi ^ table_crc_hi[i];\ncrc_hi = table_crc_lo[i];\n<\/pre><\/div>\n\n\n\n<p>Two precomputed tables are used:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>table_crc_hi[]<\/code><\/li>\n\n\n\n<li><code>table_crc_lo[]<\/code><\/li>\n<\/ul>\n\n\n\n<p>They contain the pre-calculated CRC effects for all 256 possible byte values.<\/p>\n\n\n\n<p>The new CRC:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>crc_lo<\/code>&nbsp;becomes the old high byte XORed with a lookup value.<\/li>\n\n\n\n<li><code>crc_hi<\/code>&nbsp;becomes the corresponding lookup value.<\/li>\n<\/ul>\n\n\n\n<p>This updates the CRC register for the processed byte.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Final Return Value<\/strong><\/h3>\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;}\">return (crc_hi &lt;&lt; 8 | crc_lo);\n<\/pre><\/div>\n\n\n\n<p>Combines the two bytes into a 16-bit result:<\/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 = (high_byte &lt;&lt; 8) | low_byte\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Summary<\/strong><\/h3>\n\n\n\n<p>This is a&nbsp;<strong>table-driven Modbus CRC-16 implementation<\/strong>&nbsp;that:<\/p>\n\n\n\n<p>\u2714 Starts with&nbsp;<code>0xFFFF<\/code><br>\u2714 Processes each byte using XOR + lookup tables<br>\u2714 Produces the standard Modbus CRC<br>\u2714 Runs much faster than bitwise CRC algorithm.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, create new header and source file with name of modbus.h and modbus.h respectively as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"895\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-895x1024.jpg\" alt=\"\" class=\"wp-image-4241\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-895x1024.jpg 895w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-262x300.jpg 262w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-768x879.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-750x858.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-400x458.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27-250x286.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_11-33-27.jpg 1014w\" sizes=\"(max-width: 895px) 100vw, 895px\" \/><\/figure>\n\n\n\n<p>In the header file, we start by including the following header files:<\/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;}\">#include &quot;main.h&quot;\n\n#include &quot;stdint.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare a data structure to hold the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Slave 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 points.<\/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;}\">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\n}modbusTypedefStruct;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, declare a function that will extract the slave address, function code, register address and number of 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;}\">void modbus_receive(uint8_t *buffer, modbusTypedefStruct * modbus);<\/pre><\/div>\n\n\n\n<p>Also, declare the function that will send the data when master request to read 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_slave_transmit(uint8_t Addr, uint8_t func_code,uint8_t count, uint8_t *Data);<\/pre><\/div>\n\n\n\n<p>Hence, the header file 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;}\">#ifndef INC_MODBUS_H_\n#define INC_MODBUS_H_\n\n#include &quot;main.h&quot;\n\n#include &quot;stdint.h&quot;\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\n}modbusTypedefStruct;\n\n\n\n\n\nvoid modbus_receive(uint8_t *buffer, modbusTypedefStruct * modbus);\n\nvoid modbus_slave_transmit(uint8_t Addr, uint8_t func_code,uint8_t count, uint8_t *Data);\n\n\n#endif \/* INC_MODBUS_H_ *\/\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in modbus.c source, start by including the following 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;}\">#include &quot;modbus.h&quot;\n\n#include &quot;modbus_crc.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare the serial instant that shall be used, USART1 in this case:<\/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;}\">extern UART_HandleTypeDef huart1;<\/pre><\/div>\n\n\n\n<p>For the function that extract the slave address, function code, register address and number of data:<\/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_receive(uint8_t *buffer, modbusTypedefStruct * modbus)\n{\n\tuint16_t temp_crc;\n\ttemp_crc=buffer[6]|(buffer[7]&lt;&lt;8);\n\n\tuint16_t temp_crc_cal;\n\n\ttemp_crc_cal= crc16(&amp;buffer[0],6);\n\n\tif(temp_crc==temp_crc_cal)\n\t{\n\n\t\tmodbus-&gt;Slave_Address=buffer[0];\n\n\t\tmodbus-&gt;Function_Code=buffer[1];\n\n\t\tmodbus-&gt;Register_Address=(buffer[2]&lt;&lt;8)|(buffer[3]);\n\n\t\tmodbus-&gt;Number_of_Data=(buffer[4]&lt;&lt;8)|(buffer[5]);\n\n\t}\n\n\telse\n\t{\n\t\treturn;\n\t}\n\n}<\/pre><\/div>\n\n\n\n<p>This function receives and validates a&nbsp;<strong>Modbus RTU request frame<\/strong>, then extracts its core fields into a structured format.<\/p>\n\n\n\n<p>First, it reconstructs the received CRC from&nbsp;<code>buffer[6]<\/code>&nbsp;and&nbsp;<code>buffer[7]<\/code>&nbsp;(low byte first, as per Modbus RTU). It then recalculates the CRC over the first six bytes of the frame using&nbsp;<code>crc16()<\/code>&nbsp;and compares the result with the received CRC. If both match, the frame integrity is confirmed and the function extracts the&nbsp;<strong>Slave Address<\/strong>,&nbsp;<strong>Function Code<\/strong>,&nbsp;<strong>Register Address<\/strong>, and&nbsp;<strong>Number of Data (register count)<\/strong>&nbsp;from the buffer and stores them in the&nbsp;<code>modbus<\/code>&nbsp;structure. If the CRC check fails, the function exits immediately, discarding the corrupted frame.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, the function that transmits the requested 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;}\">void modbus_slave_transmit(uint8_t Addr, uint8_t func_code,uint8_t count, uint8_t *Data)\n{\n\tuint8_t tempArray[5+count];\n\n\ttempArray[0]=Addr;\n\ttempArray[1]=func_code;\n\ttempArray[2]=count;\n\n\tfor(int i=0;i&lt;count;i++)\n\t{\n\t\ttempArray[3+i]=Data[i];\n\t}\n\n\tuint16_t crc=crc16(tempArray,count+3);\n\n\ttempArray[5+count-2]=(crc&gt;&gt;8)&amp;0xFF;\n\ttempArray[5+count-1]=(crc)&amp;0xFF;\n\n\tHAL_UART_Transmit(&amp;huart1, tempArray, 5+count, 500);\n\n}<\/pre><\/div>\n\n\n\n<p>This function constructs and transmits a&nbsp;<strong>Modbus RTU slave response frame<\/strong>&nbsp;over UART.<\/p>\n\n\n\n<p>It first creates a temporary array sized to hold the full response: slave address (1 byte), function code (1 byte), byte count (1 byte), data payload (<code>count<\/code>&nbsp;bytes), and CRC (2 bytes). The first three bytes are assigned as&nbsp;<code>Addr<\/code>,&nbsp;<code>func_code<\/code>, and&nbsp;<code>count<\/code>, then the loop copies the response data into the frame starting at index 3.<\/p>\n\n\n\n<p>Next, a CRC-16 is calculated over the address, function code, byte count, and data (<code>count + 3<\/code>&nbsp;bytes). The resulting CRC is appended to the end of the frame (two bytes), and finally&nbsp;<code>HAL_UART_Transmit()<\/code>&nbsp;sends the complete&nbsp;<code>5 + count<\/code>&nbsp;byte frame to the master.<\/p>\n\n\n\n<p>Hence, the source file 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;}\">#include &quot;modbus.h&quot;\n\n#include &quot;modbus_crc.h&quot;\n\nextern UART_HandleTypeDef huart1;\n\nvoid modbus_receive(uint8_t *buffer, modbusTypedefStruct * modbus)\n{\n\tuint16_t temp_crc;\n\ttemp_crc=buffer[6]|(buffer[7]&lt;&lt;8);\n\n\tuint16_t temp_crc_cal;\n\n\ttemp_crc_cal= crc16(&amp;buffer[0],6);\n\n\tif(temp_crc==temp_crc_cal)\n\t{\n\n\t\tmodbus-&gt;Slave_Address=buffer[0];\n\n\t\tmodbus-&gt;Function_Code=buffer[1];\n\n\t\tmodbus-&gt;Register_Address=(buffer[2]&lt;&lt;8)|(buffer[3]);\n\n\t\tmodbus-&gt;Number_of_Data=(buffer[4]&lt;&lt;8)|(buffer[5]);\n\n\t}\n\n\telse\n\t{\n\t\treturn;\n\t}\n\n}\n\nvoid modbus_slave_transmit(uint8_t Addr, uint8_t func_code,uint8_t count, uint8_t *Data)\n{\n\tuint8_t tempArray[5+count];\n\n\ttempArray[0]=Addr;\n\ttempArray[1]=func_code;\n\ttempArray[2]=count;\n\n\tfor(int i=0;i&lt;count;i++)\n\t{\n\t\ttempArray[3+i]=Data[i];\n\t}\n\n\tuint16_t crc=crc16(tempArray,count+3);\n\n\ttempArray[5+count-2]=(crc&gt;&gt;8)&amp;0xFF;\n\ttempArray[5+count-1]=(crc)&amp;0xFF;\n\n\tHAL_UART_Transmit(&amp;huart1, tempArray, 5+count, 500);\n\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in main.c:<\/p>\n\n\n\n<p>Include the modbus and stlib.h header files 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;}\">#include &quot;modbus.h&quot;\n#include &quot;stdlib.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare the data structure that holds the read request information:<\/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;}\">modbusTypedefStruct modbusFrame;<\/pre><\/div>\n\n\n\n<p>Declare a volatile flag to let us know when the data has been received 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;}\">volatile uint8_t newData;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Modify <strong>HAL_UARTEx_RxEventCallback<\/strong> 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\tmodbus_receive(rs485_buffer,&amp;modbusFrame);\n\t\tHAL_UARTEx_ReceiveToIdle_IT(&amp;huart1, rs485_buffer, bufferSize);\n\t\tnewData=1;\n\n\t}\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in user code begin 3 in while 1 loop:<\/p>\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;}\">if(newData==1)\n{\n  if(modbusFrame.Slave_Address==0x11)\n  {\n    if(modbusFrame.Function_Code==0x03) \/\/Read Request\n    {\n      uint8_t data[2];\n      data[0]=random()%255;\n      data[1]=random()%255;\n      modbus_slave_transmit(modbusFrame.Slave_Address,modbusFrame.Function_Code,2,data);\n      newData=0;\n    }\n  }\n\n}<\/pre><\/div>\n\n\n\n<p>Thats all for the 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 launching a debug session when the master is connected to your PC, you should get the following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"459\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-1024x459.jpg\" alt=\"\" class=\"wp-image-4242\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-1024x459.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-300x134.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-768x344.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-1150x515.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-750x336.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-400x179.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01-250x112.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/2026-02-26_10-59-01.jpg 1156w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\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\/02\/RigolDS5.png\" alt=\"\" class=\"wp-image-4243\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/RigolDS5.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/RigolDS5-300x185.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/RigolDS5-768x473.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/RigolDS5-750x461.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/RigolDS5-400x246.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/02\/RigolDS5-250x154.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>We have successfully send a response to the master.<\/p>\n\n\n\n<p>Next, we shall implement the write request.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Stay tuned.<\/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 4 focuses on implementing the slave-side response to a Modbus RTU read request issued by the master. In this section, the STM32-based slave processes the received frame, validates the CRC and addressing, and returns a properly formatted response containing the requested register data in full compliance with the Modbus RTU specification. In this guide, [&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-4237","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\/4237"}],"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=4237"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4237\/revisions"}],"predecessor-version":[{"id":4244,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4237\/revisions\/4244"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4237"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4237"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}