IGC 控制器通信开发
本节介绍了如何通过不同的开发方式,实现 IGC 控制器与 HMI 的通信。
本例程是在“IGC 控制器双机通信”中 VSOA Client 端开发 的工程基础上增加 Modbus 功能,与 HMI 设备采用 Modbus TCP 协议进行通讯,实现 HMI 可视化展示的效果。
说明:
由于本例程依赖的是“IGC 控制器双机通信 > VSOA Client 端开发”章节,所以本案例将依托上面的章节内容,运行在 IGC1500 控制器上。
前提条件
根据之前的学习,已经能熟练掌握 SylixOS 开发环境 RealEvo-IDE 的基本使用方法。如:新建工程,添加依赖文件及依赖路径,配置目标设备和工程编译运行等操作。
操作前需保证 IGC 控制器已经部署 VSOA 环境。若还未部署,可按照“IGC 控制器双机通信 > 环境准备”中 操作步骤 进行部署。
HMI 设备寄存器定义
寄存器 | 说明 |
---|---|
40001 | 电机启动/停止状态寄存器 |
40002 | 电机速度寄存器(单位:r/min) |
操作步骤
步骤 1:创建 App 工程
参考“IGC 控制器双机通信 > VSOA Client 端开发”中 步骤 1,创建 app_vsoa_client_modbus 工程,并添加 VSOA 和 yyjson相关依赖文件和头文件路径。
删除 app_vsoa_client_modbus.cpp 文件,并且把“IGC 控制器双机通信 > VSOA Client 端开发”中 app_vsoa_client 工程案例“src\”目录下的 app_vsoa_client.cpp、packet_json.h、packet_json.cpp 全部复制到 app_vsoa_client_modbus 工程中的“src\”目录,如图所示。
下载 app_vsoa_client_modbus 示例工程,工程中包含 libmodbus 文件夹,将 libmodbus 文件夹复制到用户的 app_vsoa_client_modbus 工程中,如图所示。
为工程添加 libmodus 库依赖。
为工程添加 libmodbus 库头文件路径。
步骤 2:创建 Modbus 线程
在 app_vsoa_client_modbus.cpp 文件中,添加 libmodbus 库头文件。
#include "modbus.h"
编写 Modbus 处理线程。创建 Modbus tcp master,连接 Modbus tcp slave HMI 设备,而后每隔一段时间,将电机速度写入 HMI 设备的 40002 寄存器中,并对 40002 寄存器的值进行监听。当数据变化时,程序通过 VSOA RPC 向 VSOA Server 端发送电机的“启动/停止”命令请求。
static void *modbus_pthread (void *arg) { modbus_t *ctx; state_data_t l_state_data; uint16_t temp; bool flag; /* * init modbus tcp master, and connect slave */ ctx = modbus_new_tcp("192.168.1.133", 502); do { sleep(1); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); } else { break; } } while (1); while (1) { usleep(100 * 1000); memcpy(&l_state_data, &state_data, sizeof(state_data)); /* * write motor speed to HMI * calc: r/min, motor encode 23 bit = 8,388,608 */ modbus_write_register(ctx, 1, ((int64_t)l_state_data.motor_speed * 60) / 8388608); /* * read start btn is not press * if press, then call vsoa rpc to set vsoa server */ modbus_read_registers(ctx, 0, 1, &temp); flag = (0 == temp) ? 0 : 1; if (l_state_data.run_flag != flag) { bool ret; vsoa_url_t url; vsoa_header_t *vsoa_hdr; vsoa_payload_t reply, send; vsoa_client_sync_call_t *sync; sync = vsoa_client_sync_create(true); /* * when the situation CODESYS as the VSOA Server, * the following "url.url" should be replaced by (char *)"/plc/motor0/control" */ url.url = (char *)"/control"; url.url_len = strlen(url.url); send.data = NULL; send.data_len = 0; send.param = ethercat_motor_control_json_stringify(flag); send.param_len = strlen(send.param); ret = vsoa_client_sync_call(client, VSOA_CLIENT_RPC_METHOD_SET, &url, &send, sync, &vsoa_hdr, NULL); if (ret) { if (vsoa_hdr) { vsoa_parser_get_payload(vsoa_hdr, &reply); char err_msg[512] = {0}; bool state; if (control_ack_parse (reply.param, reply.param_len, &state, err_msg)) { if (state) { } else { printf("conctrol motor msg err: %s\r\n", err_msg); } } else { printf("conctrol motor send msg err\r\n"); } } else { fprintf(stderr, "Server not reply!\n"); } } else { fprintf(stderr, "Synchronous RPC call error!\n"); } ret = vsoa_client_sync_delete(sync); } } _pthread_exit: return (NULL); }
在 app_vsoa_client_modbus.cpp 文件中,创建 modbus_pthread 线程。
int main (int argc, char **argv) { ... /* * subscribe /state url topic * when the situation CODESYS as the VSOA Server, * the following "url.url" should be replaced by (char *)"/plc/motor0/state" */ vsoa_url_t l_url = {0}; l_url.url = (char *)"/state"; l_url.url_len = strlen(l_url.url); vsoa_client_subscribe(client, &l_url, NULL, NULL, NULL); pthread_t id; pthread_create(&id, NULL, modbus_pthread, NULL); /* * start circular monitoring */ while (1) { FD_ZERO(&fds); max_fd = vsoa_client_fds(client, &fds); cnt = pselect(max_fd + 1, &fds, NULL, NULL, &timeout, NULL); if (cnt > 0) { if (!vsoa_client_input_fds(client, &fds)) { vsoa_client_close(client); fprintf(stderr, "Connection lost!\n"); return (-1); } } } return (0); }
步骤 3:部署工程环境
将 app_vsoa_client_modbus 应用工程部署到 IGC1500 控制器中,目标设备及路径如图所示。
右击 app_vsoa_client_modbus 应用工程进行上传部署。