
在实际工业自动化项目中PLC与外围设备如变频器、伺服驱动器、仪表、扫码枪等的串行通讯是基础且关键的环节。三菱FX1N系列PLC作为一款经典的小型机其内置的RS-485/RS-422接口支持“无协议通讯”即自由口通讯允许开发者直接通过梯形图程序控制串口的收发时序和数据格式实现与任何支持串行通讯协议的设备对接。这种方式的优点是灵活、成本低但缺点也显而易见开发者需要从零开始构建通讯帧、处理字节收发、计算校验码如CRC并处理复杂的超时、重发和异常逻辑。在如今各种成熟的通讯库、驱动和协议转换器唾手可得的背景下手动实现这些底层细节显得“原始”然而理解这个过程对于深入掌握工业通讯原理、排查底层通讯故障具有不可替代的价值。本文将围绕三菱FX1N的自由口通讯带你从零搭建一个完整的通讯链路。我们将以读取一个模拟Modbus RTU协议的设备数据为例详细讲解如何配置串口参数、编写发送和接收程序、手动实现CRC-16校验码的计算并最终验证数据。文章不仅提供可复现的梯形图代码更会深入解释每一步背后的设计逻辑和常见陷阱帮助你在面对没有现成驱动或协议的特殊设备时能够从容应对。1. 理解FX1N自由口通讯的核心机制在开始编程前必须理解FX1N自由口通讯官方称为“无协议通讯”的工作原理。它并非一个封装好的函数而是一套由特殊辅助继电器M和数据寄存器D控制的底层串口操作机制。1.1 串口通讯的基础流程自由口通讯的本质是PLC的CPU直接操作其串行通讯接口芯片。整个过程可以简化为初始化设置通讯参数波特率、数据位、停止位、校验位。发送将待发送的数据字节写入发送缓冲区然后触发发送指令。接收使能接收功能串口芯片将接收到的字节存入接收缓冲区并通过标志位通知CPU。数据处理从接收缓冲区读取字节按照协议解析数据并验证校验码。错误处理监控超时、校验错误、帧错误等并决定重发或报错。FX1N通过一系列特殊软元件来映射这个过程。例如M8122是发送请求标志M8123是接收完成标志D8120是通讯格式寄存器。1.2 关键软元件详解以下软元件是自由口通讯编程的基石必须牢记其功能软元件地址名称与功能读写属性说明D8120通讯格式寄存器写用于设置波特率、数据长度、停止位、奇偶校验。这是一个16位寄存器每一位代表一个参数。M8122发送请求标志写当程序将此位置为ON时PLC开始发送D8122指定起始地址的数据。发送完成后PLC自动将其复位为OFF。M8123接收完成标志读当接收缓冲区收到完整一帧数据或达到指定条件后此标志被PLC自动置为ON。程序读取数据后需手动将其复位为OFF以准备下一次接收。D8122发送数据起始地址指定写存放要发送的第一个数据所在的寄存器地址如D100。发送的数据长度需要另存。D8123接收数据计数器读存放当前接收缓冲区中已接收到的字节数。D8124接收数据起始地址指定读/写指定接收到的数据存放的起始寄存器地址。通常与D8123配合使用来读取数据。M81618位/16位处理模式写ON时数据按8位字节处理D寄存器的高8位和低8位独立作为两个字节。OFF时按16位字处理。自由口通讯通常设为ON。注意不同型号或固件版本的FX1N其特殊软元件地址可能略有差异。编程前务必核对硬件手册。本文以常见型号为例。1.3 为何CRC校验需要“自己写”CRC循环冗余校验是一种常用的错误检测码用于验证数据在传输过程中是否出错。Modbus RTU、Modbus ASCII等标准协议都使用CRC-16。FX1N的指令集中没有内置的CRC计算指令因此开发者必须用梯形图逻辑模拟CRC算法的计算过程。这通常涉及移位、异或等位运算在梯形图中实现需要一定的技巧这也是自由口通讯“原始”和具有挑战性的体现。2. 环境准备与通讯参数配置在编写逻辑之前需要搭建好硬件连接并确定通讯参数。2.1 硬件连接与软件准备PLC三菱FX1N系列PLC需带RS-485/RS-422通讯口型号如FX1N-40MR-ES/UL。编程软件三菱GX Works2 或 GX Developer。本文示例使用GX Works2。通讯线根据设备接口可能是RS-485总线如FX-485ADP模块连接或RS-422。确保接线正确如RS-485的DA、DB、SG。目标设备一个支持Modbus RTU协议的从站设备如温控器、变频器。假设其站号为1波特率96008数据位无校验1停止位。电脑用于编程和监控。2.2 设置通讯格式寄存器 D8120D8120的值决定了串口的工作方式。其位定义如下常见设置位功能设定值本例说明b0数据长度0 (7位) /1 (8位)Modbus RTU通常为8位。b1 b2 b3波特率011 (9600)000300, 001600, 0101200, 0112400, 1004800,1019600, 11019200, 11138400b4 b5停止位00 (1位)/ 01 (1位)/ 10 (2位)b6 b7校验位00 (无)00无, 01奇校验, 11偶校验b8起始符0 (无)可设置帧起始字符。b9终止符0 (无)可设置帧结束字符。b10 b11 b12协议000 (无协议)必须设为无协议模式。.........其他位通常保持默认0。计算D8120的值根据上表b01, b3b2b1101, b5b400, b7b600其余为0。将其转换为16进制或十进制。二进制0000 0000 1000 0111(从b15到b0)十六进制0x0087十进制135因此在程序初始化阶段我们需要向D8120写入K135。2.3 初始化梯形图程序在GX Works2中创建一个新的梯形图程序。首先编写初始化逻辑通常放在一个始终执行的回路中如M8002上电脉冲。| M8002 |[MOV K135 D8120]| // 上电时设置通讯格式9600,8,N,1 |-----------|----------------| | |[SET M8161] | // 设置为8位数据处理模式 | |[RST M8122] | // 复位发送请求标志 | |[RST M8123] | // 复位接收完成标志这段程序在PLC上电的第一个扫描周期执行一次完成了通讯端口的基础配置。3. 构建Modbus RTU请求帧与手动CRC计算假设我们要读取从站地址为1的设备的保持寄存器40001对应Modbus寄存器地址0x0000的值读取1个寄存器。3.1 Modbus RTU请求帧结构一个标准的Modbus RTU读取保持寄存器功能码03的请求帧如下字段从站地址功能码起始地址高字节起始地址低字节寄存器数量高字节寄存器数量低字节CRC低字节CRC高字节值十六进制0x010x030x000x000x000x01CRC_LCRC_HCRC值需要根据前面6个字节01 03 00 00 00 01计算得出。3.2 在梯形图中实现CRC-16/Modbus算法CRC-16/Modbus算法的多项式是0xA001即0x8005的反转。在梯形图中实现通常采用查表法或循环计算法。这里介绍一种清晰易懂的循环计算法虽然效率不是最高但易于理解和调试。算法核心是将一个16位的CRC寄存器初始化为0xFFFF然后与数据帧中的每个字节进行异或并对结果的每一位进行判断和移位、异或操作。我们需要用一系列数据寄存器来存储中间变量。假设分配如下D100~D105存放待发送的6个字节数据01, 03, 00, 00, 00, 01。D110CRC计算结果低字节。D111CRC计算结果高字节。D120循环计数器。D130临时CRC寄存器16位。D131临时字节数据8位。以下是计算CRC的子程序或一段逻辑// 步骤1准备数据和初始化CRC |[MOV H0001 D100]| // 从站地址 1 |[MOV H0003 D101]| // 功能码 03 |[MOV H0000 D102]| // 起始地址高字节 00 |[MOV H0000 D103]| // 起始地址低字节 00 |[MOV H0000 D104]| // 寄存器数量高字节 00 |[MOV H0001 D105]| // 寄存器数量低字节 01 |[MOV HFFFF D130]| // CRC寄存器初始化为0xFFFF |[MOV K0 D120] | // 数据字节索引清零 // 步骤2循环处理每个数据字节 (D100~D105) | M0 |[ D120 K5] | // M0导通表示还有字节要处理 |----------------|-------------| | M0 |[MOV D120Z D131]| // 将索引转换为地址偏移取数据字节到D131 (如D100Z) | |[INC D120] | // 索引加1为下次循环准备 | |[XOR D130 D131 D130]| // CRC寄存器与数据字节异或 // 步骤3对CRC寄存器的每一位进行处理循环8次 | |[FOR K8] | // 循环8次处理一个字节的8位 | |[MOV D130 D132]| // 复制CRC到临时寄存器D132 | |[AND D132 K1 D133]| // 取CRC的最低位到D133 | |[SHR D130 K1 ]| // CRC寄存器右移1位 | |[CMP K1 D133 ]| // 如果移出的那一位是1 | M1 |[XOR D130 HA001 D130]| // 则CRC与多项式0xA001异或 | |[NEXT] | // 结束内层8次循环 // 步骤4判断是否所有数据字节处理完毕 | M0 |[JMP to 步骤2的循环开始]| // 实际用触点线圈实现循环此处示意 // 步骤5循环结束交换CRC高低字节Modbus RTU要求 | !M0 |[MOV D130 D134]| // 将最终CRC暂存 | |[AND D134 HFF00 D135]| // 取高字节 | |[SHR D135 K8 D111]| // 右移8位得到CRC高字节存入D111 | |[AND D134 H00FF D110]| // 取低字节得到CRC低字节存入D110注意上述梯形图是算法逻辑的示意。在实际编程中循环需要用辅助继电器和计数器巧妙构造因为标准梯形图没有直接的FOR循环指令。通常的做法是用一个字节计数器0-5和一个位计数器0-7配合上升沿脉冲逐步执行。这是一个编程难点需要仔细设计。3.3 组装完整的发送帧计算得到CRC值假设为0x840A后我们需要将8个字节6个数据字节2个CRC字节放入连续的发送数据区。由于设置了M8161ON每个D寄存器只能存放一个字节。// D100~D105已在前面赋值 |[MOV D110 D106]| // CRC低字节放入发送缓冲区第7字节 |[MOV D111 D107]| // CRC高字节放入发送缓冲区第8字节现在D100到D107这8个寄存器存放了完整的请求帧01 03 00 00 00 01 84 0A。4. 发送请求与接收响应的程序实现有了完整的发送数据接下来需要触发发送并等待接收。4.1 发送数据发送的关键是设置发送起始地址和发送数据长度然后触发M8122。// 假设用一个按钮X0触发一次读取操作 | X0 |[MOV K100 D8122]| // 告诉PLC发送数据从D100开始 | |[MOV K8 D8124] | // 告诉PLC发送数据的字节长度为8 (D100~D107) | |[SET M8122] | // 置位发送请求标志PLC开始发送当M8122被置位后PLC会自动将D100开始的8个字节通过串口发出。发送完成后M8122会自动复位。程序里一般不需要手动复位它。4.2 接收数据与超时控制接收是异步的。我们需要使能接收并等待接收完成标志M8123置位同时要防范超时。首先需要设置接收数据的存放地址和条件。自由口通讯通常一收到数据就会存入缓冲区并置位M8123。我们需要在发送完成后开始监视接收。// 发送完成后启动接收超时计时器 | M8122 | | // 发送请求标志发送期间为ON |-----|/|--------|[RST M100] | // 发送结束时M8122下降沿复位一个接收超时标志 | |[OUT T0 K100] | // 启动一个100ms的定时器T0作为接收超时 | T0 |[SET M100] | // 如果100ms内没收到响应超时标志M100置位 // 接收处理 | M8123 | | // 接收完成标志为ON |-----| |--------|[MOV D8123 D200]| // 将接收到的字节数存入D200 | |[MOV K300 D8124]| // 假设接收数据存放到D300开始的地方 | |[CALL P0] | // 调用数据解析子程序 | |[RST M8123] | // 必须手动复位接收完成标志 | |[RST T0] | // 收到数据清除超时定时器 // 超时处理 | M100 |[SET M101] | // 超时发生置位错误标志M101 | |[RST M8123] | // 也复位接收标志清理状态关键点M8123必须由程序在读取数据后手动复位否则无法触发下一次接收。超时处理是工业通讯鲁棒性的关键必须要有。4.3 解析响应帧与校验CRC假设设备正常响应我们会收到一个响应帧。对于读寄存器响应帧格式为[地址][功能码][字节数][数据高][数据低][CRC低][CRC高]。在子程序P0中我们需要检查接收字节数D200是否正确例如应为7个字节。将接收到的数据D300开始取出重新计算CRC与接收帧中的CRC最后两个字节进行比较。如果CRC校验通过则解析数据部分D303,D304得到寄存器值。将解析出的值存放到指定的数据寄存器中如D500。CRC校验的计算过程与发送前计算CRC完全相同只是计算对象是响应帧中除最后两个CRC字节外的所有字节。// 子程序P0解析响应 // 1. 检查帧长度 |[CMP K7 D200] | // 比较接收字节数是否为7 | M10 |[RET] | // 如果不等直接返回M10是CMP指令的不等输出 // 2. 计算接收数据的CRC (计算D300~D304共5个字节) // ... (此处省略与之前类似的CRC计算逻辑结果存于D140, D141) // 假设计算得到的CRC存放在 D140(低), D141(高) // 3. 与接收到的CRC比较 (接收到的CRC在D305(低), D306(高)) |[CMP D140 D305] | // 比较低字节 | M11 |[RET] | // 不等则返回 |[CMP D141 D306] | // 比较高字节 | M12 |[RET] | // 不等则返回 // 4. CRC校验通过解析数据 |[MOV D303 D501] | // 数据高字节 |[SHL D501 K8] | // 左移8位 |[MOV D304 D502] | // 数据低字节 |[OR D501 D502 D500] | // 合并高8位和低8位得到16位寄存器值存入D500 // 5. 置位成功标志 |[SET M102] | // 读取成功标志5. 程序整合、运行验证与常见问题排查将以上所有逻辑段整合到一个完整的梯形图程序中并合理组织程序结构如使用主程序、初始化子程序、发送子程序、CRC计算子程序、接收解析子程序。5.1 完整程序流程与调试下载程序将编写好的程序下载到FX1N PLC。连接设备确保PLC与目标设备如变频器的RS-485接线正确波特率等参数一致。触发通讯强制或触发启动通讯的触点如上述的X0。监控数据使用GX Works2的“在线数据监控”功能观察关键软元件D100-D107查看发送的原始字节是否正确。M8122观察发送触发和自动复位过程。D200查看实际接收的字节数。D300-D306查看接收的原始字节。D500查看最终解析出的寄存器值。M101,M102查看超时或成功标志。5.2 常见问题、现象与排查路径自由口通讯调试中绝大部分问题都出在硬件连接、参数配置和程序逻辑细节上。问题现象可能原因排查步骤与解决方案发送后无任何响应超时标志置位1. 硬件接线错误或松动。2. 波特率、数据位等通讯格式不一致。3. 目标设备站号错误。4. PLC未切换到“RUN”模式。1. 用万用表检查RS-485线路通断确认DA、DB、SG线序。2. 双重检查PLC的D8120值与设备设定值。3. 核对发送帧中的从站地址字节D100。4. 确认PLC运行指示灯亮。能收到响应但CRC校验总是失败1. CRC计算算法错误。2. 接收数据区地址映射错误M8161设置。3. 接收到的数据本身因干扰出错。1.重点排查用PC串口工具如ModScan模拟从站捕获PLC发出的请求帧手动计算CRC进行比对。逐步调试CRC子程序。2. 确认M8161ON且读取D300等寄存器时是按字节访问。3. 检查接地增加终端电阻120Ω。接收完成标志M8123不置位1. 接收缓冲区已满或溢出。2. 接收控制参数设置问题。3. 程序未及时读取导致M8123一直为ON阻塞下次接收。1. 检查是否收到数据但程序未处理。确保每次M8123ON后都执行了读取和手动复位RST M8123。2. 查阅手册确认是否有其他特殊继电器如M8129控制接收中断。数据解析结果错误1. 响应帧结构理解错误。2. 字节顺序大端/小端处理错误。3. 数据寄存器地址换算错误Modbus地址与PLC寄存器地址混淆。1. 对照设备通讯手册确认响应帧每个字节的含义。2. 确认设备的数据格式。例如收到的数据是00 0A代表十进制10还是0A00代表25603. Modbus寄存器地址40001对应协议中的地址是0x0000。通讯不稳定时好时坏1. 线路干扰。2. 波特率过高或距离过长。3. 多个设备通讯冲突。1. 使用屏蔽双绞线屏蔽层单点接地。2. 降低波特率如从19200降至9600。3. RS-485总线两端并接120Ω终端电阻。4. 检查程序中是否有逻辑缺陷导致发送冲突。5.3 关键调试技巧分段调试先屏蔽CRC校验只验证数据收发是否正确。用已知正确的CRC值替代计算值。软件模拟在电脑上使用串口调试助手如AccessPort、ModScan32模拟主站或从站与PLC互发数据可以快速定位是PLC程序问题还是设备问题。监控原始数据务必在PLC中监控D100-D107发送和D300-D306接收的十六进制值这是最直接的证据。利用上升沿在触发发送、复位标志等关键操作时使用上升沿指令PLS或触点避免一个扫描周期内多次执行。6. 最佳实践与扩展方向虽然手动实现自由口通讯是一个很好的学习过程但在实际生产项目中应追求更高的可靠性、可维护性和开发效率。6.1 工程化改进建议模块化与子程序化将CRC计算、帧组装、发送触发、接收解析、错误处理分别封装成不同的子程序如P1~P5。主程序逻辑清晰便于调试和维护。状态机设计使用一个状态寄存器如D0来标识通讯阶段0:空闲1:发送中2:等待响应3:接收处理4:错误。通过状态转移来控制流程避免依赖复杂的互锁触点。完善的错误处理与重试不仅仅是超时还要检查响应中的异常码Modbus功能码最高位置1。建立重试机制如最多3次并在多次失败后触发高级别报警M或Y输出。数据封装与解耦将设备地址、功能码、寄存器地址、数据长度等参数存放在一组连续的参数寄存器中如D10-D15。通讯子程序读取这些参数工作。这样同一个通讯逻辑可以服务多个不同的读写请求。超时时间可配置将超时时间如T0的设定值K100放在一个数据寄存器中如D9方便根据不同设备响应速度进行调整。6.2 替代方案考量如果项目条件允许考虑以下更高效的方案使用FX3U/FX5U等新型号PLC它们通常内置了RS2、RS等指令或支持ADP模块的专用协议如变频器通讯指令大大简化了程序。使用通讯协议模块如三菱的FX-485ADP-MB模块可直接支持Modbus RTU主站协议无需编写CRC和帧处理程序。使用网关或协议转换器对于非标或特别复杂的协议可以使用第三方协议转换网关将串口协议转换为PLC更容易处理的格式如Modbus TCP、Ethernet/IP。6.3 深入学习路径掌握FX1N自由口通讯是理解工业通讯底层的一个绝佳起点。在此基础上可以进一步探索更多校验方式尝试实现LRC校验、求和校验等。更复杂的协议尝试实现完整的Modbus RTU主站包括读写线圈、读写离散输入、写单个/多个寄存器等功能。通讯效率优化研究如何使用中断如接收完成中断M8123来及时处理数据减少扫描周期延迟。连接更多设备设计轮询机制在一条RS-485总线上依次与多个从站设备通讯。通过亲手实现一遍CRC校验和完整的通讯流程你会对串行通讯的每一个字节、每一个时序有更深刻的理解。这种理解在日后使用高级指令或现成库时能让你在出现问题时有能力深入到最底层进行排查而不是停留在“通讯不上”的表面现象。这正是学习这种“原始”技术的最大价值所在。