SylixOS Modbus 开发
本节将通过 Modbus TCP 对从站 0 - 16 位线圈状态(Coil Status)进行读写,0 - 16 位输入寄存器 (Input Status) 进行读取,实现快速体验中的 Modbus 控制效果。
环境准备
设备列表
序号 | 设备名称 | 数量 | 备注 |
---|---|---|---|
1 | IGC1503 控制器 | 1 | 必选 |
2 | Modbus TCP 远程 IO 模块 | 1 | 可选 |
3 | 交换机 | 1 | 可选 |
软件列表
序号 | 软件名称 | 数量 | 备注 |
---|---|---|---|
1 | RealEvo-IDE | 1 | 必选 |
2 | Modbus 从站仿真软件 | 1 | 必选 |
3 | PuTTY 终端工具 | 1 | 必选 |
下载列表
与 Modbus 从站仿真软件数据交互
使用 Modbus TCP 协议实现“功能 1 为线圈状态”和“功能 2 为输入状态”的数据交互,具体操作如下。
说明:
本小节对于 Modbus 从站仿真软件的配置效果与“极速体验”章节提供的 Modbus Slave 工作空间完全一致,用户可直接按照“快速体验 > SylixOS 数据采集 > 部署应用”中 步骤 4 操作。
前提条件
根据“快速体验 > SylixOS 数据采集 > 环境准备”中 步骤 1 操作,将硬件设备进行连接。
根据“快速体验 > SylixOS 数据采集 > 部署应用”中 步骤 1 操作,设置本机 IP 与 IGC1503 处于同一网段。
步骤 1:连接从站仿真软件
单击 Connection > Connect…,会弹出设置窗口 Connection Setup。
在 Connection Setup 窗口中选择 Modbus TCP/IP,勾选 Any Address 和 Ignore Unit ID,使得 Modbus Client 可以响应任意 Modbus Server 的请求。
步骤 2:配置线圈通道
单击 Mbslave1 窗口,选择菜单栏 Setup > Slave Definition。
在 Slave Definition 窗口中配置 Slave ID 为 1,Function 为 01 Coil Status (0x),寄存器值 16,单击 OK 完成配置。
步骤 3:配置状态寄存器通道
单击菜单栏 File > New 新建 Mbslave2 通道,
单击 Mbslave2 窗口,选择菜单栏 Setup > Slave Definition。
在 Slave Definition 窗口中配置 Slave ID 为 1,Function 为 02 Input Status (1x),寄存器值 16,单击 OK 完成配置。
双击第二列任意单元格,勾选 Auto change,单击 OK 即可实现对应状态寄存器通道自动跳变的功能。
步骤 4:创建 Base 工程
打开 RealEvo-IDE,单击 Browse... 选择一个新文件夹作为工作空间,单击 Launch 进入开发界面。
在主菜单中选择 File > New > SylixOS Base 新建 Base。
在 Project name 中自定义 Base 工程名,单击 Next 进入下一步。
在 SylixOS version 下拉菜单中选择 default,并在列表中选择 SylixOS Standard Base 后,单击 Next。
如图所示选择 Toolchain、Debug Level、CPU Type、FPU Type,并单击 Next。
说明:
IGC1500,IGC1503 的 CPU Type 均为 cortex-a7。
在 SylixOS 组件配置界面,如下图进行默认选择,并单击 Finish 完成 Base 新建工作。
编译 Base 工程。右键 base_a7 工程 > Build Project。
步骤 5:创建 App 工程
新建 App 工程。在主菜单中选择 File > New > SylixOS App。
输入工程名,单击 Next。
单击 Workspace 选择上步骤创建的 SylixOS Base 工程 base_a7,并单击 Finish 完成创建。
在工程栏中 app_modbus > src,打开
app_modbus.c
文件编辑代码,示例代码如下。#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <assert.h> #include "modbus.h" /********************************************************************************************************* Config slave ip & port *********************************************************************************************************/ #define MODBUS_TCP_SLAVE_IP "192.168.1.8" #define MODBUS_TCP_SLAVE_PORT (502) /********************************************************************************************************* ** 函数名称: main ** 功能描述: 主函数 ** 输 入 : argc 参数个数 ** argv 参数指针数组 ** 输 出 : 0 or -1 *********************************************************************************************************/ int main (int argc, char **argv) { modbus_t *mbtCtx; unsigned int uiPos = 0; uint8_t ucInput[16] = {0}; uint8_t ucOutput[16] = {0}; char cBuf[512] = {0}; char cTempBuf[64] = {0}; int i = 0; int iOutputSize = sizeof(ucOutput) / sizeof(ucOutput[0]); int iInputSize = sizeof(ucInput) / sizeof(ucInput[0]); int iTempBufSize = sizeof(cTempBuf); /* * New modbus master. * argv[1] modbus device ip, argv[2] modbus device port */ if (argc > 2) { mbtCtx = modbus_new_tcp(argv[1], atoi(argv[2])); } else { mbtCtx = modbus_new_tcp(MODBUS_TCP_SLAVE_IP, MODBUS_TCP_SLAVE_PORT); } if (NULL == mbtCtx) { fprintf(stderr, "Create modbus failed!\n"); return (-1); } /* * Connect slave. */ if (modbus_connect(mbtCtx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(mbtCtx); mbtCtx = NULL; return (-1); } while (1) { sleep(1); for (i = 0; i < iOutputSize; i++) { ucOutput[i] = (i == uiPos) ? 1 : 0; } uiPos++; if (uiPos >= iOutputSize) { uiPos = 0; } /* * Write Coil Status. */ modbus_write_bits(mbtCtx, 0, iOutputSize, ucOutput); /* * Read Coil Status. */ memset(ucOutput, 0, iOutputSize); modbus_read_bits(mbtCtx, 0, iOutputSize, ucOutput); /* * Read Input Registers. */ memset(ucInput, 0, iInputSize); modbus_read_input_bits(mbtCtx, 0, iInputSize, ucInput); /* * Print results. */ sprintf(cBuf, "input(DI0~DI%d): ", iInputSize); for (i = 0; i < iInputSize; i++) { memset(cTempBuf, 0, iTempBufSize); sprintf(cTempBuf, " %d", ucInput[i]); strcat(cBuf, cTempBuf); } strcat(cBuf, "\r\n"); memset(cTempBuf, 0, iTempBufSize); sprintf(cTempBuf, "output(DO0~DO%d): ", iOutputSize); strcat(cBuf, cTempBuf); for (i = 0; i < iOutputSize; i++) { memset(cTempBuf, 0, iTempBufSize); sprintf(cTempBuf, " %d", ucOutput[i]); strcat(cBuf, cTempBuf); } printf("%s\r\n", cBuf); } /* * Close the connection. */ if (mbtCtx != NULL) { modbus_close(mbtCtx); modbus_free(mbtCtx); mbtCtx = NULL; } return (0); }
在工程中加入 Modbus 相关的依赖头文件和库文件,整体工程结构如下所示。
说明:
设置依赖文件。右键 app_modbus 工程 > Properties 打开设置界面。
在窗口进入 SylixOS Project > Compiler Setting > Include Path > Current Project 界面,设置依赖头文件。
在窗口中选择头文件所存放的 inc 文件夹,单击 OK 完成头文件路径的选择。
在窗口进入 SylixOS Project > Linker Setting > Linker Setting > Current Project 界面,设置依赖库文件并添加库路径。
在窗口中选择依赖的库文件 libmodbus.so,单击 OK 完成库文件的选择。
在弹框中选择是,工程会自动添加依赖库文件的路径。
保存所有工程配置。单击 Apply 使配置生效。最后,单击 OK 完成配置。
编译 App 工程。右键 app_modbus 工程 > Build Project。
步骤 6:部署 App
设置部署的设备及应用。右键 app_modbus 工程 > Properties 打开设置界面。
在窗口进入 SylixOS Project > Device Setting > New Device 界面,添加部署的目标设备。
添加 IGC1503 的 IP:192.168.1.253,单击 Finish 完成设置。
在窗口进入 SylixOS Project > Device Setting > Add 界面,添加库文件的部署。
单击 Workspace 选择 app_modbus > lib > libmodbus.so 库文件,并输入 Remote path,单击 OK 完成库文件的部署信息。
配置完成后,信息如下图所示。单击 Apply 使配置生效,再单击 OK 完成配置。
右键 app_modbus 工程,选择 SylixOS > Upload 将工程上传部署。
步骤 7:登录 IGC 控制器
根据“快速体验 > SylixOS 数据采集 > 部署应用”中 步骤 3 操作,登录 IGC 控制器。
步骤 8:查看运行效果
input 显示为 Mbslave2 窗口的输入状态,即 Mbslave2 的通道值改变,input 的打印信息也会打印相同的值,实现 Client 主动读取 Server 输入通道值功能。
Mbslave1 窗口显示为 output 的输出状态,即 output 打印出的值,将会在 Mbslave1 窗口中同步显示。output 值的变动实现 Client 控制 Server 流水灯功能,“1”为亮灯,“0”为灭灯,模拟了流水灯亮灭的操作。
IGC1503 运行获取寄存器状态打印如下所示。
[root@sylixos:/apps/app_modbus]# ./app_modbus input(DI0~DI16): 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 output(DO0~DO16): 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 input(DI0~DI16): 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 output(DO0~DO16): 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 input(DI0~DI16): 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 output(DO0~DO16): 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
Modbus 从站仿真软件状态如下所示。
与 Modbus TCP 远程 IO 数据交互
代码程序可从 步骤 4 开始参考操作。
运行效果与“快速体验 > SylixOS 数据采集 > 运行效果”中 Modbus 远程 IO 一致。