
1. 项目背景与需求拆解为什么又是Modbus加RS485做工业自动化的人十有八九都躲不开Modbus和RS485这对黄金搭档。我这次接到的是一个现场改造项目要在一条老产线上把和利时PLC和十几台分散的智能仪表、变频器打通做集中监控和数据采集。甲方要求很直接成本尽量低、施工尽量快、后期好维护。一圈对比下来选型和利时PLC做主站、RS485总线组网、Modbus RTU跑协议几乎是唯一不用纠结的答案。先说和利时PLC。国内工控圈用和利时的用户基数不小尤其是LK和LM两个系列在中小型项目中出镜率非常高。它自带的COM口本身就支持标准的串行通讯通过Modbus协议可以直接和第三方设备对话。这类PLC最大的优势是编程环境对国内工程师比较友好指令系统清晰处理Modbus通讯时不需要额外买专用的通讯模块一台PLC的串口就能把主站功能跑起来。再说RS485。工业现场设备分布范围经常超过几十米RS232那种二十米就拉胯的通讯方式根本扛不住现场工况而RS485用差分信号传输抗共模干扰能力强最远能到一千两百米左右而且只用两根线就能挂载多达32个节点不加热插的常规配置下。对于仪表、变频器、温控器这类Modbus从站设备RS485就是它们的标准配置接口。最后说Modbus协议本身。这个协议是Modicon在1979年搞出来的本来是给自家PLC做通讯用的后来因为实现简单、完全开放、没有任何授权费用各路设备厂商纷纷跟进变成了工业自动化领域事实上的通用语言。它要数据就能读数据要控制就能写数据报文结构清清楚楚调试时拿串口助手看字节流就能把问题定位个大概。这套组合解决的核心痛点是让一台和利时PLC通过两根线同时管理几十台不同品牌、不同功能的设备。省去了给每台设备单独拉线、单独配IO的重复工程也让数据从“现场设备里各自独立”变成“中枢统一可控”。如果你手头刚好有类似的设备联网需求或者刚接触和利时PLC的通讯编程这篇就是冲着你来的。2. 硬件选型与组网接线RS485链路搭不好后面全白干2.1 和利时PLC串口选型与硬件准备先说硬件清单。我这次用的是和利时LM系列的小型PLC自带一个九针串口物理层兼容RS232/RS485。很多人第一次看到PLC背后的DB9接口容易懵这里直接说结论和利时这类型PLC的九针口RS232走的是标准定义但RS485的引脚定义不同厂家经常不一样动手接线前一定要先翻硬件手册确认引脚编号不能想当然按通用DB9定义去接。我实测的LM系列DB9接口上RS485的A对应差分信号正端也有人标D和B负端或标D-分别占用特定引脚具体编号每个批次可能有差异。建议拿到设备后先用万用表蜂鸣档测量找到与通讯端子标识对应的针脚再去做线缆接头这一步能省掉后面非常多的排查时间。另外通讯端口如果带电插拔有概率损坏串口芯片现场务必养成断电接线的习惯。从站设备侧就是常规操作了。绝大多数智能仪表和变频器的RS485端子都是标准的A/B两个接线端子有些还标了和-。这里要特别留个心眼不同厂家对A/B的叫法偶尔会相反有的把A当正端有的把B当正端。组网后如果所有设备通讯都报错首先就要怀疑是不是某台设备的A/B接反了。2.2 RS485布线规范与终端电阻RS485看起来就是两根线走线时讲究很多。我在项目里总结出了一套比较稳的接法通讯线用屏蔽双绞线不要用普通平行电线。双绞结构本身就能抵消一部分电磁干扰屏蔽层负责对抗现场变频器、电机带来的强干扰。屏蔽层采取单端接地我习惯在PLC这一端接地另一端悬空。如果两边都接地地电位差会在屏蔽层上形成环流反而把干扰引进来。主干线尽量从一台设备串到下一台设备也就是菊花链拓扑不要搞星型分支。分支线越短越好超过一米就容易出反射问题。在总线的两端各接一只120欧姆终端电阻匹配线路阻抗减少信号反射。如果通讯距离短、速率低、节点少终端电阻不接可能也能跑但现场环境复杂建议还是按标准接上。手头的120欧姆电阻可以直接并接在首尾设备的A、B端子之间注意是接线端子上并不是PLC内部程序里做任何配置。这些细节看起来琐碎但RS485通讯的稳定性很大程度上就是被这些“小讲究”决定的。之前有个项目就是省略了终端电阻平时通讯正常一到变频器大负荷运行就偶发通讯中断查了半天最后把终端电阻补上就消停了。2.3 RS232与RS485的区别为什么现场更偏爱后者聊到这不妨把RS232和RS485的区别说透。RS232是单端信号传输发送和接收各用一根线参考地共用电压摆幅大传输距离一般不超过十五米而且标准接口只支持一对一通讯。RS485则是差分信号传输A和B两根线上的电压差来决定逻辑0和1抗干扰能力强很多支持多点挂接速度也能跑到10Mbps以上短距离时。所以只要是设备分散、数量多、现场环境不理想的场合RS485几乎是唯一稳妥的选择。RS232更多用于近距离一对一调试比如直接把电脑和PLC临时连起来看数据。3. Modbus RTU协议核心拆解从报文到功能码一次说清3.1 报文结构与CRC校验Modbus RTU的报文格式非常紧凑一条完整的请求或响应报文由四部分组成从站地址、功能码、数据区、CRC校验。从站地址占一个字节范围是1到247其中0是广播地址只适用于写命令。功能码占一个字节决定了这条报文要做什么操作。数据区是变长的具体内容看功能码而定。CRC校验占两个字节用来保证数据传输过程中的完整性。CRC16的计算是Modbus RTU比较劝退新手的点其实算法思路很机械一个16位寄存器初始化为0xFFFF然后把报文里每个字节与寄存器低字节异或再右移八次每位移出1就与0xA001异或。整个过程循环到所有字节处理完最后得到的寄存器值就是CRC。低字节在前高字节在后跟在数据区后面发出。我用C语言写过这个算法贴出来给大家参考uint16_t modbus_crc16(uint8_t *data, uint16_t len) { uint16_t crc 0xFFFF; for (uint16_t i 0; i len; i) { crc ^ data[i]; for (uint8_t j 0; j 8; j) { if (crc 0x0001) { crc 1; crc ^ 0xA001; } else { crc 1; } } } return crc; }刚开始学Modbus的朋友不用急着从0自己写CRC很多调试助手都自带CRC计算功能填上数据就能自动生成校验码用来核对程序算出来的结果完全够用。3.2 常用功能码与数据模型对应关系Modbus协议把从站的数据模型分成四类线圈Coil、离散输入Discrete Input、保持寄存器Holding Register、输入寄存器Input Register。写成通俗的话就是线圈是可读可写的开关量离散输入是只读的开关量保持寄存器是可读可写的16位数值输入寄存器是只读的16位数值。对应到功能码上读线圈是01读离散输入是02读保持寄存器是03读输入寄存器是04。写单个线圈是05写单个寄存器是06写多个线圈是15写多个寄存器是16。项目里接触最多的组合是03读保持寄存器、06写单个寄存器、16写多个寄存器基本覆盖了所有仪表参数读取和控制命令下发的场景。报文的实际格式用读保持寄存器举例主站发01 03 00 00 00 02 C4 0B含义是从站地址01功能码03起始寄存器地址0x0000对应PLC侧的40001读取数量2个寄存器CRC校验为C4 0B。从站正常响应则返回01 03 04 数据1高字节 数据1低字节 数据2高字节 数据2低字节 CRC也就是功能码后第一个字节是从站返回的字节数后面跟着实际数据。3.3 寄存器地址规则避开“地址偏移”这个经典大坑寄存器地址偏移是Modbus调试中很常见的坑。协议报文里的寄存器地址是从0开始的偏移量但很多设备手册和组态软件里给人看的地址是从1开始的比如手册上说“设备地址40001对应报文地址0x0000”。写程序时如果直接把40001填进报文里等于给设备发了一个不存在的地址返回的就是异常响应。我习惯的做法是程序内部统一用偏移地址也就是0x0000这种格式。读仪表数据时先用设备手册查清楚目标数据的协议地址和数据类型再对应到功能码和起始地址。比如现场有个温控器温度值放在保持寄存器40011协议地址0x000A用功能码03去读报文里的起始地址就是0x000A。任何一份Modbus设备手册拿过来先搞清楚它给你标的是“PLC地址”还是“协议地址”再从程序里对应调整能避免很多无意义的返工。4. 和利时PLC主站编程实战从组态到轮询逻辑落地4.1 编程环境与通讯参数组态和利时LM系列使用的编程软件是PowerPro界面风格对用过Codesys的人会非常熟悉。要跑Modbus主站第一步是把通讯端口参数配置到和从站设备一致。我这次统一用的是9600波特率、8数据位、无校验、1停止位也就是常说的8N1这也是大多数Modbus RTU设备的出厂默认值。PowerPro里配置串口参数的路径在硬件组态界面选中CPU后找到串口设置选项把波特率、数据位、校验位、停止位按实际需求填进去。有一个细节值得注意每个从站的波特率和校验方式必须和主站一致否则从站根本解不出主站发过来的报文表现为通讯一直超时。如果现场设备波特率各不相同要么逐台调整设备参数到统一数值要么给不同波特率的设备分组用不同的主站串口。4.2 主站轮询架构设计状态机才是稳定之选一个串口在同一个时刻只能处理一对主从通讯所以主站要想和多台从站设备交互必须设计轮询逻辑。写轮询最忌讳的就是用一堆定时器硬延时的“土办法”一旦某个从站无响应整个循环就会被拖死。我这次用的是状态机思路代码结构清晰容错性好扩展新从站也方便。状态机的大致思路是这样的状态初始化为发送请求帧变量记录当前正在通信的从站编号。进入发送状态后主站根据当前从站编号和功能码拼好一帧完整的Modbus请求报文放入发送缓冲区触发串口发送。发送完成后切换到等待响应状态同时启动一个超时定时器。超时时间我设置为200毫秒可以根据实际通讯距离和设备响应速度调整。如果在超时时间内收到响应就进入解析处理状态把报文里的数据提取到PLC的寄存器变量里标记该从站本次通讯成功。无论通讯成功还是超时都递增从站编号等所有从站都轮询一遍后再回到第一个从站重新开始循环。在PowerPro里这种状态机可以用梯形图或者结构文本ST来实现。ST语言写这类逻辑体验很好代码又短又直观。用ST写完后再封装成功能块主程序里调用时只需要传入从站地址和读写的寄存器信息非常方便。这里给一段ST语言参考帮助大家理解轮询的核心流程CASE state OF 0: // 发送请求 build_request_frame(slave_addr, func_code, start_addr, reg_count); send_buffer(); state : 1; timeout_timer : 0; 1: // 等待响应 IF recv_done THEN parse_response(); state : 2; ELSIF timeout_timer TIMEOUT_MS THEN comm_error[slave_addr] : TRUE; state : 2; END_IF 2: // 准备下一个从站 slave_addr : slave_addr 1; IF slave_addr MAX_SLAVE THEN slave_addr : 1; END_IF state : 0; END_CASE4.3 通讯点表规划与数据解析在和利时PLC里接收到的Modbus报文需要手工解析成实际数据。很多仪表的数据不是简单的整数而是带小数点的浮点数、或者高低字节拆分的16位值所以数据处理这步得细。比如一个温度变送器它的温度值以0.1℃为分辨率存储在保持寄存器里读出来的原始值是235那实际温度就是23.5℃。这种换算关系在设备手册里都会给程序里做一次乘除运算就行。我的做法是专门建立一张通讯点表Excel里列清楚每个从站地址、寄存器起始地址、寄存器数量、功能码、数据类型、换算系数、对应的PLC内部变量名称。这张表既是写程序的依据也是后期现场调试和维护的索引。每次新增设备先补表再改程序出错概率会小很多。5. Modbus仿真调试先用工具验证逻辑再上现场硬件5.1 Modbus Poll与Modbus Slave的搭配使用程序写完之后直接接现场设备调试是新手常干的事但效率很低。更稳的流程是先用仿真软件把通讯逻辑跑通再拿到现场连真实硬件。我常用的组合是Modbus Poll当主站调试工具Modbus Slave当从站仿真工具。Modbus Poll的作用是模拟一个Modbus主站可以按设定周期读取从站数据也能手动写单个或多个寄存器。它可以用来验证现场设备或仿真从站的数据是否正确定义也可以用来测试我们写好的和利时PLC从站功能。Modbus Slave则相反它把电脑模拟成一个Modbus从站设备可以部署一组指定的寄存器数值等待主站来读。这两个工具一主一从配合起来就能在电脑上把通讯链路完整模拟一遍。调试时的标准思路是先用Modbus Slave虚拟一个从站设置好模拟数据再用Modbus Poll作为主站去读它。如果主从能正常交互说明电脑端协议逻辑没问题。接着让和利时PLC去和Modbus Slave通讯这样就能在不占用现场设备的情况下验证PLC主站程序的对错。最后才把PLC接到真实设备上用Modbus Poll做第三方监看确认报文内容是否符合预期。5.2 现场报文抓取做到看得见才算真调通调试Modbus的时候最能直接说明问题的就是报文本身。Modbus Poll和Modbus Slave都有报文日志功能勾选显示原始报文后每一帧请求和响应都会以十六进制显示出来请求帧、响应帧、异常帧一目了然。我调试时习惯开着报文监视看三个东西主站有没有定时发出请求帧、从站有没有及时回复响应帧、响应帧里的数据值和现场仪表显示值是否一致。有一次变频器频率读出来总是不对用报文日志一查发现从站返回的CRC总是报错拿万用表测了物理层才发现是A/B反接了。如果没有报文监视这种问题可能要瞎猜很久。协议调试最大的优势就是“所见即所得”抓包看到的字节永远不会骗人。5.3 新手上路推荐从一主一从的最小系统开始如果你是第一次接触Modbus通讯我强烈建议先把系统简化到最小一台电脑当主站、一台电脑当从站用USB转RS485线连接先跑通一发一收再逐步增加节点。不要上来就拉一整套几十台设备的系统出了问题根本无从下手。最小系统的价值在于链路、协议、报文格式这三个层次的变量都被控制住了只要有问题就能非常清晰地定位到具体环节。6. 调试实录典型问题与排查方法6.1 通讯超时挂起现场最常见的故障是通讯一直超时主站发出去的请求帧石沉大海。排查时按这几个方向走先用万用表量从站设备的AB端子电压正常空闲状态下应该有1到5伏的电压差如果量出来是0大概率是接线断开、或者设备没上电。再检查总线两端有没有正确的终端电阻特别是通讯距离超过一百米之后少了终端电阻就容易出问题。最后用Modbus Poll代替PLC直接连从站设备如果Poll也超时说明问题出在链路或从站配置上和PLC程序无关如果Poll正常问题就锁定在PLC的串口参数或报文格式上。6.2 CRC校验错误频发CRC错误的含义是物理层数据收到了但是数据在传输过程中发生了变化。除了AB接反干扰是另一个常见原因。现场有大功率变频器、电机启动时瞬间浪涌会通过地线或空间耦合到通讯线上。处理方案无非几种把通讯线的屏蔽层可靠单端接地通讯线远离动力电缆交叉时尽量垂直走线降低波特率比如从19200降到9600在从站设备的AB端子上并联TVS管做浪涌抑制。逐个试大多数干扰问题都能缓解。6.3 个别从站反复掉线影响整个轮询周期轮询机制下只要有一个从站无响应整个循环都被卡住其他正常设备也收不到请求。这在中大型组网里很致命。解决思路是给每个从站单独设置超时判断无响应的从站只记录错误报文很快跳过它去轮询下一个。6.4 速度、校验位匹配问题从站设备波特率或者其他串口参数和主站不一致时表现也是超时。曾经遇到过一台设备出厂设置是8E1偶校验而主站统一配的8N1结果这台设备怎么读都是超时最后翻设备手册才发现校验位对不上。把所有设备的串口参数核对一遍比在程序里反复调报文快得多。6.5 注意容量上限RS485标准常规配置下最多挂接32个收发器。设备超过这个数量时需要通过增加中继器分段解决或者选用低功耗高输入阻抗的485芯片来扩展节点容量。这不是Modbus协议的限制而是RS485电气层面决定的。7. 和利时主站与变频器实战案例西门子PLC之外的另一条路热词里面有很多关于西门子PLC和变频器Modbus通讯的内容比如“一个西门子plc与32个变频器modbus通讯控制是否可行”之类的问题。和利时PLC做类似的集中控制思路大同小异这里用一个“多台变频器启停与频率给定”的实战案例把流程串一遍。变频器作为Modbus从站时常规控制模型是把启动、停止、正转、反转这些控制字写入变频器的控制寄存器把频率给定值写入频率设定寄存器。具体寄存器地址每款变频器手册不同调试第一步永远是查手册。比如启动停止的控制字写0x0001为启动、0x0002为停止频率设定值通常在另一个地址数值单位可能是0.01Hz。在和利时主站程序里针对每台变频器建立一个独立的写请求。启动某个电机时组一帧功能码06的报文把启动控制字写入该变频器对应寄存器。频率调节时组一帧功能码16的报文向连续的两个寄存器写入频率值。因为同一时刻只能有一个主从对话所以程序里必须把“写启动命令”和“读当前频率”这些操作放进同一个轮询队列避免同时发多个请求导致总线冲突。轮询顺序上我习惯把优先级高的控制命令放在前面周期性的状态读取放在后面。控制命令不是每个周期都发的只有操作员按下按钮时才需要往写队列里插入一帧写请求。读状态则是固定轮询周期循环执行比如把每台变频器的运行频率、电流、故障代码刷回来。整体思路就是“按需写、周期性读”这样每个设备都能拿到它的实时数据控制指令也不会被淹没在循环里。“一台PLC控制32台变频器是否可行”这个问题答案是可行但要注意轮询周期会随着节点数量线性拉长。假如每台设备读3个寄存器需要50毫秒32台设备光读取就要1.6秒一轮做实时性很高的同步控制就不太合适了。如果只是启停和常规监控这个响应速度完全够用。现场实际部署时还可以按产线把32台变频器分成两路RS485接两个串口把单个总线的轮询周期减半实时性就会好很多。8. 最后的实操心得做完整套项目我最大的感触是Modbus加RS485这套组合真的很值得下功夫吃透。它看起来“老”但在工业现场的生命力极其顽强几乎你能碰到的每一台仪表、变频器、温控器都支持这套协议。学会它意味着你不必依赖任何一家的私有协议用一套统一的方法就能把各种设备接入到控制系统里。而且这套方法论放到西门子、三菱、罗克韦尔等主流PLC上都成立换平台只是换编程语法而已通讯机制和调试思路是通用的。给后来者三个建议第一物理层永远排在第一位接线不规范、接地不可靠换再好的协议和算法都没用。第二调试时一定要借助工具看报文别靠猜报文的十六进制字节会把问题指得非常明白。第三程序架构用状态机别用硬延时一个灵活的轮询框架能帮你省下后面数不清的维护时间。最后分享一个小习惯每次做完一个Modbus项目把点表、波特率、设备寄存器定义、易踩的坑都整理成一份文档归档。半年后回看这就是最珍贵的经验库。