
RS485通信调试到头来发现是参数里一个勾选项惹的祸——这种经历我遇到过不止一次。三菱FX5U本体自带的那颗RS485口做ASCII无顺序通信时看着配置项不多可从帧拼装到完成标志处理每一步都有它自己的脾气。这篇就围绕FX5U的RS485 ASCII无顺序通信把参数配置、RS2指令运行机制、ASCII帧拼装、校验和计算、接线处理以及一次完整的联调过程摊开讲适合刚上手FX5U通信、或者用过FX3U想迁移到FX5U的同行参考也适合手头正对着一台只认ASCII私有协议的第三方设备发愁的朋友。1. 先摸清FX5U内置RS485口的能力边界在动手接线和写程序之前有必要先明确这颗口的定位。FX5U的CPU单元标配RS485端口端子是SDA、SDB、RDA、RDB、SG、FG这一组支持2线制和4线制最高速率可以到115200bps。它和扩展板、扩展适配器挂出来的485口在指令层面走同一套逻辑只是通道号不同。很多人第一次接触会把它和FX3U的通信扩展板混为一谈实际编程时操作数顺序、完成标志位的分布都有差异这一点后面会专门说。1.1 无顺序通信、MC协议与MODBUS RTU的取舍FX5U的485口能干三件事选哪一件完全取决于对面那台设备。**无顺序通信无协议通信**是自由度最高的一种帧格式自己定帧头、站号、命令码、数据区、校验和、结束符全凭对方设备的协议文档说了算。代价是要自己拼帧、自己算校验、自己解析响应。遇到扫码器、称重仪表、老式温控表、自定义协议的变频器基本只能走这条路。MC协议是三菱自家的一套通信规范主要用来和上位机、触摸屏、其他三菱PLC交换软元件数据。它不适合对接第三方设备除非对方明确说自己支持MC协议。MODBUS RTU是通用工业标准FX5U提供ADPRW指令专门做MODBUS主站参数配置好之后读写从站寄存器只需要一条指令省掉大量拼帧工作。对面设备如果支持MODBUS我个人的建议是优先用它能省一大半调试时间。判断逻辑很简单对方协议文档里出现MODBUS RTU字样就直接走MODBUS出现的是自定义命令表、帧头帧尾、校验和算法说明就走无顺序通信。ASCII和二进制则是在无顺序通信内部的两种数据形态选择。1.2 ASCII与二进制数据形态差异决定了程序写法这两个概念的差别说白了就是用字符表示数字还是用数字本身表示数字。要发送数值1234二进制方式下这是两个字节0x04D2紧凑、传输量小但你在串口助手里看到的是一堆乱码。ASCII方式下则是四个字符1234对应0x31、0x32、0x33、0x34占用四个字节传输量翻倍但抓包时肉眼就能读懂整帧内容出问题时对比协议文档非常直观。FX5U在参数里选择ASCII模式后RS2指令的发送和接收都以字节为单位处理数据而PLC的软元件是16位的一个寄存器刚好装两个ASCII字符。**发送时先发寄存器的低字节再发高字节接收时先收到的字符落在低字节后收到的落在高字节。**这个顺序贯穿始终拼帧和解析时一旦记反整帧数据就会错位。ASCII模式的另一个隐性成本是数据转换。你想发一个十进制数100不能直接把K100塞进发送缓冲区得先把它拆成100三个ASCII码。同理接收到的012345也要还原成数值参与运算。这部分工作FX5U有现成指令可以用但逻辑得自己理清楚后面第4节会展开。二进制模式并非不能用只是对接第三方ASCII设备时用不上。反过来如果对面是老式三菱设备或者某些支持二进制帧的仪表二进制模式传输效率确实更高。选哪种不由喜好决定协议文档写的是ASCII你就只能按ASCII来。2. 通信参数的每一项都不是随便填的参数配置是无顺序通信里最不起眼、却最容易出问题的环节。GX Works3里那一页参数看起来就是几个下拉框但每一项填错都会导致通信完全不通而且现象往往一模一样——收不到任何数据。所以有必要把每一项的作用和常见取值讲透。2.1 GX Works3里的模块参数逐项拆解配置入口在导航窗口参数 → FX5UCPU → 模块参数 → 485通信 → 通信协议设置。这里选无顺序通信之后会展开一组通信格式参数。参数项常见取值说明数据长度7位 / 8位绝大多数设备用8位7位只在少数老设备上出现奇偶校验无 / 奇数 / 偶数必须和对侧完全一致这是最常见的通信失败原因之一停止位1位 / 2位一般用1位长距离或干扰大的场合部分设备要求2位传送速度9600115200bps与对侧一致速率越高允许的通信距离越短校验和有 / 无勾选后FX5U自动追加和校验算法必须和对侧一致结束符无 / CR / CRLF决定接收何时判定帧结束接收超时可设定超时后接收强制结束避免程序一直挂等数据长度、校验、停止位、波特率这四项是四件套任何一项不一致物理层看起来连通了数据也收不进来。调试时我习惯把这四项写在一张纸上和对方设备说明书逐项划线核对比凭记忆确认靠谱得多。校验和与结束符这两项有个非常关键的联动特性很多人栽在这里**勾选校验和之后FX5U在发送时会自动在数据末尾追加两位校验字符接收时会自动校验并剥离勾选结束符之后发送时FX5U同样会自动补上结束符。**如果你的程序里已经手动拼好了校验和和CRLF参数里又开着自动追加对方收到的帧尾部就会多出几个字符协议解析直接失败。2.2 结束符、校验和、接收超时——三组最容易踩的设置先说结束符。接收侧的判定条件有三种满足任意一种接收就结束接收字节数达到设定值、检测到设定的结束符、接收超时。对于响应长度不固定的设备把接收点数设得比最大可能长度还大然后靠结束符来判定帧尾是最稳妥的做法。比如某台仪表响应长度在18到26字节之间浮动接收点数设成64结束符设CRLF收到CRLF立即结束不会傻等到64字节。再说校验和。三菱无顺序通信内置的校验和算法是对发送数据的全部字节做累加取低8位转成两位十六进制ASCII字符。问题在于市面上设备的校验算法五花八门——有累加和取低8位的有累加和取反的有异或和的还有把站号排除在外的。**只要对方的算法和FX5U内置的不完全一致就必须把校验和设成无自己在程序里算好再拼进帧里。**我见过有人为了省事强行勾选结果收发数据都对、就是对方拒收折腾一整天。接收超时这一项容易被忽略。默认值偏保守如果对方设备响应本来就慢比如某些仪表需要200ms以上才回应超时设得太短会频繁触发接收异常结束程序里表现为时好时坏。反过来超时设得太长对方掉线时程序会长时间挂起轮询节奏被打乱。合理做法是实测对方典型响应时间超时设成它的两到三倍。还有两个不常用的选项存在确认和附加代码。前者用于特定设备的存在检测握手后者用于追加附加字符。绝大多数通用设备用不到保持无即可。2.3 什么时候该直接动SD寄存器用GX Works3参数配置的好处是直观、可存档、随程序一起下载。但有两种场合必须改用SD寄存器直接写第一种是需要在运行中动态切换通信参数。比如同一条485总线上挂了两种波特率不同的设备得靠程序分时切换。参数界面是静态的做不到这一点只能用MOV指令在初始化时往对应的SD寄存器写值。第二种是程序移植。从别的项目拷过来的程序如果对方是用SD寄存器初始化的你得跟着保持一致否则两套配置会冲突——参数界面的设定和程序写入的SD值谁生效取决于执行顺序非常容易出鬼。FX5U内置RS485的通信设置对应的系统寄存器集中在SD10680起始的一段区域分别覆盖通信协议、数据长度与校验位、传送速度、校验和与结束符控制、接收超时这几类。具体编号随固件版本可能有细微差别动手前对照一下当前机型的手册通信篇附录。写法上通常是在初始化脉冲M8002下用一组MOV指令一次性写入注意程序里写了SD之后参数界面里对应的项就会被覆盖两边不要同时设。提示如果项目里既有参数配置又有SD写入建议二选一。团队协作时更推荐统一走参数配置配置随工程文件走接手的人打开就能看到比在梯形图里翻MOV指令快得多。3. RS2指令的运行机制与完成标志处理帧拼好了、参数设对了接下来就是指令怎么用。FX5U做485无顺序通信的核心指令是RS2一条指令同时涵盖发送和接收两个动作。它的操作数看着不多但每个的含义和相互关系必须搞清楚否则程序能编译通过、跑起来却收发全乱。3.1 五个操作数的分工RS2的指令格式是RS2 (S1) (S2) (S3) (D1) (D2)。S1发送数据的起始软元件。你拼好的ASCII帧从这里开始存放。S2接收数据的存放起始软元件。对方回的数据会填到这里。S3控制数据起始软元件。S30存放发送字节数S31存放接收字节数两个都是字节单位不是寄存器个数。D1完成标志起始软元件。D10是发送完成D11是接收完成D12是异常结束。D2通信通道号。FX5U内置485口用K1扩展板用K2扩展适配器用K3。这里有个高频错误点S3的发送点数和接收点数单位是字节。发送01RD0000加校验和加CRLF一共13个字节S30就写13而不是占用的寄存器个数7。我见过有人按寄存器个数填结果只发出一半的帧对端自然没反应。另一个容易混淆的地方是D2通道号。老款机型上通道号的写法和FX5U不完全一样从FX3U迁过来的人如果不看手册直接照抄很容易把K1写成别的值指令照常执行但数据从错误的通道走现象就是程序没报错就是没数据。3.2 重复触发与标志清除的实际写法RS2是连续执行型指令执行条件保持ON的情况下一次收发完成后会再次启动。这意味着如果你用一个常开的X0去驱动它总线上会不停地重复发送同一帧对方要么被刷屏、要么直接判为通信异常。正确的触发方式有两种。最简单的是用上升沿LDP X0 RS2 D100 D500 D300 M200 K1X0每闭合一次执行一轮收发。但如果需要周期性轮询用时钟脉冲更省事LDP M8013 AND M10 RS2 D100 D500 D300 M200 K1M8013是1秒时钟上升沿触发一次配合M10作为通信使能位整个轮询节奏清晰可控。轮询周期要根据对方设备的响应能力和总线负载来定一条总线上挂的设备越多、单帧越长周期就得放得越宽。完成标志的处理同样不能马虎。M200在发送完成后置ON并保持直到下一次执行RS2或者用RST清除。如果程序里靠判断M200来触发后续逻辑那下一步动作执行完后必须把它复位否则下一轮轮询会误判。我的习惯写法是LD M200 RST M200 此处放发送完成后的处理逻辑接收完成标志M201和异常标志M202同理。异常标志M202置ON说明这一轮收发出了问题具体原因要结合通信异常代码判断常见的有超时、校验错误、帧错误几类。程序里对M202的处理不要只做报警最好加一个重试计数连续失败若干次再停机报警能过滤掉偶发的干扰导致的单次失败。3.3 接收结束条件点数与结束符谁优先接收什么时候算结束是新手最容易误判的地方。三个条件——接收点数达到设定值、检测到结束符、接收超时——任意一个满足就结束不存在优先级之分。这个机制意味着两件事。第一如果你把接收点数设成实际响应的精确字节数一旦对方某次多回了一个字节你会一直等到超时才结束程序里表现为通信周期偶尔变长。第二如果设了结束符接收点数可以放心设大实际收到结束符就结束了多出来的空间不会被填满。我一般把接收点数设成协议文档里最大响应长度的1.5倍到2倍同时确保结束符设置和对方一致。这样正常响应靠结束符判定异常情况下由超时兜底两头都不会卡死。还有一个细节接收到的数据不足设定的点数时S2起始区域后面没被填到的寄存器保持原值不变。解析响应时不能假设整个接收区都是有效数据得靠接收完成时的实际字节数有些场合需要自己统计或者结束符位置来判断有效长度。用STR指令把接收区转字符串显示时如果不做长度截断会把上一次的残留数据一起显示出来看起来像是收到了奇怪的内容其实是缓冲区没清。4. ASCII帧的拼装与校验和计算到了真正动手拼帧的环节。ASCII通信的程序量比二进制大不少核心原因是每个数值都要转成字符。FX5U提供了一组字符串和ASCII转换指令用对了能省很多事。4.1 字符串指令ASC在拼帧中的用法FX5U支持在指令里直接写字符串常量。比如要发送01RD0000最直接的写法是$MOV 01RD0000 D100执行后D100到D104就被填上了对应的ASCII码。具体分布是D100低字节0x40、高字节0x300D101低字节0x311、高字节0x52R依次类推。九个字符占用五个寄存器最后一个寄存器只有低字节有效。这里要特别注意字符串在寄存器中的存储顺序和发送顺序是对应的RS2发送时先发D100的低字节0x40再发高字节0x30正好就是0两个字符。所以$MOV写进去之后不需要再做任何字节交换直接发给RS2就行。这一点让不少人省了心因为按二进制思维很容易怀疑是不是要交换高低字节。如果帧内容需要在运行时动态生成比如站号要跟着配方变就不能用字符串常亮了。这时候可以用ASC指令把字符串软元件转成ASCII码或者干脆用MOV逐字节拼。站号是两位数的情况下用除法取商和余数分别加0x30两三条指令就能算出来比调字符串指令还快。帧头的、命令码的R和D这些固定内容用$MOV一次性写进去最省事。地址域如果固定也一并写如果地址需要变化就单独用MOV覆盖对应寄存器。4.2 累加和校验的完整计算与ASCII化假设协议要求帧为 站号(2位) 命令(2位) 地址(4位) 校验和(2位) CRLF校验和是对到地址末位这9个字节做累加、取低8位、转两位十六进制大写ASCII。第一步求字节和。FX5U有按字节求和的指令BSUM格式是BSUM (S) (D) (n)对起始软元件S开始的n个字节求和结果存D。这里n写9起始写D100BSUM D100 D110 K9结果D110里是9个字节的累加和可能超过255。第二步取低8位AND D110 HFF D111D111的低8位就是校验值高8位清零。第三步把D111拆成两个十六进制字符。方法是用除法和掩码D111除以16取商得到高4位D111和0x0F做与运算得到低4位。然后两个半字节分别转ASCII——0到9加0x3010到15加0x37。逐条写比较啰嗦我通常用一个查表法预先在D500到D515里放好0到15对应的ASCII码0x30到0x39、0x41到0x46然后用变址寄存器取值。FX5U支持软元件加变址的写法MOV K0 Z0 MOV D111 D112 AND D112 H0F D113 低4位 DIV D111 K16 D114 D114存商D115存余数 MOV D114 D116 AND D116 H0F D117 高4位 MOV D500Z0 D120 低4位查表 MOV D117 Z0 MOV D500Z0 D121 高4位查表最后把D120、D121的低字节拼进帧的校验和位置。注意校验和是高4位字符在前、低4位字符在后。注意如果对方协议里的校验和算法是累加和取反或异或和就不能用BSUM直接算。取反的话在AND取低8位之后加一条异或0xFF异或和的话得用一个循环逐字节异或程序量会大一些但逻辑同样清晰。动手前务必把协议文档里的公式抄在纸上照着写。4.3 高低字节顺序一个寄存器装两个字符这一节单独拿出来讲是因为它在拼帧和解析两个环节都会咬人。发送方向寄存器低字节先发、高字节后发。所以往D104里写校验和的两个字符时第一个字符高4位对应的大写十六进制字符应该放在低字节第二个字符放在高字节。写反了对方算出来校验不通过现象是帧内容看着完全正确就是被拒收。接收方向先收到的字节落在低字节。响应帧01进来D500的低字节是0x40高字节是0x300。如果响应长度是奇数最后一个字节只占低字节高字节保持原值解析时要有意识地只取低字节。拼接发送帧时还有一个长度奇偶的问题。整个帧13个字节占用7个寄存器最后一个寄存器D106只有低字节有效0x0A即LF高字节是无效数据。发送点数写13RS2只会发13个字节D106的高字节不会被发出去所以不用担心多余数据混进去。但如果这个寄存器之前被别的逻辑用过、高字节有残留值虽然不影响发送读程序的时候容易看花眼初始化时清一下更清爽。响应解析时同样是这个道理。假设响应18个字节占用9个寄存器第九个寄存器只有低字节是有效数据。用STR指令把D500起始的9个寄存器转成字符串会得到18个字符的字符串正好对应实际响应长度不多不少。如果响应是17个字节转出来的字符串第18位会是残留的旧数据这时候就需要按已知长度截断。5. 接线、终端电阻与现场抗干扰程序写得再漂亮线接错了照样不通。485接线的坑主要集中在制式选择和屏蔽接地这两块。5.1 2线制与4线制的接法差异FX5U的端子排上有SDA、SDB、RDA、RDB四个信号端支持4线全双工和2线半双工。无顺序通信绝大多数场合用2线制因为大部分第三方设备只支持2线。2线制的接法是把FX5U的SDA和RDA短接、SDB和RDB短接然后SDA/RDA这组接到对方的A或标为、T/RSDB/RDB这组接到对方的B或标为-、T/R-。A和B接反是最常见的问题接反了不会烧设备但通信完全不通而且不同厂家对A、B的定义偶尔还会反过来遇到完全没数据的情况先换一下这两根线往往就是它。4线制用在需要全双工的场合接线是交叉的FX5U的SDA接对方RDA、SDB接对方RDBFX5U的RDA接对方SDA、RDB接对方SDB。四根信号线之外SG必须对接这是信号参考地不接的话两端地电位差会让通信变得极不稳定表现为时通时不通、数据偶发错位。终端电阻方面2线制链路的两端各接一个110Ω电阻中间节点不接。有些设备内置了120Ω终端电阻通过拨码开关启用这时候不要再外加否则阻值并联后偏离设计值信号质量反而变差。短距离、低波特率的场合不接终端电阻一般也能跑但工业现场我建议还是按规范接上省得后期偶发故障时再回头查。5.2 屏蔽、接地与共地的处理485用屏蔽双绞线是标配。屏蔽层的处理有个原则单端接地。一般接在PLC柜的接地排或者FG端子上另一端悬空。两端都接会形成地环路反而引入干扰。走线方面通信线必须和动力线分开走至少保持20厘米以上间距实在避不开就垂直交叉。我遇到过一次偶发丢帧查了两天参数和程序都没问题最后发现通信线和某台设备的输出电缆在同一个线槽里并排走了三米多分开走线之后故障率直接归零。这类问题在实验室里永远复现不出来只有到现场才会现形。通信距离和波特率是此消彼长的关系。9600bps下理论距离可以做到上千米115200bps时建议控制在百米以内。距离长、节点多的场合适当降速比什么都管用。还有一点常被忽略FX5U内置的485口不是隔离型。如果通信双方分处不同的配电柜、地电位差比较大建议在链路中加隔离中继器或者在选型阶段就用带隔离的通信扩展模块。隔离不是万能的但在地电位差明显的现场它能省掉大量莫名其妙的通信故障。6. 一次完整的联调实录从发不出到稳定收发理论说完了拿一个实际场景走一遍。通信对象是一台支持ASCII私有协议的称重仪表要求PLC每隔一秒读一次当前重量。6.1 协议帧拆解与程序分段仪表手册给的读重量命令是 站号(2位) RD 地址00004位 校验和(2位) CRLF。校验和是到地址末位共9个字节的累加和取低8位转两位大写十六进制ASCII。响应格式是 站号 RD或- 6位重量值 校验和 CRLF共19个字节。站号设为01的情况下帧头部分固定为01RD0000。按第4节的算法这9个字节的累加和是0xE7转成ASCII就是E0x45和70x37。完整发送帧13个字节01RD0000E7\r\n。参数上波特率9600、8位数据、无校验、1位停止位校验和设无因为要自己算结束符设无因为要手动拼CRLF如果这里设了CRLFFX5U会自动再补一遍对方收到两个CRLF。程序分三段写。第一段初始化M8002下把发送缓冲区清空、把固定的帧头内容写进去、设定发送和接收点数。第二段拼校验和用BSUM加查表法算出两个字符塞到D104。第三段是轮询主体M8013上升沿触发RS2完成标志和异常标志分别处理。6.2 联调中出现的问题与定位过程第一轮上电串口助手挂在总线上监听能看到PLC确实在发数据但仪表毫无反应。抓到的帧是01RD0000E7\r\n逐字节对照手册一个不差。问题出在参数——仪表的通信格式是8位数据、偶校验、1位停止位而我按无校验配的。改成偶校验之后仪表立刻有响应了。第二轮仪表回了数据但PLC的接收完成标志M201始终不置ON一直等到超时才结束。原因是我把接收点数设成了19而仪表实际响应是18个字节——重量值没有负号的时候少了符号位那一个字符。接收点数改成64、结束符设成CRLF靠结束符判定问题解决。第三轮运行半小时后开始偶发丢帧异常标志M202大约每小时亮两三次。参数和程序都查过没问题最后顺着线槽找发现通信线和一台设备的动力电缆并排敷设。改道之后连续跑了三天没再出现。第四轮是解析环节接收缓冲区里拿到的重量值要还原成数值参与比较。这里用STR指令把接收区转成字符串再从第5位开始截取6个字符用VAL指令转成数值。注意截取前要确认响应的符号位是否存在负数响应比正数多一个字符不处理的话数值会整体错位。6.3 稳定运行后的几点收尾工作联调通过之后有几件事建议顺手做掉。一是把通信异常的处理逻辑补全。单次失败重试三次三次都失败才置报警位同时在HMI上显示累计失败次数和最后一次的异常代码。这样现场出问题时值班人员一眼就能看到是从来没通过还是偶尔失败排查方向完全不同。二是给接收缓冲区加一个清零动作。每轮RS2执行之前把接收区起始的若干寄存器清成0避免上一轮的残留数据混进这一轮的解析里。这个动作开销极小但能省掉很多数据看着对、细看不对的怪问题。三是把站号、波特率、超时时间这些可调参数放到HMI上别写死在程序里。现场换设备、加节点的时候改个数字比重下程序快得多。四是留一份串口抓包记录。调试期间抓到的正常帧和异常帧都存下来后面再出问题时拿出来对比能快速判断是设备侧变了还是PLC侧变了。7. 通信不通时的排查链路这套顺序是我这些年养成的习惯从物理层往上走一层层排除比东一榔头西一棒子有效率得多。物理层先确认A/B有没有接反、SG接没接、终端电阻装了没有、线缆有没有断