如何限制Modbus保持寄存器中特定寄存器的写入操作?
解决Modbus Slave部分保持寄存器只读的问题
要在保持寄存器区域(MB_PARAM_HOLDING)实现部分寄存器只读,同时支持主站一次性读取所有寄存器,核心思路是通过写回调函数拦截非法写入请求,具体步骤如下:
第一步:标记只读寄存器范围
先在代码里定义需要设为只读的寄存器地址范围,比如:// 示例:地址10到14的寄存器设为只读(共5个) #define READ_ONLY_REG_START 10 #define READ_ONLY_REG_COUNT 5如果是离散的单个寄存器,也可以用数组存储只读地址列表,后续在回调里逐个比对。
第二步:修改Modbus写回调函数
在ESP-IDF示例的mb_slave_cb回调中,针对MB_REG_WRITE和MB_REG_WRITE_MULTIPLE类型的请求,添加权限校验逻辑:esp_err_t mb_slave_cb(esp_mb_param_group_t *param_group, const esp_mb_param_info_t *param_info, esp_mb_cmd_type_t cmd_type, void *context) { esp_err_t err = ESP_OK; switch (cmd_type) { case MB_REG_WRITE: case MB_REG_WRITE_MULTIPLE: { uint16_t req_start = param_info->start_offset; uint16_t req_count = param_info->param_count; uint16_t ro_end = READ_ONLY_REG_START + READ_ONLY_REG_COUNT; // 检查请求的寄存器范围是否与只读范围重叠 if (!(req_start + req_count <= READ_ONLY_REG_START || req_start >= ro_end)) { // 存在只读寄存器,返回错误拦截写入 err = ESP_ERR_INVALID_ARG; break; } // 校验通过,执行原有写逻辑 // (此处保留示例中原有的寄存器值更新代码) break; } case MB_REG_READ: // 读操作不做限制,所有寄存器均可正常读取 // (保留示例中原有的读逻辑代码) break; default: err = ESP_ERR_NOT_SUPPORTED; break; } return err; }第三步:错误码映射说明
返回的ESP_ERR_INVALID_ARG会被ESP-IDF的Modbus栈自动转换为Modbus协议的MB_EX_ILLEGAL_DATA_VALUE异常码,主站收到后会知晓该写入请求无效,等同于这些寄存器是只读属性。
这种方案既保留了所有寄存器在同一保持寄存器区域(支持一次性批量读取),又精准拦截了对特定寄存器的写入操作,完全匹配你的需求。
内容的提问来源于stack exchange,提问作者JimitD
相关产品推荐
相关产品推荐

