ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用STM32仿西门子S7-200 PLC:低成本PPI协议控制器实现

用STM32仿西门子S7-200 PLC:低成本PPI协议控制器实现 简介这是一套基于STM32的仿西门子PLC228完整量产方案面向嵌入式开发、工业控制及PLC替代应用场景适合需要低成本自研PLC或深入理解PLC运行机制的工程师。压缩包共113个文件约51.92MB工程内容覆盖Altium Designer原理图与PCBpcbdoc/schdoc、STM32固件源码c/h/s、Keil工程配置、PDF说明文档及hex烧录文件等从硬件设计到软件运行均有完整交付。资源描述明确为“量产成熟方案”附带全套BOM与详细说明可作为硬件改版、软件二次开发或小批量生产的直接参考。已有702人学习下载尤其适合具备一定嵌入式基础、希望借鉴整套PLC实现框架的开发者按目录结构即可快速定位原理图、代码模块与生产文件。 开始聊这个项目之前我先说个背景。前段时间要做一套小型自动化控制板传统做法是直接上西门子S7-200作主控但PLC价格高、交期又不好控手里正好囤了一批STM32F103。于是我就认真研究了一圈“用STM32仿西门子PLC228”这类方案最终把这套东西从PCB画板到梯形图下载跑通做成了一个能用STEP 7-MicroWIN写逻辑、能用RS485通信、能直接驱动继电器输出的低成本PLC控制器。这篇文章把整个方案的设计思路、硬件选型、协议实现、实操流程和踩坑记录整理出来给想搞工控替代方案或者学习PLC工作原理的朋友做个参考。1. 项目定位与整体思路拆解1.1 先搞明白这个项目“仿”的是什么很多人一听“STM32仿西门子PLC228”第一反应是拿单片机去模拟一个PLC外观或者干脆就是个点灯玩具。其实不是。这个项目要做的事情是在STM32上实现西门子S7-200 PLC的编程环境兼容能力让你在STEP 7-MicroWIN里画梯形图写逻辑然后能像给真PLC下载程序一样把这套逻辑下载到STM32板子上让它根据输入信号执行梯形图再驱动输出继电器。换句话说软件生态是西门子的硬件核心是STM32的中间通过PPI协议把两者接起来。“PLC228”这个型号名称很值得解释一下它并不是西门子官方型号而是开源社区里对S7-200体系一个自定义的习惯叫法。早期有人做兼容CPU 224、CPU 226后来又有开源项目把这种兼容方案统称为“仿PLC228”实际上就是做一版支持S7-200梯形图指令集的嵌入式控制器。这个方案非常适合三类人一类是做设备配套的工程师不想每台设备都上千块买原装PLC另一类是嵌入式开发者想从寄存器操作层面理解PLC扫描执行的工作原理还有一类是自动化专业的学生想通过低成本硬件反复练习梯形图编程。1.2 为什么核心芯片选STM32F103选择STM32F103来做这个方案核心原因有三个。第一是价格和供货优势F103C8T6这种芯片散片也就几块钱即便用ZET6容量更大的型号整体BOM成本也比原装PLC低一个数量级。第二是资源够用72MHz主频、64K到512K Flash、20K到64K SRAM跑一个梯形图解释执行引擎加上PPI协议从站性能非常充裕。第三是外设丰富2到3路USART可以分开处理PPI编程口和Modbus通信多个定时器用来产生梯形图运行所需的时间基准GPIO资源足以扩展几十路数字量输入输出。需要额外强调一点市面上国产的APM32、GD32很多型号可以直接用STM32的程序寄存器兼容性很好。如果你做产品有供应链考虑完全可以在代码层面保持同一套工程只是在烧录时编译不同的芯片型号。这让我在项目中期换料时省了不少事程序几乎零改动就能跑到国产芯片上。整体软件架构上下位机固件分为三个层次底层是STM32的外设驱动中间是PPI协议栈和指令解析引擎最上层是梯形图运行时环境。梯形图下载的时候上位机并不是把图形文件直接发下来而是通过PPI协议进行数据交换把编译后的逻辑块写到PLC的V区或者程序块中。STM32收到这些编译后的指令数据再通过自己的解释执行器在每次扫描周期里逐条执行梯形图对应的指令列表。2. 硬件设计从最小系统到隔离IO2.1 最小系统与电源设计硬件电路是整个PLC方案的基础一开始我太乐观直接在现成开发板上测试协议结果通信不稳定、程序跑飞找不到问题。后来还是老老实实画了一版专门的控制板把所有电气细节都处理好。最小系统这部分STM32F103的启动模式必须处理好BOOT0引脚要接10K下拉到地让芯片从Flash启动。复位电路用经典的RC复位10K电阻加100nF电容到地同时接一个复位按键方便调试。晶振我用的是8MHz无源晶振这里就涉及到晶振电容计算的问题STM32的OSC_IN和OSC_OUT引脚各接一个负载电容到地容值选择公式是CL相当于两个电容串联后的等效值再加上引脚寄生电容约3到5皮法。比如目标负载电容12pF那每个外接电容取两个串联后等效约8到9皮法串联两个同样容值的电容等效值是一半所以取18pF到22pF基本都能匹配。F103内部PLL可以最高倍频到72MHz这也是主频的极限值。电源部分我采用外部24V工业电源输入经过防反接二极管和保险丝后先由XL1509降压到5V再通过AMS1117-3.3得到数字3.3V给STM32和逻辑电路供电。要注意的是如果板上既有数字3.3V又有模拟3.3VADC采集时要用磁珠隔离并且在每个电源引脚旁边放100nF去耦电容。实测下来这个电源方案在驱动4路继电器同时动作时5V纹波还能控制在50mV以内可靠性足够。2.2 输入输出电路与RS485通信接口PLC和普通单片机开发板最大的区别就是IO口必须能接工业现场的传感器和执行器要能扛住24V电平、静电放电和电磁干扰。数字量输入侧我用PC817光耦做隔离输入端口串一个1K限流电阻再反向并联一个二极管保护LED避免反压击穿外部接入24V时电流大约10mA光耦输出端由3.3V上拉。这样STM32内部和外面24V系统完全电气隔离即使外部接线短路也不至于烧主控板。输出侧如果直接驱动继电器线圈单片机IO口电流不够而且反电动势很容易打坏引脚。我选择了ULN2803达林顿管阵列自带续流二极管每个通道500mA电流驱动能力驱动5V小型继电器非常稳定。考虑到PLC应用里有时需要控制24V中间继电器ULN2803的COM引脚接上24V就能释放反向电动势输出端直接接继电器线圈到24V简单可靠。当然如果你要的是晶体管输出型PLC特性可以用光耦加MOS管方案但通用性不如继电器输出实用。RS485通信这块是整个方案能不能被STEP 7-MicroWIN识别的前提。我用的收发芯片是SP34853.3V供电最大通信速率10Mbps但PPI协议默认波特率是9.6kbpsSP3485完全够用。A、B总线之间并联一个120欧终端电阻这个电阻是必须的不然信号在长线上反射严重会出现时通时不通的情况。在工业现场A、B线还分别对地接了TVS管防止总线受到浪涌干扰损坏芯片。另外SP3485的RO引脚和DI引脚通过6N137光耦与STM32的UART引脚隔离这样通信接口和主控之间也是隔离的整体抗干扰能力上一个台阶。RE和DE引脚我用一个GPIO控制方向收和发切换之间加一点延时避免发送完最后一个字节立刻切换方向导致帧尾被截断。3. 软件架构PPI协议和梯形图引擎3.1 PPI协议让电脑认出你的PLCPPI协议是西门子S7-200编程口使用的通信协议运行在RS485物理层上主从式结构编程软件作为主站PLC作为从站。网上能找到的资料不算多但如果你手头有逻辑分析仪抓取编程软件和真实PLC之间的通信报文很快就能把帧格式摸清楚。一个典型PPI帧的结构是这样的起始字节SD固定为0x68然后是LE和LEr表示数据长度再次是SD1固定0x68接着是DA目的地址、SA源地址、FC功能码最后是数据单元DSAP、SSAP、DU和FCS校验字节以及结束字节ED。FCS是整个帧中从DA到DU之前所有字节累加和取低八位这个校验算法很简单但非常容易出错写代码时务必逐个字节验证我第一次写校验函数就把DA和SA弄反了导致上位机直接报错没有响应。STM32这一端要做的事情是作为PPI从站监听上位机发来的请求。我使用USART2接收中断把收到的字节放进环形缓冲区主循环里对帧进行状态机解析。状态机按照起始字节、长度、地址、功能码、数据域的顺序逐层判断。地址匹配很关键STEP 7-MicroWIN默认访问站号2所以STM32固件里默认从站地址设置为2如果你要支持多从站就把地址做成参数存到Flash里。接收完一个合法请求后固件需要根据功能码组织应答帧。最常用的几个功能包括读取PLC状态、读取系统数据块、写入程序块、控制PLC运行停止、读取变量值等。这一块是整个项目工作量最大的地方因为上位机在连接和下载的过程中会发出各种探询报文只有准确回应每一个请求STEP 7-MicroWIN才会认为你是一个正常的S7-200设备才会开放下载和监控功能。3.2 指令解释器梯形图执行的秘密当STEP 7-MicroWIN把梯形图编译成逻辑块数据再通过PPI协议下载到STM32之后STM32就需要把这些数据“跑起来”。梯形图本身不是直接被CPU执行的它首先会被编译成一条条语句表指令类似LD I0.0、AN I0.1、 Q0.0这种指令列表。西门子S7-200在运行时就是逐条执行这些语句表指令的所以STM32端要做的就是实现一个指令解释器对这些指令进行解析执行。指令执行引擎的核心变量是逻辑栈。PLC的梯形图是多个网络组成的比如并联分支时需要暂存中间结果这时就用到了栈操作。我的实现方案是在SRAM中维护一个深度为8的布尔栈LD/LDN指令把触点状态压栈A/AN指令把栈顶与寄存器的结果进行AND操作O/ON指令执行OR操作输出指令“”则把栈顶值写到输出映像区。这个逻辑和CPU的算术逻辑单元一个道理只是操作对象是位变量。除了位逻辑指令定时器和计数器也是PLC程序里高频使用的功能。S7-200的定时器分为通电延时TON、断电延时TOF和保持型定时器TONR计时基准有1ms、10ms和100ms三种。STM32的SysTick我配置成1ms中断一次中断里累加系统时基并更新所有定时器实例的当前值。这里有个难点不同精度定时器的刷新策略不一样1ms定时器要每个毫秒都刷新而100ms定时器可以每100次刷新一次如果统一按1ms刷新也没问题只是执行多个网络时效率和实时性会受到轻微影响。计数器CTU的原理也不复杂每检测到一个上升沿计数器当前值就加1当当前值大于等于预设值时计数器位输出置位。上升沿靠上一次扫描值和本次扫描值取反相与来判断需要在每个扫描周期里保存每个计数器的旧输入状态。扫描周期的实现思路是第一步读取所有数字量输入引脚状态更新输入映像表第二步执行用户程序也就是逐条执行下载下来的指令列表第三步把输出映像表的状态通过GPIO写到实际输出引脚。一次完整的“读输入、执行程序、写输出”就是一个扫描周期。用户程序执行过程中不允许直接操作硬件引脚只能读写内存映像表这样无论程序怎么写整个周期的行为都是可预测的。4. 实操记录跑通第一个点动程序4.1 工程搭建和固件烧录固件工程的搭建我推荐直接使用STM32CubeMX生成基础代码然后集成自己写的PPI协议栈和指令解释器。用CubeMX的好处是时钟树和引脚初始化交给工具生成减少手工配置出错的可能。关键配置项包括外部晶振HSE选8MHzPLL倍频到72MHzUSART2配置成异步模式波特率9600数据位8位偶校验1位停止位这个参数和PPI协议完全对应。SysTick天然就是1ms中断不需要额外配置。代码编写完成以后用ST-LINK V2通过SWD接口烧录。这里提醒一下STM32的SWD接口在代码里默认是开启的但如果你后续调试时把SWD引脚复用成普通GPIO会导致烧录器连不上解决办法是按住复位键点击烧录在烧录器复位芯片的瞬间释放复位键。这个操作能救回很多“变砖”的板子我第一次把PB3和PA15复用成输出之后就是用这个办法恢复烧录的。4.2 用STEP 7-MicroWIN建立连接和下载程序到这一步硬件已经通过USB转RS485模块连接到电脑了。这里有一个特别容易踩的坑市面上买到的USB转串口模块很多是TTL电平而不是RS485电平直接连SP3485的A、B线肯定不行。必须用带RS485收发功能的模块或者确认模块本身输出的就是RS485差分信号。我手头有个FT232RL加SP485方案的USB转RS485模块测试下来兼容性很好。在STEP 7-MicroWIN里双击通信刷新系统会扫描PPI网络上的设备。第一次刷新时如果看到地址为2的设备就说明PPI协议栈工作正常了。如果看不到设备先检查PG/PC接口设置确认选择的是PPI协议并指定正确的COM口号。然后检查USB转RS485模块的A、B线有没有接反A接A、B接B如果线序反了通信绝对建立不起来。连接成功之后新建一个工程写一个最经典的启动自锁程序按一下启动按钮I0.0常开触点输出Q0.0线圈得电同时在Q0.0旁边并联一个自己的常开触点做自锁停止按钮用常闭触点I0.1串联在回路里。下载之前把PLC切换到STOP模式这样程序下载过程更稳定。点击下载按钮STEP 7-MicroWIN会把编译后的逻辑块通过PPI协议发送给STM32。下载成功后切换到RUN模式这时STM32会按扫描周期开始执行梯形图逻辑。按下接在I0.0输入端的按钮Q0.0对应的继电器就会吸合按下停止按钮Q0.0就释放。这样一个完整的PLC循环就跑通了。4.3 在线监控和状态观察一个PLC方案只做到能下载程序还不算完全兼容在线监控能力也是重要指标。STEP 7-MicroWIN可以打开状态图表添加I0.0、I0.1、Q0.0这些变量地址然后点击监控按钮。这些变量值会实时从STM32通过PPI协议上传到上位机方便观察程序运行状态。更直观的功能是梯形图监控模式程序里触点和线圈的状态会高亮显示绿色表示导通。第一次在STM32方案上看到梯形图实时高亮的时候确实有种“成了”的感觉。调试过程中我还用到了在线强制功能。比如在状态图表里直接强制Q0.0为1看输出继电器是否动作。这个功能看起来简单但实现上需要PPI协议支持写单个变量而STM32端要正确处理写V区、写Q区的请求。如果强制输出不生效优先检查协议栈里写操作对应的数据区地址映射是否写得正确Q0.0在S7-200里的映射地址是Q区偏移地址0的第0位V区是从VB0开始连续的一段存储空间这个对应关系不能搞混。5. 踩坑实录常见故障与排查思路5.1 上位机刷新不到设备怎么办这是整个方案里出现频率最高的问题。遇到这种情况我一般按这个顺序排查。第一步检查RS485链路用万用表量A、B线之间的电压正常空闲状态下应该在1.5V到5V之间。如果电压接近0大概率是收发芯片没有正常工作检查SP3485的供电和RE/DE引脚方向控制。如果电压正常继续检查波特率、校验位、数据位这些串口参数是否和固件一致PPI是9600、8位数据、偶校验、1位停止位不能按Modbus习惯设成8N1。第二步检查地址匹配STEP 7-MicroWIN默认搜索站号2的设备如果你的固件把地址写成了别的值需要先在软件里修改远程站地址或者把固件默认地址改回2。另外注意上位机软件有时会缓存上次的通信配置换地址之后要退出软件重新打开否则还是连不上老地址这个坑我至少踩了两次。第三步就要用串口分析仪抓数据了。把USB转RS485模块的A、B线同时并接到逻辑分析仪上看上位机有没有发出PPI请求帧。如果发送端正常但没有应答基本可以确定问题在STM32固件的帧解析或者应答逻辑上如果压根没有请求帧那就是上位机配置的问题。5.2 程序能下载但PLC不运行这类怪问题有几次遇到程序下载成功也切到RUN模式了但输入输出完全没反应。这种问题往往不在PPI协议而在执行引擎本身。首先要确认STOP/RUN切换是否真的生效了。S7-200的RUN模式需要程序块里有合法的用户程序如果之前下载的工程是空程序或者下载过程中逻辑块数据就不完整执行引擎可能没有获得任何可执行的指令。解决办法是先下载一个最简单的点动程序确认能运行后再写复杂逻辑。其次是扫描周期是否正常启动。可以在固件里加一个调试用的周期计数变量每执行完一个扫描周期就自增一次再把这个变量通过预留的UART3打印到调试串口。如果计数不变化说明执行引擎卡死在了某个指令上。最常见的原因是指令解释器遇到无法识别的操作码这时程序会挂起我一开始就是直接返回错误处理结果导致扫描周期停止。后来改成跳过未知指令并继续执行同时记录错误码整个系统的鲁棒性就好了很多。最后还需要检查堆栈和内存分配。PLC程序的变量存储在V区S7-200的可寻址V区很大但STM32F103的SRAM是有限的我用ZET6有64K SRAMV区也只分配了8K左右。如果上位机程序里配置了大数组和字符串变量写V区的操作超出内存边界就会把系统变量覆盖导致各种随机故障。在PPI协议栈里增加地址越界检查是非常必要的一旦写地址超出范围就丢弃该请求并返回错误代码避免核心数据结构被破坏。5.3 实时性和抗干扰方面的心得仿PLC方案基于STM32解释执行实时性是很多人最担心的问题。我实测下来在72MHz主频下扫描周期大约在1到2毫秒之间和原装PLC几百微秒到几毫秒的扫描时间没有本质差别。但需要注意指令解释器每执行一条指令都有函数调用和栈操作的开销如果梯形图里有大量数学运算或浮点处理扫描周期会明显上升。因此我在固件里编译时开启-O2优化并把系统时基中断的优先级调到最低确保中断不会频繁打断指令执行。抗干扰方面光耦隔离加TVS管是必须的尤其是继电器频繁吸合断开的场合。第一次测试时我没有装续流二极管ULN2803也没有接续流保护结果继电器动作几次之后STM32就开始随机复位。加上续流二极管之后电路工作就稳定了。此外给单片机电源加一个独立的LC滤波或者至少并联一个大容量电解电容对消除继电器线圈拉低电压的问题也有很大帮助。前面讲的都是这个方案的核心内容最后再分享一个我后来补上的功能。我给PLC228扩展了一个自诊断位程序里偶尔用它来监控扫描周期、堆栈状态和通信错误计数。排查现场问题时这个自诊断位能直接通过STEP 7-MicroWIN的状态图表读出来省去了额外接调试串口的麻烦。这个做法操作起来很简单但效果真的很明显尤其适合自己做的非标控制器在没有屏幕的环境下快速判断程序状态比反复猜测和盲调日志高效得多。本文还有配套的精品资源点击获取
返回列表