ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

libmodbus 从站号读取 API 详解:modbus_get_slave 的用法、底层实现与实战场景

libmodbus 从站号读取 API 详解:modbus_get_slave 的用法、底层实现与实战场景 通信嵌入式物联网【免费下载链接】libmodbusA Modbus library for Linux, Mac OS, FreeBSD and Windows项目地址https://gitcode.com/gh_mirrors/li/libmodbus点击查看免费下载modbus_get_slave()是 libmodbus 提供的用于读取上下文modbus_t中当前从站号slave number的轻量级 API。在需要动态切换通信目标如 RTU 总线上的多从站轮询、在服务器模式下校验报文来源或调试“请求发给了哪个设备”等场景中它是与modbus_set_slave()配对的常用辅助函数。读完本文你将掌握该函数的签名、返回值与错误语义理解它在 RTU/TCP 两个后端中的真实实现并能在自己的工程中正确组合使用读写从站号的 API。函数签名与声明位置int modbus_get_slave(modbus_t *ctx);该函数在公共头文件 src/modbus.h 中与modbus_set_slave()一同声明MODBUS_API int modbus_set_slave(modbus_t *ctx, int slave); MODBUS_API int modbus_get_slave(modbus_t *ctx);其中modbus_t是 libmodbus 的不透明上下文类型typedef struct _modbus modbus_t;见 src/modbus.h由modbus_new_rtu()、modbus_new_tcp()、modbus_new_tcp_pi()等构造函数创建随后作为几乎全部 libmodbus API 的第一个参数传递。函数语义从上下文中取出当前从站号modbus_get_slave()的功能非常明确读取 libmodbus 上下文中保存的从站号并返回。这里的“从站号”是上下文内部字段ctx-slave的当前值——它既可以是RTU 模式下客户端master要通信的远端设备 ID也可以是服务器slave模式下的自身服务 ID详见下文“与 modbus_set_slave 的配对使用”。需要说明的是该函数只做“读取”动作不发起任何总线通信也没有任何网络 I/O 副作用因此可以安全地在任意时刻调用用于确认上下文当前指向哪个从站。返回值与错误处理成功返回当前从站号非负整数。失败返回-1并设置errno。官方文档 docs/modbus_get_slave.md 中列出的错误仅有一种errno触发条件EINVALlibmodbus 上下文未定义即传入的ctx为NULL这一语义与modbus_set_slave()的错误处理形成互补modbus_set_slave()在从站号超出协议范围时同样返回-1并设置EINVAL而modbus_get_slave()由于只读取内部字段唯一的失败入口就是空指针上下文。底层实现剖析modbus_get_slave()的实现非常直接位于 src/modbus.cint modbus_get_slave(modbus_t *ctx) { if (ctx NULL) { errno EINVAL; return -1; } return ctx-slave; }从源码结构可以看到三个关键事实空指针保护在前ctx NULL时直接置errno EINVAL并返回-1与文档中的错误说明完全一致。不经过后端函数指针与modbus_set_slave()不同后者通过ctx-backend-set_slave(ctx, slave)转发给具体后端见 src/modbus.cmodbus_get_slave()直接访问共享结构体字段ctx-slave。这意味着 RTU、TCP、TCP-PI 三种后端读取到的是同一个统一的从站号。字段在上下文初始化时被置为-1ctx-slave在上下文初始化函数中设置为-1见 src/modbus.c 附近因此“从未设置过从站号”时调用本函数会得到-1。在 RTU 客户端的请求构建函数_modbus_rtu_build_request_basis()中源码使用assert(ctx-slave ! -1)明确要求必须先设置从站号见 src/modbus-rtu.c——也就是说RTU 模式下直接发请求前不设置从站号是典型的编程错误而用modbus_get_slave()做前置校验是一个稳妥的防御手段。与 modbus_set_slave 的配对使用三种典型场景从站号是读写一体的状态理解modbus_get_slave()必须结合它的“写”搭档modbus_set_slave()。官方文档 docs/modbus_set_slave.md 与源码共同确认了以下语义RTU 客户端多从站轮询在 RTU 模式下从站号直接决定了串行总线上请求帧的第一个地址字节。作为客户端modbus_set_slave()设置的是“你想要通信的远端设备 ID”因此在发起任何 Modbus 请求之前必须先设置若要依次与多个从站通信只需在每次请求前切换从站号。此时modbus_get_slave()可用于确认当前请求将要发往的设备int current modbus_get_slave(ctx); printf(当前请求将发送给从站 %d\n, current);RTU 服务器对外公布自身 ID作为服务器slavemodbus_set_slave()设置的则是本服务的 ID网络中的客户端只有向该 ID或广播地址发送请求才会被接受。modbus_get_slave()在此场景下可用于在日志或调试输出中打印“本服务器应答的从站号”。TCP 模式单元标识符Unit Identifier的特殊性在 TCP 模式下从站号仅当报文需要穿透网关到达串行网络上的设备时才被实际使用。部分不合规的设备或软件如 modpoll会把该值当作单元标识符使用——虽然按 Modbus 规范这是不正确的用法但若不设置该值这些有缺陷的远端设备会直接丢弃请求。TCP 后端还支持特殊值MODBUS_TCP_SLAVE0xFF来恢复默认值该特殊值的处理逻辑可见于 src/modbus-tcp.cstatic int _modbus_set_slave(modbus_t *ctx, int slave) { int max_slave (ctx-quirks MODBUS_QUIRK_MAX_SLAVE) ? 255 : 247; /* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */ if (slave 0 slave max_slave) { ctx-slave slave; } else if (slave MODBUS_TCP_SLAVE) { /* The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to * restore the default value. */ ctx-slave slave; } else { errno EINVAL; return -1; } return 0; }广播地址从站号 0广播地址定义为MODBUS_BROADCAST_ADDRESS值为 0见 src/modbus.h。当需要让网络上所有 Modbus 设备都收到请求时把从站号设为 0 即可modbus_get_slave()返回 0 也就意味着当前处于广播模式。从站号取值范围与 quirks 扩展RTU 与 TCP 后端的set_slave实现遵循相同的取值范围规则见 src/modbus-rtu.c 与 src/modbus-tcp.c默认合法范围0 slave 247启用MODBUS_QUIRK_MAX_SLAVE后上限放宽为255针对不遵守规范、使用 248~255 地址的设备。单位测试 tests/unit-test-client.c 对这一点做了直接验证在默认情况下将从站号设为 248 会被拒绝rc -1而启用MODBUS_QUIRK_MAX_SLAVE后再设 248 则被接受。这也提示我们modbus_get_slave()返回的值可能落在 0~255 之间处理日志与协议帧时应按 uint8_t 的语义看待而不应假设它永远 ≤ 247。完整示例读取并验证从站号结合modbus_set_slave()官方示例docs/modbus_set_slave.md与modbus_get_slave()的语义下面给出一个完整、可编译的 RTU 客户端片段展示“设置 → 校验 → 连接”的推荐顺序#include errno.h #include stdio.h #include modbus.h #define YOUR_DEVICE_ID 1 int main(void) { modbus_t *ctx; int rc; int slave; ctx modbus_new_rtu(/dev/ttyUSB0, 115200, N, 8, 1); if (ctx NULL) { fprintf(stderr, Unable to create the libmodbus context\n); return -1; } /* RTU 客户端模式下必须在发起任何请求前设置远端从站 ID */ rc modbus_set_slave(ctx, YOUR_DEVICE_ID); if (rc -1) { fprintf(stderr, Invalid slave ID\n); modbus_free(ctx); return -1; } /* 读取并校验上下文中的从站号确认请求目标 */ slave modbus_get_slave(ctx); if (slave -1) { fprintf(stderr, Unable to get slave: %s\n, modbus_strerror(errno)); modbus_free(ctx); return -1; } printf(当前上下文的从站号为 %d\n, slave); if (modbus_connect(ctx) -1) { fprintf(stderr, Connection failed: %s\n, modbus_strerror(errno)); modbus_free(ctx); return -1; } /* ... 此处可发起 modbus_read_registers() 等请求 ... */ modbus_close(ctx); modbus_free(ctx); return 0; }代码要点modbus_set_slave()失败时返回-1此时必须释放上下文modbus_free()并退出modbus_get_slave()返回-1的唯一原因是ctx NULL正常流程中几乎不会触发但作为防御性检查成本极低错误描述统一使用modbus_strerror(errno)输出其行为见 docs/modbus_strerror.md。常见误用与注意事项RTU 模式下忘记先设置从站号源码_modbus_rtu_build_request_basis()中的assert(ctx-slave ! -1)会直接断言失败见 src/modbus-rtu.c。先用modbus_get_slave()校验返回值是否为-1可避免这类崩溃。把modbus_get_slave()当作协议校验该函数只是读取本地字段不会验证从站号是否仍在合法范围——它只是把上一次成功modbus_set_slave()写入的值原样返回。范围校验发生在set_slave阶段。广播与 TCP 默认值的区分返回 0 表示广播模式TCP 模式下返回0xFFMODBUS_TCP_SLAVE表示使用默认单元标识符两者语义不同日志记录时应注意区分。相关文档modbus_set_slave 详解从站号的写入 API与本文函数配对使用modbus_new_rtu / modbus_new_tcp创建上下文modbus_connect建立连接modbus_strerror错误码到可读文本的转换modbus_enable_quirks / modbus_disable_quirks控制MODBUS_QUIRK_MAX_SLAVE等兼容性开关赞分享通信嵌入式物联网【免费下载链接】libmodbusA Modbus library for Linux, Mac OS, FreeBSD and Windows项目地址https://gitcode.com/gh_mirrors/li/libmodbus点击查看免费下载相关推荐x64dbg 表达式求值 API 深度解析DbgValFromString 的用法、底层实现与实战场景x64dbg 表达式求值 API 深度解析DbgValFromString 的用法、底层实现与实战场景 导读 DbgValFromString 是 x64db逆向工程调试器开发工具应用安全使用 MoviePy ffmpeg_extract_audio 从视频中提取音频API 详解与底层实现使用 MoviePy ffmpeg_extract_audio 从视频中提取音频API 详解与底层实现 ffmpeg_extract_audio 是 Movi音视频视频处理音频处理StarRocks fmod 函数详解浮点取模的语法、用法与底层实现StarRocks fmod 函数详解浮点取模的语法、用法与底层实现 fmod 是 StarRocks 提供的数学函数之一用于计算两个数值相除后的浮点余数数据库OLAP数据仓库大数据湖仓一体数据分析上一篇Swift 归并排序Merge Sort实战指南从递归分治到迭代自底向上实现下一篇PyTorch Lightning 版本历史指南从 1.0 到 2.x 的演进脉络与升级路径创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表