在项目里用欧姆龙CP1H去跟台达VFD-M变频器做自由口通讯,很多人第一反应是“这还要写教程”?但真到了现场,你会发现值得踩的坑一个都不少:自由口模式下报文怎么组织、CRC高低字节往哪儿放、变频器参数有没有切到通讯模式、RS485正负接反、寄存器地址差一位……随便哪一个都能让你白折腾半天。这篇文章就从一个实际用CP1H无协议通讯接台达VFD-M变频器的例子入手,把从硬件接线、变频器参数设置、Modbus报文组装到梯形图程序实现的完整链路走一遍,顺手把那些“手册不会明说”的经验一并交代了。
适读人群:正在用欧姆龙CP1H做主站、想控制台达变频器的一线电气工程师,或者刚接触自由口通讯、对Modbus RTU报文体感还不够深的新手。文章里的程序思路不挑PLC品牌,换成其他支持无协议串口收发的PLC也能照搬。
1. 通讯方案整体设计思路:为什么用自由口做Modbus
1.1 应用场景与需求拆解
最常见的使用场景是这样:一台机器上有欧姆龙CP1H做逻辑控制,旁边是一台台达VFD-M变频器带着电机跑,HMI或者上位机要求能远程设定频率、启停电机、再读回实际频率和电流。
要实现这个功能,方案其实有好几条。一是给CP1H加一块专用的Modbus-RTU从站/主站模块,但成本上去了,而且CP1H本体不少型号并没有现成的Modbus主站扩展模块可用,得靠功能块去模拟。二是用CP1H自带的串口做HOST Link跟触摸屏通讯,让屏直接去读变频器,但这样PLC程序里拿不到变频器的实时数据,后续做逻辑联动(比如频率到了才允许动作)就非常别扭。
所以最务实的就是第三条路:把CP1H的串口设置为“无协议”通讯模式,用自由口方式自己组织Modbus RTU报文,CP1H作为主站去轮询台达VFD-M。
1.2 自由口通讯的本质
自由口通讯这个词听起来玄乎,本质上就是一句话:串口不再跑固定的HOST Link协议,而是完全由用户程序决定发什么字节、收什么字节。欧姆龙CP1H里实现收发就两条指令:TXD发送、RXD接收。你把一串数据放到数据区里,TXD把它从串口发出去;变频器回的数据进了串口寄存器,RXD再把它读进数据区。
Modbus RTU是一个极其简单的协议:一帧报文就是“从站地址 + 功能码 + 数据 + 16位CRC校验”。它天然适合用自由口做,因为报文本身没有复杂的帧头帧尾和转义规则,就是裸字节流。CP1H做Modbus主站,核心工作就四件事:组帧、发帧、收帧、解帧。中间再插入一个轮询调度,让多个读写任务有条不紊地跑。
1.3 为什么不直接买通讯模块
可能有人问,既然台达和欧姆龙都有针对性的通讯方案,为什么不直接买现成的网关或者模块?原因很现实:成本只是一方面,更重要的是现场维护的透明性。
自由口方案的报文是自己在程序里组装的,变频器回的数据也是自己解析的。一旦现场通讯异常,看一下程序里的收发缓冲区,一眼就知道报文死在哪个环节:是没发出去,还是发了变频器没回,还是回了但CRC不对。而用现成的通讯模块,报文被封装在模块内部,出了问题只能拿串口助手下到线上去抓包,反而多一道工序。
对熟悉梯形图的工程师来说,自由口方案的调试难度不高,只要把协议解析清楚,剩下的工作量其实不大。另外,CP1H本身留了内置串口和扩展通信板两种方式,不需要额外增加太多硬件成本。
2. 硬件接线与变频器侧参数配置
2.1 CP1H串口扩展方案对比
CP1H做自由口通讯,常见的硬件接法有三种,我直接按推荐顺序排:
| 方案 | 硬件组成 | 优点 | 缺点 |
|---|---|---|---|
| 推荐方案 | CP1H + CP1W-CIF11 RS-485通信板 | 稳定、RS485电平直接引出、端子接线方便 | 需要占用扩展槽,增加一块板卡成本 |
| 常规方案 | CP1H内置RS232C口 + RS232转RS485转换器 | 不需要扩展板,成本最低 | 转换器质量参差不齐,高速通讯容易丢数据 |
| 较少用 | CP1W-CIF01/CIF02 转接电缆 | 适合原有老设备改造 | 灵活性差,现在基本不推荐 |
CP1W-CIF11是插在CP1H主机上的RS-485通信板,插上之后相当于给PLC扩展了一个标准RS485串口。对于要和变频器组网通讯的场景,我通常优先选它,直接端子对端子,接线比RS232转485中间加转换器干净得多。
顺带说明一点:CP1H内置的RS232C口做自由口通讯是可以的,但RS232是点对点、电压型信号,距离和抗干扰都比RS485差。变频器现场多的是强电干扰,能用RS485就尽量不用RS232。
2.2 RS485接线细节
RS485是两线制半双工通讯,CP1W-CIF11上一般会有S+和S-两个接线端子。对应的,台达VFD-M的通讯端子上通常也是两组标识,常见的是S+、S-,部分机型标成D+、D-,个别版本还带一个SG端子作为信号地。
接线要注意这几件事:
- 极性不能反。S+接S+,S-接S-,一旦反了,变频器收不到任何数据,但绝大多数情况下不会烧设备,只是通讯不上。
- SG信号地建议连接。把两边的SG或者0V连在一起,可以降低共模干扰导致的通讯误码。但注意,这是信号地,不要跟变频器的主回路地混在一起。
- 通讯线用屏蔽双绞线。变频器输出侧就是强干扰源,普通平行线走一两米问题不大,走远了高频干扰会让你抓狂。
- 屏蔽层单端接地。屏蔽层只在PLC侧(或者只在变频器侧)接地,不要两头都接,避免形成地环路电流。
- 终端电阻。RS485总线两端各接一个120欧姆终端电阻。CP1W-CIF11上一般有跳线或者拨码可以启用终端电阻;VFD-M可以查一下手册看有没有内置终端电阻选项。实际距离在10米以内、只有两台设备时,终端电阻可以先不接;超过20米或者有干扰症状就接上。
2.3 台达VFD-M关键的参数设置
变频器的通讯参数没有设置对,程序写得再好也是白搭。VFD-M的通讯相关参数,重点看这几个:
| 参数号 | 名称 | 推荐值 | 说明 |
|---|---|---|---|
| 00-01 | 通讯地址 | 1 | 从站地址,范围1~254,PLC发报文时用同一个地址 |
| 00-02 | 通讯速率 | 1 | 9600bps,PLC侧串口必须一致 |
| 00-03 | 通讯协议 | 0或1 | 务必选Modbus RTU,不要选ASCII |
| 00-04 | 通讯数据格式 | 3或5 | 8-E-1或8-N-2,PLC侧必须一致 |
| 01-00 | 主频率指令来源 | 2 | 2代表RS485通讯给定频率 |
| 01-01 | 运转信号来源 | 2 | 2代表RS485通讯给定启停命令 |
这里一定要多说一句:很多新手把通讯线接好了,用Modbus调试工具发报文,变频器能正常响应,可PLC程序一跑却发现控制不了——原因就是变频器的频率指令来源和运转信号来源没有切换到“通讯”。如果这两个参数还是面板或端子给定的状态,PLC发再多的正转命令,变频器也只会按照自己的频率来源执行。
另外,修改变频器通讯参数之后,有些机型需要断电重新上电才完全生效,尤其是数据格式和协议相关的参数。参数改完最好断电重启一次,别在调试时反复怀疑是自己的程序有问题。
2.4 串口参数一致性检查表
CP1H侧和VFD-M侧串口参数必须完全一致,否则会出现“报文发出来了,变频器回了一堆乱码”或者“变频器直接不理你”的情况。对照表如下:
| 参数 | PLC侧(CX-Programmer串口设置) | 变频器侧(VFD-M参数) |
|---|---|---|
| 波特率 | 9600 | 00-02=1 |
| 数据位 | 8 | 00-04对应8位 |
| 校验位 | 无校验或偶校验 | 00-04对应 |
| 停止位 | 1位或2位 | 00-04对应 |
| 从站地址 | 报文首字节=01 | 00-01=1 |
一个常见的坑:默认情况下,PLC侧的串口如果设置了无协议模式,某些手册会默认“8位数据、无校验、2停止位”,而变频器默认是“8-N-2”,两边一凑往往就通了。但如果你把PLC侧改成了偶校验,变频器那边就必须同步改成偶校验,漏改一个字节都会导致整个通讯失败。
3. Modbus报文与CRC校验:先把协议吃透再写程序
3.1 Modbus RTU帧结构
Modbus RTU的帧结构非常规整,发送和接收都是这样排布的:
从站地址(1字节) + 功能码(1字节) + 数据(N字节) + CRC16(2字节, 低字节在前)其中CRC16占2个字节,在报文里是低字节在前、高字节在后。这一点特别容易搞反,搞反的结果就是变频器收到报文后校验不通过,直接丢弃,表现为“变频器毫无反应”。
帧与帧之间至少要有3.5个字符时间的间隔。Modbus协议规定这个时间是为了让设备区分两帧数据的分界。PLC程序里如果两个命令之间延时太短,变频器可能把两帧当成一帧数据,这种情况在现场调试时很常见:报文是对的、CRC也是对的,但就是偶发无响应,多半就是帧间隔不够。
3.2 VFD-M寄存器地址对照
台达VFD-M的Modbus寄存器地址,常用的是这几个:
| 寄存器地址 | 方向 | 含义 | 单位 |
|---|---|---|---|
| 2000H | 写 | 运行命令 | bit控制 |
| 2001H | 写 | 频率指令 | 0.01Hz |
| 2100H | 读 | 变频器状态 | bit状态 |
| 2101H | 读 | 输出频率 | 0.01Hz |
| 2102H | 读 | 输出电流 | 0.01A |
2000H运行命令的位定义,不同批次的产品略有差异,最常见的是:
- bit0 = 1:正转运行
- bit1 = 1:反转运行
- bit2 = 1:停止
所以在程序里我习惯写成:正转命令发送2000H=0001H,反转命令发送2000H=0002H,停止命令发送2000H=0004H。这三条命令分开处理,逻辑非常清晰。
3.3 CRC16计算方法与ST实现
前面说了,Modbus RTU的CRC有两种算法风格:一种叫“查表法”,运算速度快但需要一张256个字的表,适合在上位机或者单片机里用;另一种叫“移位法”,代码简单、占资源少,适合PLC的ST语言或功能块实现。CP1H的运算速度足够快,移位法完全够用。
CRC计算的规则是:
- 初始值取FFFFH
- 每一个字节先跟当前CRC值做异或
- 然后右移一位,如果移出的位是1,则异或A001H
- 如此循环8次,处理完所有字节后得到最终CRC值
我用ST语言写过一个通用计算功能块,CP1H的CX-Programmer支持ST,写起来很顺手:
FUNCTION_BLOCK FB_CRC16 VAR_INPUT Data : ARRAY [0..15] OF WORD; // 待计算数据,只用每个字的低字节 Len : WORD; // 字节数 END_VAR VAR_OUTPUT Result : WORD; // CRC计算结果 END_VAR VAR i : WORD; j : WORD; crc : WORD; END_VAR crc := 16#FFFF; FOR i := 0 TO Len - 1 DO crc := crc XOR (Data[i] AND 16#00FF); FOR j := 1 TO 8 DO IF (crc AND 1) = 1 THEN crc := (crc SHR 1) XOR 16#A001; ELSE crc := crc SHR 1; END_IF; END_FOR; END_FOR; Result := crc;这个功能块接收一个“以字为单位”的数组,每个元素的低字节就是报文里要发送的字节,高字节忽略。算完之后,Result的低字节是CRC低字节,Result的高字节是CRC高字节。往发送缓冲区里放的时候,记得低字节放前面。
3.4 报文实例拆解
拿一个最常用的操作举例:把频率设定为50.00Hz,从站地址是1,寄存器2001H,功能码06(写单个保持寄存器)。
50.00Hz换算成寄存器值就是5000,十六进制是1388H。那整帧报文就是:
01 06 20 01 13 88 CRClow CRChigh逐个字节解释:
- 01:从站地址
- 06:写单个保持寄存器功能码
- 20 01:寄存器地址2001H,高字节在前
- 13 88:要写入的数据,高字节在前
- CRClow CRChigh:前面6个字节的CRC校验
再举一个读的例子:读变频器的输出频率,寄存器2101H,功能码03。
发送帧是:
01 03 21 01 00 01 CRClow CRChigh其中00 01表示读取1个寄存器。变频器正常响应时,返回的帧是:
01 03 02 13 88 CRClow CRChigh解析一下:01是从站地址(回显),03是功能码(回显),02表示后面跟了2个字节的数据,13 88就是频率值5000,也就是50.00Hz。
实际调试时,我会先用电脑上的串口调试工具把这两个报文发给变频器,确认变频器能正确响应,再回头写PLC程序。这一步可以帮你把“PLC程序问题”和“接线参数问题”彻底分开。
4. CP1H自由口程序框架与梯形图实现
4.1 数据区规划
写程序前先把数据区规划好,能省掉后面大量麻烦。我的习惯是这样分:
| 地址 | 用途 |
|---|---|
| D100~D107 | 发送缓冲区,TXD直接从这里取数 |
| D200~D206 | 接收缓冲区,RXD收进来的数据放这里 |
| D300 | 轮询步号(0~3) |
| D301 | 当前步重发计数 |
| D302 | 连续通讯失败计数 |
| D500 | 变频器运行状态字 |
| D501 | 输出频率(0.01Hz) |
| D502 | 输出电流(0.01A) |
| W0.00 | 启动轮询触发位 |
| W0.01 | 发送请求标志 |
| W0.02 | 接收完成处理标志 |
| W0.03 | 通讯超时标志 |
注意一点:欧姆龙的TXD指令发送时,是把发送缓冲区里每个通道的低字节依次发出去。所以组包时,每个报文字节要放在对应的通道低字节。例如要发01 06 20 01 13 88,那就是D100的低字节=01,D101的低字节=06,D102的低字节=20,D103的低字节=01,D104的低字节=13,D105的低字节=88,D106的低字节=CRC低,D107的低字节=CRC高。
4.2 无协议通讯的串口设置
在CX-Programmer里打开“PLC设定”,找到串口设置,把通讯模式改为“无协议”。这里有两个关键项:
- 起始码和结束码都设为0000,不启用。Modbus RTU不需要起始码和结束码,帧长由字节数和间隔决定。
- 接收格式要单独设置。CP1H无协议模式支持两种接收格式,每一种可以指定固定的接收字节数。因为VFD-M的读响应是7字节(地址+功能码+字节数+2数据+2CRC),写响应是8字节(地址+功能码+2地址+2数据+2CRC),所以可以把接收格式1的字节数设为7,接收格式2的字节数设为8。
这样设置的好处是:变频器回7字节时,接收格式1的完成标志置ON;回8字节时,接收格式2的完成标志置ON。PLC侧不需要自己猜接收了多少字节。
接收完成标志对应关系,再啰嗦一遍:
- 内置RS232C口:接收格式1完成标志A3.00,接收格式2完成标志A3.01
- 扩展通信板(CP1W-CIF11):接收格式1完成标志A3.02,接收格式2完成标志A3.03
我的主方案用的是CP1W-CIF11,所以下面程序里的完成标志都按A3.02和A3.03来写。
4.3 发送环节:TXD指令与组包
TXD指令的用法是这样的:
TXD 源首通道, 控制字, 字节数- 源首通道:发送缓冲区起始地址,例如D100
- 控制字:#0100 表示从扩展通信板端口发送、从源首通道的低字节开始取数。如果用的是内置RS232C口,控制字改成#0000
- 字节数:&8 或 &7,取决于当次发送的报文长度
我习惯写一个“当前步报文组装”的子程序。比如D300=0时,组写运行命令帧;D300=1时,组写频率指令帧;D300=2时,组读状态帧;D300=3时,组读频率帧。组包的具体操作就是把每个字节MOV到对应通道的低字节,再调用CRC功能块算出CRC填入末尾两个通道。
以D300=1(写频率50.00Hz)为例,梯形图里做这几步:
- MOV &1 D100 → 从站地址
- MOV &6 D101 → 功能码06
- MOV &16#20 D102 → 寄存器地址高字节
- MOV &1 D103 → 寄存器地址低字节
- MOV &16#13 D104 → 数据高字节
- MOV &16#88 D105 → 数据低字节
- 调用FB_CRC16,输入D100、长度6,得到结果存入D107(高字节)和D106(低字节)
- 置W0.01为ON,申请发送
发送时,W0.01上升沿触发TXD,同时启动一个500ms的定时器作为超时判断。发送完成后要等待接收,不要在这个时间段里再次触发TXD。
4.4 接收环节:RXD指令与帧解析
RXD指令的用法和TXD对称:
RXD 接收首通道, 控制字, 字节数接收完成标志一旦ON,就执行RXD把数据读走。以接收格式1(7字节)为例,如果A3.02是ON,就执行:
RXD D200, #0100, &7数据读进D200~D206之后,开始解帧:
- 先看D200低字节是否等于01(从站地址),不对就丢弃。
- 再看D201低字节是否等于03(读响应功能码),不对就丢弃。
- 然后对D200~D206这7个字节重新算一次CRC,跟D205低字节(CRC低)和D206低字节(CRC高)比较,不一致说明数据在传输中损坏,丢弃。
- 全部通过后,把D203低字节(数据高)和D204低字节(数据低)组合成一个16位数据,存入D501。
梯形图里做这个组合,我会用逻辑运算实现:
- 先把D203的低字节取出,逻辑左移8位,得到高字节部分
- 再把D204的低字节取出,作为低字节部分
- 两者相或,得到完整的16位寄存器值
如果是接收格式2(写响应8字节),A3.03为ON,执行RXD读回D200~D207。写响应的解析相对简单:只要校验从站地址、功能码和CRC,确认和发送帧一致即可,不需要提取数据。
4.5 轮询状态机的设计
整个自由口通讯程序的核心,是一个简单的轮询状态机。我习惯用D300做步号,0到3循环:
- 步0:发正转运行命令
- 步1:发频率设定命令(50.00Hz)
- 步2:读变频器状态
- 步3:读输出频率
每步的执行流程都一样:
- 判断不是忙状态(接收完成标志和超时标志都是OFF)
- 组帧,置发送请求位
- TXD发送,启动超时定时器
- 等待两个事件之一:
- 接收完成标志ON:RXD接收 → 解析 → 正确则D300+1(到4回0),清零重发计数
- 超时定时器ON:重发计数+1,未超过3次则重新发送当前步;超过3次则置通讯故障标志,D300+1(继续跑下一轮,不让整条程序卡死)
超时重发这个小设计非常重要。变频器偶尔会因为电网上电瞬间、母线电压建立等原因晚回一两拍,直接判故障会让整个设备连环跳机。给它3次重试机会,绝大多数偶发问题就自己过去了。如果连续三轮都失败,那一定是硬件或参数有问题,置故障让上位机提示,比程序自己死磕靠谱。
5. 常见问题与排查实录
5.1 变频器完全没反应
这是占比最高的问题。排查顺序我一般是这样的:
- 先确认PLC程序里的报文发出来了。拿一个USB转RS485模块接到总线上,用串口调试工具监听。如果能看到CP1H发的报文,说明TXD工作正常,接下来看变频器有没有回。如果监听不到,说明PLC侧串口配置或TXD控制字有问题。
- 确认变频器参数生效。尤其是数据格式、协议、地址,改完有没有断电重启。这一点我每次都要强调,现场很多人改完参数直接按“确认”就测通讯,协议和数据格式有时不能即时生效。
- 确认RS485接线极性。S+和S-接反是最常见的低级故障,几乎每个人都会遇到一次。
- 确认PLC侧和变频器侧波特率、停止位一致。
排查时建议做一个“最小闭环测试”:只发一条读2101H的报文(03功能码、命令最安全,不会改变变频器状态),如果变频器能正常回,说明整条链路是通的。
5.2 数据能读但控制无效
报文能收能发,读频率、读电流都有数据,但PLC发运行命令变频器就是不动。这种问题九成出在变频器的控制指令来源没切到通讯模式。
比如一台VFD-M,频率来源01-00=2、运转信号来源01-01=2,外部端子没有给使能信号,通讯命令也会被屏蔽。还有一部分机型有“外部端子控制优先”逻辑,需要把外部端子使能回路短接或者放开。
另一个隐蔽问题:2000H命令字里的停止位可能和你发的内容冲突。比如你发正转0001H,但变频器内部要求bit2停止位必须为0,如果程序里上一次停止命令还把bit2置1,那这一次的正转命令就会被覆盖。所以我的习惯是:正转、反转、停止三条命令使用独立的赋值逻辑,正转时强制写0001H,不要叠加其他位。
5.3 CRC与乱码问题
收下来的报文能看但CRC校验不过,通常有三种原因:
- 组帧时字节序错了:寄存器地址和数据都是高字节在前,写反了变频器要么不响应,要么回异常码。
- CRC高低字节放反了:Modbus要求低字节在前,放反之后变频器校验永远失败。
- 接收长度不对:RXD的接收字节数和实际响应长度不一致,会把后面的字节截掉或粘帧。
还有一个容易忽略的点:CP1H的TXD发送的是通道低字节,如果你组帧时把字节放到了高字节,TXD仍然会把低字节发出去,导致报文完全不是你想象的内容。组完帧之后,用串口助手下线看一下实际发出的字节序列,比在梯形图里反复核对高效得多。
5.4 现场抗干扰问题
变频器一启动,通讯就断;变频器一停,通讯就恢复。这是很典型的RS485干扰现场。对应措施:
- 通讯线改成屏蔽双绞线,屏蔽层单端接地
- 通讯线远离变频器输出线和动力电缆,不要并行走线
- 两台设备距离超过20米时,在两端接上120欧姆终端电阻
- 把波特率从19200降到9600,有时候就能稳住
- 如果有偏置电阻设置,在无数据时让总线保持一个确定电平,可以避免空闲时段收到杂波
我在一个现场遇到过必须把波特率降到4800才稳定的情况,原因是走线跟变频器输出线困在同一个线槽里。最后重新拉了一根屏蔽线,9600就恢复正常了。布线影响比协议还大,别忽视。
5.5 调试工具与调试顺序
调试这套自由口通讯,我强烈建议按这个顺序来,能省一半以上的时间:
- 先用电脑串口调试工具(USB转RS485)直连变频器。直接把读频率、写频率、正转、停止这几条报文发给变频器,确认变频器本身是好的、寄存器地址是正确的、参数是生效的。
- 再用CP1H自发自收。把TXD的发送目标先指向一个空口或者把回显接回自己的接收端,确认TXD和RXD指令、控制字、接收格式配置都能正常工作。
- 最后接上变频器跑联合调试。到了这一步,如果再有问题,多半就是接线极性、干扰或者参数不一致了。
整个调试过程中,我习惯在手边放一张“报文速查卡”,上面写好几条常用报文:读频率、读电流、正转、反转、停止、写50Hz。逐条验证,效率极高。你用不着把Modbus协议背得滚瓜烂熟,但一定要会拼一条正确的报文,并且知道CRC算出来应该放在哪个位置。
这套自由口通讯方案跑起来之后,其实稳定性比很多人想象的要好。原因也简单:报文是自己组的、CRC是自己算的、时序是自己控的,每一步都看得见摸得着。真出现一个异常,程序里D302的失败计数会明确告诉你是哪一步出了问题,不用拿万用表去猜。
我个人体会最深的一点是:CP1H和VFD-M通讯这件事,最大的门槛不在PLC指令,也不在变频器参数,而在你是否愿意把报文的每个字节、每个字节序、每个校验位都理解到位。把这套自由口的思路吃透之后,你会发现,以后接温控器、接仪表、接伺服驱动器,全都是一样的套路,换张寄存器表就能复用。