简介:本资源是一套面向工业自动化工程师与倍福(Beckhoff)PLC初学者的RS232/RS485自由口通信实战案例,聚焦Twincat环境下串口协议自主解析与硬件交互,解决现场设备(如仪表、传感器、旧式控制器)无标准协议支持时的定制化通信需求。压缩包共4个文件(34KB),含2个TwinCAT工程文件(.pro)用于主站逻辑与通信配置、1个封装好的串口通信库(.lib)提供底层驱动与帧处理功能、1个XML设备描述文件(.xml)定义EL6021串口模块参数及9600bps/E81格式配置,结构精简、即开即用。已有2065人学习下载,内容覆盖BCC校验实现、COM端口初始化、ASCII/HEX混合帧构造与超时重发机制等关键细节,可直接导入Twincat 3(4024.11及以上版本)运行调试,是理解倍福软PLC串口编程逻辑与工程落地的典型参考范例。
1. 项目概述:为什么需要关注倍福PLC的自由口通信?
在工业自动化现场,你肯定遇到过这样的场景:一台崭新的倍福(Beckhoff)PLC需要与一台老旧的设备(比如一台特定品牌的变频器、一台非标仪表、或者一台没有标准总线接口的机床)进行数据交换。这台老设备只提供了一个朴素的RS232或RS485串口,通信协议也是厂家自定义的“自由口”格式。这时候,你没法简单地插上一根EtherCAT网线了事,深入理解并实现PLC的串行自由口通信,就成了打通数据孤岛、让新旧设备协同工作的关键技能。
倍福的TwinCAT平台以其强大的软PLC和实时以太网技术闻名,但其对传统串行通信的支持同样完善且灵活。所谓“自由口通信”(Free Serial Port Communication),就是指PLC不依赖标准的Modbus RTU、Profibus等预置协议栈,而是直接通过串口发送和接收原始的字节流,由用户程序来解析和组帧。这赋予了工程师最大的自由度,可以应对任何私有协议,但同时也对编程的严谨性提出了更高要求。RS232适合点对点、短距离通信,而RS485则支持一主多从、更长距离的网络,两者在电气特性上不同,但在TwinCAT的软件配置层面,其核心逻辑是相通的。
本文将从一个实际案例出发,拆解在倍福TwinCAT 3环境下,如何从硬件接线、软件配置、到程序编写,一步步实现稳定可靠的RS232/485自由口通信。无论你是刚刚接触倍福的工程师,还是正在为某个特定设备协议而头疼,这篇基于实战经验的总结都将提供清晰的路径和必须避开的“坑”。
2. 通信方案整体设计与硬件连接要点
实现自由口通信,首先要在头脑中构建清晰的通信模型。我们的目标是在TwinCAT PLC运行时中,创建一个能够自主管理串口收发、处理数据帧的通信任务。
2.1 核心组件选择与架构思路
在倍福的体系中,串口通信通常不直接由标准的PLC任务处理,因为收发数据的时机是异步的、由硬件中断驱动的。最稳妥的方案是使用TwinCAT Serial Communication功能库。这个库提供了FB_SerialCom等功能块,封装了底层串口驱动、缓冲区管理等复杂操作,我们只需关注何时发送、如何解析接收到的数据。
整个架构可以这样设计:
- 硬件层:PLC的串口模块(如EL6001)通过DB9或端子块与外部设备连接。
- 驱动层:在TwinCAT System Manager中配置串口参数(波特率、数据位等),并激活Serial Communication驱动。
- 逻辑层:在PLC项目中,调用
FB_SerialCom功能块。我们需要编写两个主要循环:- 发送循环:根据内部逻辑或外部触发,将组装好的数据帧(字节数组)提交给
FB_SerialCom发送。 - 接收/解析循环:在
FB_SerialCom的接收事件或周期性地检查接收缓冲区,将原始的字节流按照预定协议解析成有意义的变量(如温度值、状态字)。
- 发送循环:根据内部逻辑或外部触发,将组装好的数据帧(字节数组)提交给
注意:对于RS485网络,由于是半双工(同一时刻只能发送或接收),必须严格管理收发状态的切换。
FB_SerialCom通常通过RTS(Request To Send)信号自动控制RS485收发器的方向,但这需要硬件接线和软件配置正确配合。
2.2 硬件接线实战与避坑指南
正确的硬件连接是通信的物理基础,这里面的细节直接决定通信能否建立。
对于RS232(点对点):接线相对简单,核心是“交叉互联”。PLC串口(DTE设备)的TxD线应连接外部设备(DCE设备)的RxD线,PLC的RxD连接外部设备的TxD。地线(GND)必须连接以确保共地。如果使用倍福的EL6001等模块,其引脚定义是标准的。
- 实操要点:务必使用万用表确认引脚,或者查阅EL6001手册。一个常见的错误是使用了直连线而非交叉线,导致双方都能发送但都无法接收。
对于RS485(多点网络):接线和配置更为关键,主要目标是保证信号完整性。
- 差分线对:严格连接A线(通常对应D-或B)和B线(通常对应D+或A)。在整个网络的总线两端,必须并联终端电阻(通常为120欧姆),以消除信号反射。很多通信不稳定的问题都源于终端电阻缺失或阻值不匹配。
- 接地与屏蔽:RS485网络应使用单点接地,避免地环路电流引入干扰。屏蔽双绞线的屏蔽层应在控制器端单点接地。
- RTS方向控制:这是关键!RS485是半双工。
FB_SerialCom库通过RTS引脚输出高低电平来控制外接RS485收发器芯片的发送使能端。- 接线:将串口模块的RTS引脚连接到RS485收发器芯片的DE(发送使能)引脚,有时还需要连接/RE(接收使能,通常低有效)。
- 配置:在
FB_SerialCom功能块中,需要正确设置RTS相关的参数,如RTSOnForSend,确保在发送数据前自动拉高RTS,发送完成后拉低,切换回接收状态。
避坑心得:我曾在一个项目中,RS485通信间歇性出现乱码。排查良久,最后发现是总线末端的终端电阻虚焊。用示波器观察A、B线间的波形,发现信号边沿有明显的振铃(过冲)。补焊电阻后波形变得干净,通信立刻稳定。因此,对于RS485网络,示波器是比万用表更强大的诊断工具。
3. TwinCAT软件配置与核心功能块详解
硬件准备就绪后,需要在TwinCAT环境中进行软件层面的搭建。
3.1 System Manager中的串口配置
首先,在TwinCAT System Manager中,找到你的串口硬件(例如EL6001)。
- 右键选择“Change to Free Run Mode”(如果可用),这能让串口独立于PLC任务周期运行,响应更及时。
- 在“Serial”选项卡或设备参数中,配置通信参数,这些参数必须与外部设备完全一致:
Baudrate:波特率,如9600, 19200, 115200等。Data Bits:数据位,通常为8。Parity:奇偶校验位,通常为None(无校验)。Stop Bits:停止位,通常为1。Flow Control:流控制,自由口通信通常设为“None”。
- 激活配置并下载到运行时。此时,Windows设备管理器中应能正确识别该串口(如COM3)。
3.2 PLC项目中功能块的调用与参数解析
在Visual Studio的TwinCAT PLC项目中,需要引用Tc2_SerialCom库。核心是FB_SerialCom功能块。
FUNCTION_BLOCK FB_SerialCom VAR_INPUT sPortName: STRING := 'COM3'; // 串口名称,与System Manager中一致 bAudRate: UDINT := 9600; // 波特率 bDataBits: BYTE := 8; // 数据位 eParity: E_PARITY := eNone; // 校验位 eStopBits: E_STOPBITS := eOne; // 停止位 bOpen: BOOL; // 上升沿触发打开串口 bClose: BOOL; // 上升沿触发关闭串口 pSendBuffer: POINTER TO BYTE; // 指向发送数据缓冲区的指针 cbSendBuffer: UDINT; // 发送数据的字节长度 bSend: BOOL; // 上升沿触发发送 END_VAR VAR_OUTPUT bOpened: BOOL; // 串口已打开 bBusy: BOOL; // 串口忙状态 bError: BOOL; // 错误标志 nErrId: UDINT; // 错误代码 pReceiveBuffer: POINTER TO BYTE; // 指向接收缓冲区的指针 cbReceivedBytes: UDINT; // 当前接收到的字节数 END_VAR关键参数设置与使用流程:
- 初始化与打开:在PLC的初始化阶段(如
PLC_PRG的第一次扫描),给bOpen输入一个上升沿,功能块会尝试打开指定的COM口。成功后bOpened变为TRUE。 - 发送数据:将待发送的数据填充到一个字节数组(如
arrSend: ARRAY[0..255] OF BYTE)中。将pSendBuffer指向该数组的首地址(使用ADR(arrSend)),设置cbSendBuffer为实际长度,然后给bSend一个上升沿脉冲。 - 接收数据:
FB_SerialCom内部有环形接收缓冲区。我们需要周期性地(例如在一个10ms的循环任务中)检查cbReceivedBytes。当它大于0时,说明有数据到达。此时,可以通过pReceiveBuffer指针访问缓冲区数据,并将其拷贝到我们自定义的解析数组中进行处理。 - 关闭与错误处理:在程序退出或需要时,给
bClose上升沿关闭串口。始终监控bError和nErrId,它们能指示出“端口不存在”、“参数错误”、“缓冲区溢出”等关键问题。
实操心得:
pReceiveBuffer指向的是功能块内部的缓冲区,其内容可能在下一次接收时被覆盖。因此,一旦检测到有新数据,必须立即将其拷贝到程序自定义的全局数组变量中,然后再进行解析。切忌直接基于指针进行复杂的、耗时的解析操作,否则数据可能丢失。
4. 通信协议解析与PLC程序实现
自由口通信的核心难点和魅力在于协议处理。这里我们以一个模拟的“读取温度值”协议为例。
4.1 定义通信协议帧格式
假设外部仪表采用如下简单协议:
- 主机(PLC)查询帧(4字节):
[帧头0xAA] [设备地址0x01] [命令字0x03] [校验和]- 校验和 = (0xAA + 0x01 + 0x03) & 0xFF = 0xAE
- 从机(仪表)应答帧(6字节):
[帧头0xBB] [设备地址0x01] [命令字0x03] [数据高字节] [数据低字节] [校验和]- 数据为16位有符号整数,表示温度(单位0.1℃)。
- 校验和为前5字节的累加和取低8位。
4.2 发送与接收的PLC程序编写
在TwinCAT PLC中,我们通常使用结构化文本(ST)语言。
PROGRAM MAIN VAR fbSerial: FB_SerialCom; // 串口功能块实例 bInitOpen: BOOL := TRUE; // 初始化打开标志 arrTxBuffer: ARRAY[0..63] OF BYTE; // 发送缓冲区 arrRxBuffer: ARRAY[0..255] OF BYTE; // 自定义接收缓冲区 nRxIndex: UDINT := 0; // 自定义缓冲区索引 bSendCommand: BOOL; // 发送触发 tSendInterval: TON; // 发送间隔定时器,例如每秒发一次 nTempValue: INT; // 解析出的温度值 bNewData: BOOL; // 新数据到达标志 // 协议解析状态机变量 eParseState: (IDLE, WAIT_FOR_HEADER, WAIT_FOR_ADDR, WAIT_FOR_CMD, WAIT_FOR_DATA_H, WAIT_FOR_DATA_L, WAIT_FOR_CHECKSUM); nExpectedLength: UDINT; nCalcChecksum: BYTE; nReceivedChecksum: BYTE; END_VAR主循环逻辑:
// 1. 初始化打开串口(仅一次) IF bInitOpen THEN fbSerial(sPortName:='COM3', bAudRate:=9600, bOpen:=TRUE); bInitOpen := FALSE; END_IF // 2. 周期性发送查询命令 tSendInterval(IN:=NOT tSendInterval.Q, PT:=T#1S); IF tSendInterval.Q THEN tSendInterval(IN:=FALSE); // 组装查询帧 arrTxBuffer[0] := 16#AA; arrTxBuffer[1] := 16#01; arrTxBuffer[2] := 16#03; arrTxBuffer[3] := 16#AE; // 校验和 // 触发发送 fbSerial(pSendBuffer:=ADR(arrTxBuffer), cbSendBuffer:=4, bSend:=TRUE); END_IF // 3. 检查并处理接收数据 IF fbSerial.cbReceivedBytes > 0 THEN // 立即将内部缓冲区数据拷贝到自定义数组 MEMCPY(destAddr:=ADR(arrRxBuffer[nRxIndex]), srcAddr:=fbSerial.pReceiveBuffer, n:=fbSerial.cbReceivedBytes); nRxIndex := nRxIndex + fbSerial.cbReceivedBytes; // 可以在这里重置fbSerial的接收计数器(通过特定方法或依赖其自动管理) END_IF // 4. 协议解析状态机(独立任务或周期调用) CASE eParseState OF IDLE: IF nRxIndex > 0 THEN eParseState := WAIT_FOR_HEADER; END_IF WAIT_FOR_HEADER: IF arrRxBuffer[0] = 16#BB THEN nCalcChecksum := 16#BB; eParseState := WAIT_FOR_ADDR; // 可以移动缓冲区,这里简化处理,假设每次只处理一帧 ELSE // 帧头错误,丢弃一个字节(简易处理) MEMCPY(ADR(arrRxBuffer), ADR(arrRxBuffer[1]), nRxIndex-1); nRxIndex := nRxIndex - 1; eParseState := IDLE; END_IF WAIT_FOR_ADDR: IF nRxIndex >= 2 THEN IF arrRxBuffer[1] = 16#01 THEN // 地址匹配 nCalcChecksum := nCalcChecksum + 16#01; eParseState := WAIT_FOR_CMD; ELSE // 地址不匹配,丢弃 eParseState := IDLE; nRxIndex := 0; END_IF END_IF // ... 依次等待并校验命令字、数据高字节、数据低字节 WAIT_FOR_CHECKSUM: IF nRxIndex >= 6 THEN // 完整帧已到达 nReceivedChecksum := arrRxBuffer[5]; IF nCalcChecksum = nReceivedChecksum THEN // 校验成功,提取温度数据 nTempValue := SHL(TO_INT(arrRxBuffer[3]), 8) OR arrRxBuffer[4]; bNewData := TRUE; END_IF // 无论校验成功与否,都从缓冲区移除这6个字节 MEMCPY(ADR(arrRxBuffer), ADR(arrRxBuffer[6]), nRxIndex-6); nRxIndex := nRxIndex - 6; eParseState := IDLE; END_IF END_CASE注意事项:上述状态机是一个简化示例。工业级的解析器需要更健壮,包括处理缓冲区中粘包(多帧连在一起)、断包(一帧被拆分成多次接收)、超时重发等复杂情况。通常需要维护一个循环队列作为接收缓冲区,状态机根据已接收的字节数推进。
5. 调试技巧与常见问题排查实录
即使逻辑正确,在实际调试中也会遇到各种问题。以下是我总结的排查清单。
5.1 通信完全无响应的排查步骤
- 检查物理层:
- 线缆:用万用表通断档检查TxD/RxD/A/B线是否导通。对于RS485,测量A-B间在空闲时的电压差(应有几十毫伏到几伏的稳定差值,方向取决于上下拉电阻)。
- 电源与接地:确保所有设备共地。检查RS485收发器芯片供电是否正常。
- 终端电阻:用万用表测量RS485总线两端的A-B间电阻,应为60欧姆左右(两个120欧姆并联)。
- 检查软件配置:
- 端口号:确认TwinCAT中配置的COM口号与Windows设备管理器中的一致。有时USB转串口适配器的COM号会变动。
- 参数匹配:波特率、数据位、停止位、校验位必须与从设备百分百一致。一个常见的错误是设备设置为“115200, 8, N, 1”,而PLC配置成了“9600, 8, N, 1”。
- 权限问题:以管理员身份运行Visual Studio/TwinCAT开发环境。有时普通用户权限无法访问串口。
- 使用第三方工具辅助:
- 使用串口调试助手(如AccessPort、友善串口助手)替代PLC,先与从设备通信。如果能通,证明硬件和从设备没问题,问题在PLC程序。
- 用串口调试助手模拟从设备,接收PLC发送的数据。查看PLC发出的原始字节是否正确。这能隔离是发送问题还是接收/解析问题。
5.2 通信不稳定、数据错误的排查
- 电气干扰:
- 这是RS485长距离通信的头号杀手。确保使用屏蔽双绞线,屏蔽层单点接地。远离变频器、大功率电机等强干扰源。
- 在示波器上观察A-B信号波形。好的波形应干净、陡峭。如果看到毛刺、振铃或幅值衰减,说明存在干扰或阻抗不匹配,需要检查终端电阻、线缆质量或增加共模扼流圈。
- 波特率容错:
- 双方晶振误差累积可能导致波特率偏差。在高速率(如115200)长距离时更明显。尝试适当降低波特率。
- 程序逻辑缺陷:
- 缓冲区溢出:检查
FB_SerialCom的接收缓冲区大小是否足够。如果数据接收过快,而PLC程序解析太慢,未及时取走数据,会导致新数据覆盖旧数据。可以增大缓冲区,或提高解析任务的执行频率。 - 数据粘包处理不当:如果从设备响应很快,两帧数据可能在同一接收事件中被读到。你的解析状态机必须能处理这种情况,即解析完一帧后,缓冲区里可能还有剩余数据,状态机应继续解析,而不是重置。
- 发送与接收切换时序(RS485):确保
RTSOnForSend参数设置正确。可以用示波器同时监控RTS信号和A-B差分信号,确认RTS在发送数据前变高,并在最后一个字节发送完成后延迟一段时间再变低(这个延迟在功能块参数中可设置,通常为几个位时间)。切换太快,可能丢失最后一个字节;切换太慢,会阻塞对方回应的开始部分。
- 缓冲区溢出:检查
5.3 TwinCAT特有的问题
- 实时性影响:如果PLC任务周期设置过长(如100ms),而串口数据速率很高,可能导致接收缓冲区溢出。考虑将串口通信相关的功能块调用放在一个周期更短的任务中(如5ms或10ms)。
FB_SerialCom版本:不同版本的TwinCAT 3,其Tc2_SerialCom库可能有细微差别。如果从老项目移植代码到新环境,最好重新添加库引用并检查功能块引脚。- ADS通信干扰:在极少数情况下,剧烈的网络ADS通信(如大量变量监控)可能影响PLC任务的实时性,间接导致串口处理不及时。调试时可以先暂停HMI的变量监控试试。
最后,保持耐心,遵循“从硬件到软件,从底层到上层”的排查顺序,利用好示波器和串口调试助手这两个利器,大部分自由口通信问题都能被定位和解决。记住,稳定的工业通信,往往建立在无数细节的正确处理之上。
本文还有配套的精品资源,点击获取