ARTICLE DETAIL

资讯详情

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

Omron PLC上位机通信框架:C++实现MODBUS/FINS协议

Omron PLC上位机通信框架:C++实现MODBUS/FINS协议 简介本资源是一套面向工业自动化工程师与PLC初学者的Omron PLC上位机通信开发实践代码包聚焦PLC与计算机间多协议交互实现解决设备联网、数据采集与远程监控等典型工程问题。压缩包共31个文件含5个头文件h、4个C源码cpp、1个可执行程序exe及配套资源文件rc、res、ico等涵盖MSComm串口通信封装、PLC对话框界面逻辑与调试配置文件整体体积仅417KB轻量易部署。已有128人学习下载适合嵌入式开发人员、自动化专业学生快速掌握Omron PLC通信底层机制。读者可直接复用串口通信模块mscomm.h/cpp、参考PLCDlg类实现人机交互界面、结合ReadMe.txt理解项目结构并基于MODBUS RTU/TCP、CC-Link等协议示例拓展实际产线集成方案。1. 这不是PLC编程软件而是一套可直接编译的Omron PLC上位机通信框架你手头拿到的PLC.rar压缩包表面看是“PLC代码”但实际它根本不是梯形图或结构化文本ST程序——它是一套完整的、基于MFC的Windows上位机工程目标明确用C实现与Omron PLC的底层串口/以太网通信控制。压缩包里没有.cxp、.nsx或.sys这类欧姆龙专用工程文件全是.cpp/.h/.dsp/.dsw等VC6工程构件说明它面向的是开发者而非现场工程师。这套代码不依赖CX-Programmer或Sysmac Studio而是绕过官方SDK直接操作MSComm串口控件、解析MODBUS RTU帧、构造CC-Link主站命令甚至预留了Ethernet/IP协议栈接入点。它解决的不是“怎么写逻辑”而是“怎么让PC真正读到PLC寄存器值、写入线圈、触发远程RUN/STOP”。适合需要定制HMI、数据采集系统、OPC UA网关或与非欧姆龙设备混合组网的自动化集成工程师——尤其当你被要求在老旧产线加装边缘计算节点又拿不到官方OPC Server授权时这套可修改、可调试、带完整调试日志的VC6工程比任何现成工具都更可控。2. 解析VC6工程结构从PLCDlg.h到mscomm.cpp的通信链路拆解2.1 工程入口与通信模块职责划分整个VC6工程以PLC.dsw为工作区入口主对话框类CPLCDlg定义在PLCDlg.h/cpp中是用户交互层mscomm.h/cpp封装串口操作提供OpenPort()、WriteToPort()、ReadFromPort()三类核心接口PLC.h声明协议相关常量与结构体如#define MODBUS_FC03 0x03读保持寄存器、#define OMRON_CMD_FINS 0x80FINS协议命令码。关键在于PLC.cpp——它不直接调用mscomm而是通过CPLCDlg::OnBnClickedBtnRead()触发PLC::ReadHoldingRegisters()方法该方法先按MODBUS RTU格式组装请求帧含地址、功能码、起始地址、寄存器数量、CRC校验再交由mscomm发送。这种分层设计使协议逻辑与硬件驱动解耦更换为TCP通信时只需重写PLC::SendRequest()而不动mscomm。提示PLC.dsp中Output Directory设为.\Debug\但mscomm.cpp里硬编码了COM1端口。若需适配USB转串口设备如CH340必须在mscomm.cpp第47行修改m_strPortName COM3;并确保CCommPort::OpenPort()中SetCommState()参数匹配波特率默认9600Omron CP1E系列常用。2.2 MODBUS RTU帧构造与CRC16校验实现PLC.cpp中BuildModbusRTUFrame()函数负责生成标准RTU帧。其字节序严格遵循MODBUS规范[SlaveID][Function][StartAddr_H][StartAddr_L][RegCount_H][RegCount_L][CRC_L][CRC_H]。关键代码如下// PLC.cpp 第128行 void PLC::BuildModbusRTUFrame(BYTE* pFrame, BYTE slaveID, BYTE func, WORD startAddr, WORD regCount) { pFrame[0] slaveID; // 从站地址Omron默认为0x01 pFrame[1] func; // 功能码0x03读保持寄存器 pFrame[2] HIBYTE(startAddr); // 起始地址高位 pFrame[3] LOBYTE(startAddr); // 起始地址低位 pFrame[4] HIBYTE(regCount); // 寄存器数量高位 pFrame[5] LOBYTE(regCount); // 寄存器数量低位 WORD crc CalcCRC16(pFrame, 6); // 计算前6字节CRC pFrame[6] LOBYTE(crc); // CRC低位在前 pFrame[7] HIBYTE(crc); // CRC高位在后 }CalcCRC16()采用标准MODBUS CRC16算法多项式0xA001逐字节异或查表。此处必须注意Omron部分型号如CJ1M在MODBUS模式下要求从站地址为0x00而非0x01否则返回0x83异常响应非法地址。实测时若ReadFromPort()返回空数据应先用串口助手发送00 03 00 00 00 01 84 0A读地址0的1个寄存器验证PLC是否响应。2.3 FINS协议基础帧结构与CP1E系列适配要点虽然摘要提到Ethernet/IP和CC-Link但当前工程实际聚焦FINSFactory Interface Network Service——Omron专有协议支持串口RS-232/422和以太网TCP 9600端口。PLC.h中定义#define FINS_HEADER_LEN 10PLC.cpp的BuildFINSFrame()生成标准FINS帧字段长度值说明Header10字节0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00固定填充实际使用时前4字节为网络号/节点号Command Code2字节0x00 0x01读内存区域命令Response Code2字节0x00 0x00请求时置0Data Length2字节0x00 0x04后续数据长度本例读DM区Data变长0x82 0x00 0x00 0x00 0x00 0x01DM0地址0x82DM区0x000000地址00x0001读1字注意CP1E系列默认FINS端口为TCP 9600但串口FINS需设置DIP开关SW1ON, SW2OFF启用。若mscomm发送FINS帧后无响应检查PLC面板RUN灯是否亮起STOP状态下FINS服务关闭并确认PLC.cpp中m_nFinsNodeAddr设为PLC实际节点号默认000。3. 编译与调试VC6环境配置、串口权限及PLC侧关键设置3.1 VC6工程编译前的三项强制修改原始工程为VC6 SP5环境构建现代Windows 10/11需做兼容性调整平台SDK路径修正打开Tools → Options → Directories将Include files路径改为C:\Program Files (x86)\Microsoft Visual Studio\VC98\Include若VC6安装在默认路径链接器输出路径右键工程→Settings → Link → Output file name改为.\Debug\PLC.exe避免因路径含空格导致链接失败Unicode字符集禁用Project → Settings → General → Character Set选Not Set否则CString与char*转换报错。编译成功后生成PLC.exe双击运行会弹出主界面但此时串口仍无法通信——因为Windows 10对COM端口有严格权限控制。3.2 Windows串口权限获取与设备管理器验证在管理员权限CMD中执行# 查看当前用户对COM1的ACL icacls COM1 # 若提示拒绝访问需添加权限 echo y | cacls COM1 /G %USERNAME%:F更可靠的方式是进入设备管理器 → 端口(COM LPT) → 属性 → 端口设置 → 高级勾选使用FIFO缓冲区并设置接收缓冲区1024。实测发现未启用FIFO时mscomm.cpp中WaitForSingleObject(m_hEvent, 100)超时概率达70%启用后稳定在毫秒级响应。3.3 Omron PLC侧四步必设配置PLC端配置错误是通信失败的主因需逐项核验步骤操作位置关键参数验证方法1. 通信模式选择CX-Programmer → PLC属性 → 通信设置选Host Link或MODBUS-RTU非FINS面板显示HL或MB标识2. 波特率匹配同上 → 串口设置必须与mscomm.cpp中m_dwBaudRateCBR_9600一致用万用表测TX/RX电平变化频率3. 从站地址设定CX-Programmer → 在线 → PLC设置 → 网络设置Unit No.设为001对应代码中slaveID0x01修改后需断电重启PLC4. 内存区使能CX-Programmer → 在线 → 内存区设置确保DM区数据存储器未被密码锁定尝试用CX-Programmer手动写入DM0值提示若PLC型号为NJ/NX系列需在Sysmac Studio中启用Controller Settings → Communication → Host Link并关闭Security → Password Protection否则FINS命令返回0x0001错误码访问拒绝。4. 协议切换实战从MODBUS RTU到FINS TCP的代码改造4.1 替换通信通道串口→TCP Socket的关键改动mscomm.h仅支持串口要接入FINS TCP需新增fins_tcp.h/cpp。核心改动在PLC.cpp// 原mscomm调用第215行 // m_mscomm.WriteToPort(pFrame, frameLen); // 改为TCP发送新增代码 SOCKET sock socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in addr; addr.sin_family AF_INET; addr.sin_port htons(9600); // FINS默认端口 addr.sin_addr.s_addr inet_addr(192.168.1.10); // PLC IP connect(sock, (sockaddr*)addr, sizeof(addr)); send(sock, pFrame, frameLen, 0); closesocket(sock);此处必须注意FINS TCP帧不包含CRC校验且首部10字节需填充有效网络号0x0000表示本地网络、节点号0x0001对应PLC节点号。若PLC IP为192.168.1.10则pFrame[0]0x00; pFrame[1]0x00; pFrame[2]0x00; pFrame[3]0x00; pFrame[4]0x00; pFrame[5]0x00; pFrame[6]0x00; pFrame[7]0x00; pFrame[8]0x00; pFrame[9]0x00;即全0网络号。4.2 FINS内存区读取指令详解与DM区实测PLC.cpp中ReadDMArea()函数构造FINS读DM区指令// 读DM0地址16位字 BYTE finsFrame[20] {0}; finsFrame[0] 0x00; finsFrame[1] 0x00; // 网络号 finsFrame[2] 0x00; finsFrame[3] 0x00; // 节点号 finsFrame[4] 0x00; finsFrame[5] 0x00; // 单元号 finsFrame[6] 0x00; finsFrame[7] 0x00; // CPU号 finsFrame[8] 0x00; finsFrame[9] 0x00; // 命令码读内存 finsFrame[10] 0x00; finsFrame[11] 0x01; // 命令码0x0001读 finsFrame[12] 0x00; finsFrame[13] 0x00; // 错误码请求时为0 finsFrame[14] 0x00; finsFrame[15] 0x04; // 数据长度4字节区码地址长度 finsFrame[16] 0x82; // 区码0x82DM区 finsFrame[17] 0x00; finsFrame[18] 0x00; finsFrame[19] 0x00; // 地址00x000000 // 后续2字节为读取长度0x00011字实测时在CX-Programmer中向DM0写入0x1234运行PLC.exe点击“读DM区”按钮OnReceiveData()回调中解析pRecv[20]起始的响应帧pRecv[24]和pRecv[25]即为0x12和0x34——验证FINS TCP读取成功。4.3 CC-Link主站模拟的可行性边界分析摘要提及CC-Link但工程中无相关代码。CC-Link需专用主站模块如CS1W-CLK21及从站PLC纯软件模拟不可行。可行替代方案是用PLC.cpp扩展SendCCLinkCommand()函数通过Omron提供的CCLinkLib.dll需额外购买调用CCLink_Open()但此DLL仅支持Windows XP/7且不兼容64位系统。当前工程更现实的路径是将CC-Link从站数据映射至DM区再用现有FINS/TCP读取——即PLC侧用梯形图将CC-Link采集的温度值存入DM100上位机读DM100即可间接获取CC-Link数据。5. 故障诊断黄金法则三类典型错误的定位与修复5.1 串口通信超时的五层排查法当ReadFromPort()返回空数据按以下顺序逐层验证层级检查项工具/方法修复动作物理层TX/RX线是否反接万用表测PLC TX脚对地电压空闲时5V交换DB9针脚2/3链路层波特率/停止位/校验位串口助手XCOM发0000000000000000000000000000000000000000000000000000000000000000在CX-Programmer中设为9600,N,8,1协议层MODBUS地址是否越界XCOM发送01 03 00 00 00 01 84 0A查PLC手册确认DM区起始地址为D0000而非D0应用层mscomm.cpp缓冲区溢出在OnReceiveData()中加TRACE(Recv:%d bytes\n, nBytes);将m_nMaxReadLength从1024改为4096系统层Windows驱动冲突设备管理器禁用Microsoft Serial Ballpoint卸载所有虚拟串口驱动如Virtual Serial Port Driver5.2 FINS响应码速查表与对应处理FINS响应帧第12-13字节为错误码常见值及含义错误码HEX含义代码修复建议00 00正常响应解析后续数据00 01未登录/密码错误在CX-Programmer中清除PLC密码或设No Password00 02命令不支持检查PLC型号是否支持该FINS命令如CP1E不支持0x0002写位00 03地址无效核对区码0x82DM,0x00IR与地址范围DM0~DM999900 04数据长度超限将单次读取寄存器数从100改为100x000A在PLC.cpp的ParseFINSResponse()中加入判断if (pResp[12] 0x00 pResp[13] 0x03) { AfxMessageBox(FINS Error: Invalid Address! Check DM area range.); return FALSE; }5.3 VC6调试技巧利用TRACE宏捕获实时通信帧在mscomm.cpp的OnReceiveData()开头插入CString strHex; for(int i0; inBytes; i) { strHex.AppendFormat(%02X , pBuf[i]); } TRACE(RX[%d]: %s\n, nBytes, strHex);配合OutputDebugString()可在VC6的Output窗口实时查看收发帧。例如看到发送01 03 00 00 00 01 84 0A后收到01 03 02 00 00 B8 44即确认MODBUS RTU通信已通——02为字节数00 00为DM0值B8 44为CRC。注意TRACE仅在Debug版生效Release版需改用OutputDebugString()并配合DebugView工具捕获。最后一步把PLC.exe复制到产线工控机用记事本打开ReadMe.txt按其中Step 3: Set PLC to Host Link Mode操作然后双击运行——当界面上的DM0 Value:从0x0000跳变为0x1234时你就完成了对这套二十年前VC6工程的现代产线复活。本文还有配套的精品资源点击获取
返回列表