在工业自动化这行摸爬滚打多年,从日系PLC到国产PLC都碰过,但真正让我觉得“编程体验”上了一个台阶的,是第一次用CODESYS开发汇川AC801运动控制项目。汇川不只是做变频器和小型PLC,它的中大型PLC产品线——AC801实时运动控制器、AM400/AM600系列中型PLC——底层全部跑在CODESYS V3平台上。这意味着什么?意味着你用汇川AM600做过程控制,和用AC801做多轴运动控制,用的是同一套CODESYS开发环境,只是设备描述文件和许可证不同。这篇文章就是想把这条“奇妙之旅”上的实践细节、踩坑教训和选型思路完整记录下来,适合刚接触汇川中大型PLC、或者正打算从InoProShop切换到CODESYS平台的工程师参考。
1. 为什么汇川中大型PLC会站在CODESYS这条赛道上
1.1 从InoProShop到CODESYS:一次开发环境的“换挡”
很多人第一次打开汇川AM600的编程软件时会发现,界面似曾相识。没错,汇川的InoProShop本质上就是基于CODESYS V3定制出来的,只是换了一套品牌壳、汉化了菜单、内置了汇川的硬件库。所以当你用InoProShop写AM400/AM600时,你已经默默在使用CODESYS了;而当你直接用CODESYS V3.5连接AC801、AM400、AM600时,反而会看到更“原汁原味”的IEC 61131-3编程环境。
从工程角度来说,CODESYS真正值钱的地方不只是“标准编程语言”,而是它把控制器开发需要的东西全揉在了一起:IEC 61131-3六种编程语言、PLCopen运动控制库、现场总线配置(EtherCAT/CANopen/Modbus)、可视化界面、在线调试、库管理。这套生态对设备厂家特别友好,所以你会发现不光是汇川,很多国产中高端PLC、运动控制器都在CODESYS上做二次开发。对工程师来说,这是一个“学一次,多个品牌通用”的赛道。
1.2 AC801、AM400、AM600三兄弟的定位差异
汇川这三款产品虽然都跑在CODESYS平台上,但定位完全不同,项目选型时先要拎清楚。
| 型号 | 产品定位 | 主要接口与总线 | 运动控制能力 | 典型应用 |
|---|---|---|---|---|
| AC801 | 运动控制器 | EtherCAT、以太网、CANopen、RS485 | 最多支持几十轴,EtherCAT同步 | 锂电设备、3C贴装、包装机械、飞剪/追剪 |
| AM400 | 中型PLC | 以太网、CANopen、RS485、EtherCAT(部分型号) | 可带少量轴,逻辑为主 | 单机设备、注塑机辅机、小型产线 |
| AM600 | 大型/过程级PLC | 双以太网、CANopen、Profibus-DP可选、EtherCAT可选 | 偏逻辑与过程控制,运动能力弱于AC801 | 产线级控制、暖通空调、能源管理、大型设备集中控制 |
我自己的选型经验:只要项目里有超过两三个伺服轴、且有高速同步需求,直接上AC801;如果只是做产线逻辑控制、数据采集、HMI通讯,AM600的双网口和较大程序空间更合适;AM400则刚好卡在两者中间,适合“逻辑为主、轴不超过四五个”的工况。千万不要用AM400硬撸多轴运动控制,到后期扩展轴数和扫周期时你会非常难受。
2. 开发环境准备:从安装到第一次上载程序的完整链路
2.1 CODESYS安装与设备描述文件的“坑”
CODESYS安装本身不算难,去官网下载CODESYS V3.5(建议SP17以上版本,汇川的库对新版本兼容性更好),一路Next装完。但紧接着就会遇到第一个坑:打开CODESYS新建工程时,Device列表里压根找不到AC801、AM400、AM600。这是因为你还没装汇川的设备描述文件,也就是Package包。
正确操作顺序是:
- 安装CODESYS V3.5基础环境。
- 从汇川官网或随附资料包获取对应的设备包文件(通常是.package或.codesys-package格式)。
- 在CODESYS主界面点击“工具 → 包管理器 → 安装”,选择汇川设备包。
- 安装完成后重启CODESYS,新建工程时就能在设备列表里看到汇川的控制器型号。
这个步骤最大的坑是版本匹配。比如你装了CODESYS V3.5 SP19,但汇川设备包是基于SP17编译的,那么大多数情况下没问题;如果反过来,设备包基于SP20编译,你的环境是SP17,CODESYS会直接拒绝加载或报“未找到依赖的库”。所以我的习惯是:装环境和装设备包前,先看一眼汇川官方发布说明里推荐的CODESYS版本,不要盲目追新。
2.2 连接方式与上载程序:源文件不是你想上就能上
AM400/AM600/AC801都支持以太网连接,部分型号有USB口。以太网连接最简单,把电脑和PLC放进同一个网段,新建工程后在设备树里双击“Device”,设置IP地址,点击“登录”即可。这里有个小坑:如果现场PLC的IP地址忘了,先用汇川的搜索工具或CODESYS的“扫描网络”功能搜一下,有些老固件默认是通过拨码设置IP,改之前记得拍照记录。
再说上载程序。很多工程师第一次用CODESYS上载汇川PLC时都会问同一个问题:“为什么我上载回来的工程没有源代码,只有一堆功能块和变量?”答案是:这取决于下载程序时有没有勾选“包含源代码”选项。CODESYS的工程下载到PLC时,默认状态下可以选择是否把完整源代码一并写入控制器。如果没勾选,PLC里只有编译后的机器码,上载时只能得到代码框架、变量表和库引用,没法还原ST和梯形图。
所以项目管理上要形成一条铁律:下载前主动勾选“允许上载源代码”,或者干脆在每次下载时选“工程 → 创建引导工程”,把源代码打进引导程序里。现场维护人员上载回来后,至少能拿到一份可读、可修改的工程。
2.3 下载程序的三种启动方式
CODESYS下载程序时,会弹出一个对话框让你选择启动方式:热启动(Warm Reset)、冷启动(Cold Reset)、初始化复位(Origin Reset)。这也是新手容易搞混的地方。
- 热启动:保留保持变量和普通变量,处理器重新开始执行程序。适合程序小改动后快速恢复生产。
- 冷启动:清除普通变量,保持变量(VAR RETAIN)保留,重新初始化程序。适合需要重新初始化状态、但不想丢失掉电保持数据的场景。
- 初始化复位(Origin Reset):把所有变量(包括保持变量)全部清零,回到出厂般的初始状态。适合调机阶段或者程序逻辑大规模重构后。
我的建议:生产设备上做在线下载时,默认选“热启动”或“冷启动”,选之前一定要确认设备处于安全状态;调试阶段可以随便点,但不要养成一有问题就“Origin Reset”的习惯,否则掉电保持的配方、累计产量、补偿参数全部清零,现场会很难看。
3. 用ST语言写汇川PLC:从梯形图思维到文本编程的切换
3.1 ST语言为什么在CODESYS项目里是主力
虽然CODESYS支持梯形图、功能块图、顺序功能图、结构化文本等多种编程语言,但我在做汇川AC801/AM400/AM600项目时,主力语言几乎全是ST(结构化文本)。原因很简单:这套设备的项目通常不是“几个点动、互锁”那么简单,而是要处理运动控制、配方管理、数据通信、报警分级、产量统计。这些内容如果用梯形图写,动辄几十个网络页,翻页翻到怀疑人生;用ST写,一段CASE状态机就能把十几步动作描述清楚。
而且CODESYS支持同一个工程里不同POU用不同语言:简单逻辑用梯形图,复杂算法用ST,状态流程用SFC。我会在设备树里明确分工,比如轴控制FB全部用ST,外围气缸逻辑用LD,流程主控用SFC,让不同习惯的维护人员都能上手。
3.2 正弦运动、延时指令、比较中断的ST写法
先说延时。传统PLC里是TON/TOF定时器,CODESYS里也一样,但用ST调用功能块的写法对新手需要适应一下:
VAR fbDelay : TON; bStart : BOOL; bDelayOK : BOOL; END_VAR fbDelay(IN := bStart, PT := T#5S); bDelayOK := fbDelay.Q;这样一段代码就实现了输入信号保持5秒后输出的效果。注意TON的实例必须声明为VAR,不能每次调用都重新声明,否则定时器计时会被不断清零。
再说“比较中断”。这个词在汇川小型PLC(比如H3U/H5U)里有对应指令,但AM400/AM600/AC801这套CODESYS平台里并没有传统意义上“数值达到某个值就立即中断主程序”的指令。更常规的做法是建立一个高优先级独立循环任务,比如1ms任务,专门做比较逻辑:
IF rActualSpeed >= rSpeedLimit THEN bSpeedAlarm := TRUE; ELSE bSpeedAlarm := FALSE; END_IF这个任务独立于主程序运行,扫描周期固定1ms,一旦实际速度超过阈值,bSpeedAlarm在1ms内就能翻转,效果上已经非常接近“比较中断”。在AC801上做运动控制时,我常用这种方式做软限位和跟随误差保护,比在默认主任务里比较可靠得多。
最后说正弦运动。如果项目里需要做往复运动、摆动、或者傅里叶式速度规划,CODESYS的运动控制库里不一定有封好的“正弦运动”功能块,通常我会自己写一个速度规划FB,比如实现“速度按正弦曲线变化”。
FUNCTION_BLOCK FB_SineMove VAR_INPUT fAmplitude : REAL; // 最大速度幅值 fFrequency : REAL; // 摆动频率 Hz END_VAR VAR_OUTPUT fVelocityCmd : REAL; // 当前速度指令 END_VAR VAR fbCycle : TON; fTime : LREAL; bFirst : BOOL := TRUE; END_VAR // 每10ms累加一次时间 fbCycle(IN := TRUE, PT := T#10MS); IF fbCycle.Q THEN fbCycle(IN := FALSE); fTime := fTime + 0.01; END_IF fVelocityCmd := fAmplitude * SIN(6.28318 * fFrequency * fTime);然后在运动控制轴里用MC_MoveVelocity功能块,把fVelocityCmd作为速度输入即可。这样做的好处是运动曲线平滑,对机械冲击小,特别适合涂胶、点胶、往复打磨这类应用。
3.3 文件读写与动态文本的实际用法
CODESYS平台最让我喜欢的点之一,就是它对文件操作的支持。在传统国产小型PLC里,想存一条配方或导出一条报警记录,往往要拼外部HMI去实现;而在CODESYS里,可以直接用CAA File库对U盘或控制器本地文件做读写。
一个很实用的场景是做配方导入导出。把一台设备的几十个工艺参数存成CSV文件,放在U盘里,PLC启动时去读,操作工改配方时直接在触摸屏上选文件,PLC自动加载。核心代码是:
// 打开文件 hFile := FileOpen(sFileName, FILE_MODE_READ OR FILE_MODE_BINARY); // 读取一行 FileRead(hFile, pBuffer, uiSize, uiRead); // 关闭文件 FileClose(hFile);注意sFileName的路径格式取决于目标设备,Windows控制器用盘符路径,Linux控制器用挂载路径,最好在手册里确认。另外文件读写不要放在1ms或者5ms的快速任务里,会拖慢任务周期,我一般放在普通任务或专门的任务里,由标志位触发执行。
再说动态文本(Dynamic Text)。如果你做CODESYS可视化界面,又不想为了几十个状态变量做一堆文本切换,Dynamic Text控件是最省事的方案。它本质上是一个文本显示控件,绑定一个整型变量或枚举变量,然后配置变量值与显示文本的映射关系。比如设备状态变量bState=0时显示“停止”,=1时显示“运行中”,=2时显示“故障”。现场调试时,我习惯把所有报警码和状态码做成枚举,可视化里配好动态文本,操作工一眼就能看懂,不用总盯着数字猜含义。
4. 通讯实战:多协议选择的底层逻辑与实操配置
4.1 汇川电机通讯协议选型:新手最容易纠结的问题
汇川电机(包括变频器和伺服驱动器)支持的通讯协议很多,新手特别容易纠结。我按使用场景给一个直观的分层建议:
| 协议类型 | 物理层 | 实时性 | 上手难度 | 推荐场景 |
|---|---|---|---|---|
| Modbus RTU | RS485 | 低 | 低 | 变频器启停、低速率参数读写、点位少的场合 |
| Modbus TCP | 以太网 | 中 | 低 | 与上位机、MES系统交互 |
| CANopen | CAN | 中高 | 中 | 多轴小规模控制、IO扩展、传感器接入 |
| EtherCAT | 高速以太网 | 高 | 中高 | 多伺服轴高同步运动控制 |
| Profinet/EtherNet/IP | 以太网 | 中高 | 中 | 与西门子等第三方PLC对接 |
如果只是入门,我强烈建议从Modbus RTU开始。原因很简单:RS485接线简单,报文格式公开透明,用串口助手就能调试,出了问题一拍一个准。而EtherCAT虽然性能强,但初次接触要理解主站、从站、DC同步、PDO映射这些概念,学习曲线陡很多。
4.2 RS485控制MD200T变频器:一个最经典的案例
MD200T是汇川很常见的通用变频器,支持Modbus RTU。我举一个用AM400/AM600的RS485口直接控制MD200T的经典例子,协议就是Modbus RTU,从站地址1,波特率9600,8数据位1停止位无校验。
变频器侧需要设置的参数大致如下(具体以对应手册为准):
| 参数号 | 含义 | 设定值 |
|---|---|---|
| P00.00 | 运行命令通道 | 2:通讯控制 |
| P00.01 | 频率设定通道 | 2:通讯设定 |
| P97.00 | 通讯地址 | 1 |
| P97.01 | 通讯波特率 | 3:9600 |
| P97.02 | 数据格式 | 0:无校验8N1 |
写频率时,Modbus地址一般对应频率设定寄存器,单位是0.01Hz,所以设定50.00Hz要写入5000。启动变频器是往控制字寄存器写正转命令,停止是清零或写停止码。
在CODESYS里调用Modbus库,用ModbusMaster功能块,组帧如下:
// 正转启动:功能码06,寄存器地址16#2000,数据16#0001 // 频率50Hz:功能码06,寄存器地址16#2001,数据16#1388如果不想依赖库,也可以自己用串口功能块组Modbus RTU帧,关键是CRC16算法。下面是我常用的一段CRC16计算ST代码,可以直接抄:
FUNCTION F_CRC16 : WORD VAR_INPUT pData : POINTER TO BYTE; uiLen : UINT; END_VAR VAR i : UINT; j : INT; wCrc : WORD; END_VAR wCrc := 16#FFFF; FOR i := 0 TO uiLen - 1 DO wCrc := wCrc XOR pData[i]; FOR j := 0 TO 7 DO IF (wCrc AND 16#0001) <> 0 THEN wCrc := (wCrc SHR 1) XOR 16#A001; ELSE wCrc := wCrc SHR 1; END_IF END_FOR END_FOR F_CRC16 := wCrc;网上很多人搜“200smart如何通过RS485控制汇川MD200T变频器实例”,西门子S7-200 Smart走的也是Modbus RTU,逻辑一样:指令库MBUS_CTRL + MBUS_MSG,写控制字和频率寄存器。这个方案在汇川AM400上同样成立,只是把库换成CODESYS的Modbus库。我实际测试下来,用AM600通过RS485控制MD200T的启动频率切换,响应稳定在几十毫秒级,完全够用。
4.3 CAN自由口编程与伺服终端电阻
“汇川CAN自由口编程”是论坛里一个高频词。所谓自由口,就是不使用标准CANopen协议栈,直接用CAN控制器发送和接收自定义报文。这样做的好处是报文格式自己定,跟自定义设备对接非常灵活;坏处是失去了CANopen的标准化对象字典和PDO机制,每台设备都要自己定义ID和数据含义,后期维护全靠注释。
我建议大家评估一下:如果对接的是汇川自家伺服SV660、IS620N,或者第三方标准CANopen设备,优先用CANopen协议,CODESYS里挂一个CANopen Master,直接配置PDO映射,比自由口省事太多。只有对接某些非标设备、对方只提供原始CAN帧协议时,才考虑自由口。真要用自由口,CODESYS里通常需要通过CAN卡驱动或厂家的CAN接口库来实现,先确认目标控制器是否有对应的CAN底层访问接口。
再说终端电阻。无论用CANopen还是CAN自由口,CAN总线两端必须各接一个120欧姆终端电阻。汇川的伺服驱动器和不少控制器都有内置终端电阻,有的通过拨码开关(比如SW1、SW2)开启,有的通过软件参数设置。很多现场通讯偶发报错、跑一段时间就掉线,排查半天最后发现是终端电阻没拨。两个端节点各拨一组,中间节点全部不拨,这是铁律。总线距离长的时候,还要注意使用双绞屏蔽线、屏蔽层单端接地,这些细节往往比协议本身更影响稳定性。
5. 库文件、封装与团队协作:把项目从“能跑”变成“好维护”
5.1 生成库文件的正确姿势
CODESYS最强大的能力之一就是“库化”。如果你写了一组很好用的功能块,比如“设备状态管理”、“配方解析”、“轴回零序列”,完全可以把它们打包成一个库文件,供多个项目复用。操作路径是:在工程里选中要发布的POU,右键“保存为库”,设置库名称、版本号、公司信息,确定对外可见的接口POU,把内部变量和辅助函数隐藏起来。
生成库时有一个关键点:选择与目标控制器匹配的兼容版本。如果你库代码里用了CODESYS V3.5 SP19才出的新语法,而另一个项目还在用SP17环境,那个项目加载库时会直接报错。所以我一般让库版本“向下兼容”,尽量只用基础IEC语法和PLCopen库,避免为了少写两行代码引入高版本特性。
5.2 封装与版本管理的经验
我对项目中的代码封装要求很明确:功能块要“高内聚、低耦合”。比如一个负责EtherCAT伺服轴启停的功能块,输入是轴引用、使能信号,输出是轴状态、报警代号,内部实现里再复杂的逻辑都不影响外部调用。这样即使从AM400换到AC801,甚至换到另一个品牌的CODESYS控制器,只要PLCopen库接口不变,上层逻辑几乎不用改。
版本管理是我强烈建议团队补上的环节。CODESYS的.project工程文件可以用Git或者SVN管理,关键不只是提交代码,还要把库文件、设备包版本、PLC固件版本一起记录在设备台账里。现场出现“程序一样但行为不同”的问题,十有八九是控制器固件版本或CODESYS库版本不一致。我的习惯是在每个项目根目录放一个README.txt,写明:
- 开发环境版本(CODESYS V3.5 SP19)
- 固件版本
- 依赖的库文件及版本
- 下载选项(是否包含源代码)
- PLC IP及站点名称
有了这些信息,半年后回头维护项目,或者换人接手,都不会一脸茫然。
6. 实战踩坑排查链:从现象到根因的完整复盘
6.1 案例一:程序下载后设备不动作的排查
现象:用CODESYS给一台AM600下载完程序后,PLC停止运行,即使切到RUN也不动作。排查过程:
- 先看PLC状态指示灯,是否运行时马上跳STOP。如果跳STOP,打开CODESYS里的“设备 → 诊断 → 日志”查看异常,常见原因是程序里触发了看门狗故障,或者访问了无效硬件地址。
- 切到在线监控模式,观察主任务是否在运行。CODESYS默认任务如果周期设置过短,而程序量又大,可能会导致任务超时,控制器自动进入STOP。把任务周期从1ms改到5ms或10ms,问题往往会消失。
- 检查是不是下载时选了“初始化复位”,把保持型变量全部清了。比如轴位置、补偿值、变频器通讯参数,这些数据清零后设备自然不动作。重启设备、重新触发一次初始化流程,问题解决。
这个案例给我的教训是:下载前先看“启动方式”弹窗,选错了别着急怪程序。现场处理时尽量用“热启动”,不要一上来就“Origin Reset”。
6.2 案例二:UDP通讯偶发断线的根因
现象:AC801通过UDP与上位机视觉系统通讯,运行十几个小时后偶发收不到数据,必须重启控制器或上位机程序才恢复。排查链路:
- 先用Wireshark在上位机侧抓包,确认UDP报文是否有从PLC发出。抓到表明PLC发出来了,问题出在上位机接收侧;抓不到说明PLC侧没发。
- 查看CODESYS里的Socket任务周期。我在项目里最初把UDP收发放在主任务里,主任务周期10ms,而视觉系统的发送周期是5ms,导致UDP缓冲区不断有数据塞进来,PLC来不及读,缓冲区溢出后Socket句柄异常,通讯卡死。
- 解决:把UDP收发独立成一个循环任务,周期2~4ms,并每次读取时循环把缓冲区里所有待处理报文取出,直到缓冲区空,而不是只处理最新一条。另外加上心跳序号,若连续N个周期没收到心跳,主动关闭Socket并重新创建。
处理完这个案例后,连续跑了一周没有再断。关键经验:UDP通讯不可靠是常态,工业现场必须在应用层做数据校验和断线重连,不能依靠“发一次就永远通”的侥幸心理。
6.3 案例三:上载程序与源文件不一致的问题
现象:设备维护人员在现场用CODESYS上载了PLC程序,和公司电脑上的工程文件做对比,发现大量功能块内容对不上,怀疑是谁改过程序没同步。排查后确认:原开发工程师在几个月前用在线修改方式改过几个参数,但没有把修改同步到本地工程文件。PLC里跑的是“修改后”的代码,本地工程还是“修改前”的版本,所以上载回来后差异巨大。
处理方式:在CODESYS里登录在线状态时,先点击“在线 → 工程设置 → 比较”,用“在线与此工程比较”功能,逐项对比POU、变量、库版本,确认差异后决定是上载覆盖本地,还是本地覆盖现场。更重要的是建立流程:每次在线修改后,立即同步工程文件并提交版本库,避免“现场最新、电脑不是最新”的两头分叉状态。
我在实际项目里还养成了一个习惯:转产或交付前,从PLC上载一份完整工程,另存为“现场已交付版本”放在项目归档目录里。真出问题时,先拿这份归档文件做基准,而不是拿开发电脑里的“你以为的最新版”做基准。
最后再分享一个实用小技巧:CODESYS底层是连续的在线环境,改程序时不要频繁“Register下载”再“Reset”,尽量用在线修改(Online Change)把小的改动直接投入运行。但前提是你的修改没有增加新变量类型、没有删除POU、没有改变任务配置,否则在线修改会失败,只能走完整下载流程。掌握这个边界,能让你在不停机的状态下安全地迭代程序。