
干电气维修和调试这行十几年天天跟各种设备打交道PLC程序看过的没有一千也有八百。前阵子车间里有个小活老板说新来的电工想练练手让我拆个S7-1200的流水灯程序讲讲原理。我想着这玩意儿确实是个好的教学案例逻辑简单、效果直观但里面涉及到的小知识点一点都不少上电延时、移位循环、定时器配合、字节位映射这些够新手琢磨一阵子了。今天就把这个“上电延时触发移位循环流水灯”的梯形图程序从头到尾拆一遍把每一步的逻辑、指令选择的原因、调试时踩过的坑都写清楚。不管你是刚摸PLC的电气小白还是在车间搞设备维护想补补基本功的老师傅这篇都能给你点实在东西。即使手头没有S7-1200实物照着思路用博途仿真也一样能跑起来。1. 项目思路拆解流水灯为什么用“移位循环”1.1 先搞清楚流水灯到底要实现什么效果所谓的“流水灯”说通俗点就是一个一个灯依次点亮像水流一样过去。最常见的效果有几种单灯从左往右扫过去、单灯从两端往中间聚拢、多灯跑马灯式循环以及全亮全灭的呼吸效果。这次龙师傅拆的这个程序是最基础的“单灯循环右移”或者“单灯循环左移”——起始只有第一个灯亮每隔一段时间亮灯的位置往旁边挪一位走到最边上了再跳回起点周而复始。这里有个容易搞混的概念移位循环里的“循环”两个字指的是位数据从寄存器一头溢出后从另一头再补进来。这不同于普通的左移或右移普通移位空出来的是补0而循环移位是“头尾相接”的。比如一个字节8个bit第7位最高位移出去之后这个1被送到第0位最低位这样就形成了一个闭环灯永远不会灭只会转圈。1.2 为什么不用一堆置位复位而是用移位指令很多刚学梯形图的朋友第一反应是我有8个灯那我就写8个输出用一个定时器轮流触发置位和复位不就行了吗理论上可以但是程序会非常啰嗦。比如说8个灯每个灯至少需要一段置位逻辑、一段复位逻辑加上定时、切换程序会膨胀到几十行。如果以后改成16个灯、32个灯这种写法几乎是灾难改起来恨不得把整个程序重写。移位循环方案就优雅得多。核心思想是用一个字节Byte或一个字Word作为“数据容器”每个bit代表一个灯0是灭、1是亮。通过移位指令让这个“1”在容器里移动位置再把容器的bit直接映射到输出Q点。程序只需要一个移位指令加一个边界判断不管你接8个灯还是16个灯核心逻辑几乎不用变只需要改数据类型和输出映射而已。这就是“数据驱动逻辑”的思路跟那种一条指令写一个灯的“点动思维”完全不在一个层级上。1.3 上电延时触发是什么意思、有什么用上电延时触发字面理解就是系统上电之后不立刻开始跑流水灯而是等一段时间再启动。为什么要加这个延时两个原因一是设备上电瞬间PLC内部的输出模块、外部继电器、接触器都处于不稳定状态电压还没稳定这时候如果输出直接动作容易误触发外部设备可能引起机械冲击或者安全事故二是很多设备有“自检”流程上电后需要先让系统初始化完成确认外部条件OK了再进入运行逻辑。比如你接的是一个传送带的示意灯上电后让操作员有时间离开危险区域再开始跑灯这个延时就能起到缓冲作用。在这个程序里延时一般用TON接通延时定时器来实现。按下启动按钮后先让M0.0运行标志置位但此时输出还不动作TON开始计时计时结束的瞬间产生一个完成标志这个标志才去激活移位循环的“使能”端。为什么不用定时器直接用因为TON的Q端在延时结束后会一直保持为1如果你把这个Q端直接当使能信号那没什么问题但如果你想控制“延时不重新开始”就需要处理得精细一点否则每次按下启动都会重新计时。具体代码里怎么处理后面第三节会详细说。2. 软硬件准备与工程搭建跑通程序需要什么2.1 S7-1200的硬件选型与博途软件版本先聊硬件。S7-1200是西门子的小型PLC常见型号有1211C、1214C、1215C本体自带一部分数字量IO。做流水灯这种纯演示项目用CPU 1214C DC/DC/DC最合适自带14个数字量输入和10个数字量输出Q0.0到Q0.7正好8个点全都能用来接指示灯。如果你是自学的手头没有实物也没关系博途软件自带PLCSIM仿真功能仿真器里可以监控程序运行状态唯一区别是没有真实IO输出得靠变量表或者强制表来看字节数据的变化。软件方面TIA Portal博途从V13开始就支持S7-1200现在V15、V16、V17都是主流。版本不用纠结代码逻辑基本一样我用V16演示。如果你用的是V13或V11创建项目和指令位置略有差异但梯形图指令名称是通用的。2.2 新建博途项目并完成基础配置打开博途在“启动”界面点“创建新项目”输入项目名称比如“S7-1200流水灯演示”点确定。然后在项目树里双击“添加新设备”选择一个S7-1200 CPU型号。这里注意一点选CPU时一定要选对订货号和固件版本否则下载程序的时候会报固件不匹配。常见1214C的订货号是6ES7 214-1AG40-0XB0对应固件V4.0。选完CPU后系统会提示是否调用OB1默认是有的这个OB1就是主程序块我们绝大部分逻辑都写在OB1里。设备添加完成后还有两个设置建议提前做。第一个是CPU属性里的“启动”方式默认是“暖启动-重新启动”保持默认即可这意味着CPU上电后会执行一次OB100启动组织块再扫描OB1正好可以利用OB100做初始化。第二个是数字量输出的“对CPU STOP的响应”默认是“关闭输出”这个保持默认安全。如果你用的是实际PLC而不是仿真别忘了在“设备和网络”视图里给CPU分配IP地址IP地址要和电脑在同一网段比如PLC设192.168.0.1电脑设192.168.0.2。2.3 变量规划用符号表理清每个地址的含义我见过很多新手写程序直接在梯形图里填I0.0、Q0.0这种绝对地址这个习惯非常不好。程序短还好说程序一长满屏的I0.0、M0.2你根本分不清哪个是启动哪个是停止后期维护简直想哭。正确做法是在“PLC变量表”里把用到的地址一个个定义好符号名然后在梯形图里直接使用符号名。这个程序的变量表大致如下符号名数据类型地址注释启动按钮BoolI0.0点动启动上升沿触发停止按钮BoolI0.1常闭触点按下停止运行标志BoolM0.0程序运行总开关延时完成标志BoolM0.1TON定时器Q端移位时钟BoolM0.21Hz脉冲产生移位触发移位数据ByteMB20当前灯的亮灭状态初始值ByteMB21流水起始值默认1延时设定值DIntMD40上电延时时间毫秒LED输出-Q0.0~Q0.7BoolQ0.0~Q0.78路指示灯输出变量表建好后梯形图里引用M0.0时会显示“运行标志”这四个字程序可读性直接上一个台阶。3. 梯形图程序逐段拆解延时、移位、输出映射全流程3.1 启动组织块OB100给程序一个“干净”的起点S7-1200跟S7-200/300有个不同点它有一个OB100启动组织块CPU每次从STOP切到RUN或者上电启动OB100里的程序只执行一次然后才进入OB1循环扫描。这个特性非常适合做初始化操作。在OB100里我们要做的事只有三件把运行标志M0.0复位成0把移位数据MB20清零清掉延时完成标志M0.1。为什么要清零MB20如果不清零上一次运行的残留数据还在里面可能一开机就莫名点亮某个灯。初始化逻辑用梯形图写很简单用一段常开触点加一个复位线圈就行。比如用“常ON”的M0.3或者直接用系统常量TRUE去复位M0.0再复位MB20再复位M0.1。这里有个细节OB100里复位的M0.1和OB1里TON定时器的M0.1是同一个地址。这样设计的目的是CPU启动瞬间延时是肯定不会立即完成的必须先处于“未完成”状态。如果不做这个复位万一M0.1在断电前刚好是1那下次上电即使运行标志还没置位输出逻辑里的某些使能条件可能在不该满足的时候满足了。虽然不一定造成事故但程序不严谨隐患早晚出事。3.2 启停控制与上电延时像给程序装一道闸门主程序OB1里第一段要处理启停逻辑。启动按钮I0.0的上升沿用来置位运行标志M0.0停止按钮I0.1作为复位条件去复位M0.0、MB20和M0.1。很多老师傅习惯把停止按钮接成常闭触点接到输入端梯形图里用常开指令读取也就是“急停优先断开优先”的逻辑。如果接常开线掉了停不下来这是安全大忌。启停做完了然后是延时部分。当运行标志M0.0为1时接通一个TON定时器。TON的输入IN接M0.0PT端接延时设定值MD40Q端输出到M0.1ET是当前计时值可以用变量表监控。这里关键点是当M0.0从0变1时TON开始从0计时计时到设定值后M0.1被置为1并保持只要M0.0一直为1M0.1就一直为1。如果M0.0断开TON复位M0.1立即变0下次启动重新计时。这就实现了“每次按下启动后都先等5秒再开始跑灯”的效果。延时时间我习惯在程序里写死为5000ms如果你想通过触摸屏调节把这个地址换成触摸屏连接的DB块变量即可。3.3 移位循环核心时钟上升沿驱动“1”往前走灯要“走”起来必须有一个节拍就像音乐需要有拍子一样。这个节拍我习惯用M0.2移位时钟来表示。生成1Hz脉冲的常用方法是用另一个TON定时器做自复位振荡器也叫“闪烁电路”当M0.1延时完成标志为1时TON2开始计时计时500ms后Q端振一下同时用它的常闭触点或者常开触点让TON2复位然后再重新开始计时循环往复产生0.5秒周期的方波信号。取这个方波的上升沿就得到了每500ms一次的移位触发脉冲。注意梯形图里“上升沿”用的是边沿检测指令。我喜欢用“R_TRIG”触发块因为它比普通的“触点上升沿”更清晰尤其是在S7-1200的梯形图里R_TRIG是一个功能块需要配一个背景DB或者在全局DB里调用。用R_TRIG的CLK端接M0.2Q端接M0.4。这样M0.4就变成了一个“脉宽为一个扫描周期”的脉冲信号只在M0.2从0变1的那一瞬间为1其他时间都是0。移位操作就是在这个M0.4的脉冲驱动下执行。S7-1200的移位指令在梯形图里叫“SHL”左移全称Shift Left。具体用法EN使能端接M0.4IN端接MB20要移动的数据N端接1每次移动1位OUT端接MB20结果存回原地址。这样一来每来一个脉冲MB20就往高位方向挪一位里面的那个“1”就从bit0跑到bit1再跑到bit2依次点亮Q0.0到Q0.7。3.4 循环边界处理让灯绕回起点的关键技巧移位指令本身只负责移动它不管数据会不会越界。当MB20里的“1”到达bit7最高位后再执行一次左移这个1就会从最高位移出去MB20全部变成0灯全灭这不叫循环。所以我们必须自己写边界判断。思路很简单在每次移位之后扫描MB20的最高位M20.7也就是bit7的上升沿如果它变成1了说明“1”已经走到头了那么在下一个扫描周期把MB20重新赋值为1让“1”回到最低位重新开始走。用梯形图写就是M20.7的上升沿作为条件执行一条“MOVE”指令把常数1传送到MB20里去。有人可能会问为什么不直接用循环左移指令ROR/ROL这样硬件上就不需要边界判断了。这个想法是对的S7-1200确实有ROR循环右移和ROL循环左移指令直接就是循环移位。但这里有个坑S7-1200基础指令库里ROL和ROR的操作数类型是双字DWord不是字节或字。你如果想把MB20这个字节做循环左移得先把数据转换成双字再左移再截取低位操作反而更繁琐。所以这个项目里用“普通左移边界重装初值”的组合反而更简单直观也更容易让初学者理解循环的本质——所谓循环就是到头的重新开始。等以后做32位流水灯时直接用双字的ROL指令会更高效但初学者先把这种思路吃透受用无穷。3.5 输出映射把数据变成真实的灯数据在MB20里已经跑了但是MB20是个内部存储字节它不会直接驱动物理输出。最后一步是把MB20的每一位映射到Q0.0到Q0.7。最简单的方法是直接用8条赋值语句Q0.0 : MB20的bit0Q0.1 : MB20的bit1依次类推。梯形图里可以写成常开触点引用M20.0去驱动Q0.0的线圈引用M20.1驱动Q0.1以此类推。还有一种更简洁的方法是利用西门子的I/O直接映射特性把Q0.0到Q0.7所在的字节QB0直接赋值给MB20。也就是执行一条MOVE指令把MB20传送到QB0。这样一条指令搞定8个输出程序非常紧凑。但用这个方法有个前提QB0的低8位Q0.0~Q0.7不能同时被其他逻辑使用否则会覆盖。在流水灯演示项目里QB0专门留给指示灯所以可以放心用MOVE直接输出。输出映射放到移位的后面顺序别搞反。如果先映射再移位那灯会“慢半拍”每次总是显示上一次的移位结果。正确顺序是检测移位脉冲→执行移位→边界判断重装初值→把新值映射到输出。扫描周期是毫秒级的人眼感觉不到延迟但逻辑上必须对。3.6 完整程序段顺序总结把上面所有逻辑整理成梯形图程序段顺序至关重要程序段1启动停止逻辑置位复位运行标志M0.0程序段2上电延时TONM0.0驱动TONQ端输出到M0.1程序段31Hz时钟发生器用M0.1作为使能TON2自复位振荡产生M0.2程序段4上升沿检测R_TRIG检测M0.2上升沿输出到M0.4程序段5移位执行M0.4驱动SHL指令把MB20左移1位程序段6边界重装M20.7上升沿触发MOVE把1写入MB20程序段7输出映射MOVE指令把MB20传送到QB0这7段程序全部用梯形图写逻辑清晰从上往下一条线任何人拿到手都能顺着检查。4. 实操调试与常见问题仿真运行和现场排障4.1 用PLCSIM仿真运行没有PLC也能学没有实物的时候博途的PLCSIM是学习神器。把程序写好、编译通过后点仿真按钮PLCSIM会自动启动然后点下载把程序下载到虚拟PLC里。在PLCSIM界面里点“启动”按钮让CPU进入RUN状态就能看到程序开始执行了。但PLCSIM有个麻烦它不模拟真实的物理输入输出点。你想按下启动按钮I0.0得在程序监控界面里右键I0.0的线圈位置选“修改为1”或者“强制为1”强制输入后程序逻辑立刻就会作出响应。同理停止按钮I0.1也要手动强制。这里要提醒一下仿真器里强制IO很方便但实际PLC上做强制操作一定要非常谨慎强制错一个点设备可能直接就动作了轻则停机重则伤人。用仿真调试时最有用的窗口是“监控表”。把MB20、QB0、M0.0、M0.1、M0.4这些关键变量拉到监控表里点击“观察”图标就能实时看到数据变化。特别是MB20你会在屏幕上亲眼看到它从1变成2、4、8、16、32、64、128然后跳回1循环往复。那种感觉非常直观程序到底有没有按逻辑跑一目了然。4.2 现场调试LED接线注意源型漏型和公共端如果你是在真实设备上跑这个程序接LED灯时有一个很容易踩的坑S7-1200直流输出点的接线方式。S7-1200大多数晶体管输出是源型输出也就是输出端接通时电流从模块流出到负载所以负载要有公共端接到24V电源负极。具体到一套LED指示灯你可以把LED的公共端接到PLC输出点的1L和2L上输出点的0.0到0.7分别接LED的负极。通电后Q点有输出时Q点和M电源负极之间导通LED点亮。接线前一定要先确认PLC输出模块的类型。如果是继电器输出型那公共端和接法跟晶体管型又有区别通常是一个COM端接220V电源的火线Q点出线到负载负载另一头回零线。继电器输出可以直接驱动220V的指示灯但如果是24V的LED就要注意别把电压接错烧了LED是小事把PLC输出触点打坏了就得换模块了。4.3 常见报错和异常现象速查表在调试这个流水灯程序的过程中有几种高频问题我把现象和原因、解决办法整理成了一张表方便对照异常现象可能原因排查与解决按下启动灯完全不亮运行标志M0.0没置位检查I0.0接线或强制值看监控表里M0.0是否为1延时结束后灯不流动移位触发脉冲没生成监控M0.2确认TON2是否在振荡检查R_TRIG是否正常工作灯亮了但跑着跑着全灭边界重装逻辑失效检查M20.7的上升沿检测是否写在了移位之后且重装值正确灯从最高位后不回到起点重装初值被后续扫描覆盖确认MOVE指令把1写入MB20后本周期不再执行SHL两个灯同时亮移位指令的N参数不是1确认SHL的N端是常数1不是2或更多上电后延时没生效延时时间PT数值过小检查MD40的数值默认5000ms别误写成5程序下载后CPU报错固件版本不匹配在项目树CPU上右键属性更新固件版本或者换匹配固件死活连不上PLCIP地址不在同网段确认PLC网线接到电脑网口Ping通PLC IP必要时恢复出厂设置4.4 调通之后几个值得做的扩展玩法程序跑通之后别急着收工。同一个核心逻辑稍微改一改就有很多变种我经常拿这个程序当“母版”给新人练手第一种改方向。把SHL改成SHR右移灯就变成从右往左跑注意边界判断要改成扫描M20.0最低位当它变1时把128写入MB20这样8个灯就倒着循环了。第二种改速度。把TON2的PT时间从500ms改成200ms灯就跑得快一些改成2000ms就跑得像乌龟爬。把这个PT参数接到一个模拟量输入的AIW值上你还能用外部电位器无级调速做成一个“速度感应流水灯”也挺有意思的。第三种加花样。不只有一个1在跑而是初始值设为3二进制00000011两个灯同时跑产生“双灯流动”的效果或者初始值设为12910000001变成两头灯往中间聚拢的效果。这一下就从“流水灯”进化到“跑马灯plus”了逼格直接拉满。第四种扩展输出数量。S7-1200如果是16个灯把数据容器从字节换成字Word变量类型改成MW20移位指令换成SHL_W字左移边界判断改到M21.7MW20最高位输出映射改成MW20传送到QB0和QB1两个字节。核心逻辑一点不用变熟悉这套操作后以后做32路输出、64路输出原理完全通用。5. 经验总结与设计心得程序拆解完了回头聊点实在的心得。这个流水灯项目看似简单但它几乎涵盖了PLC编程中最核心的几个概念位变量与字节变量的关系、定时器的工作机制、边沿检测的应用、移位指令的边界处理、以及输出映射的思路。这几样东西单独拎出来任何一个都够新手琢磨好一阵。把它们串在一起做成一个能看、能摸、能跑的实际项目学习效率远高于对着书本看概念。我个人在实际调试中最大的体会是写PLC程序第一优先级永远是“可读性”和“可维护性”其次才是“功能”。功能跑不通可以查、可以改但如果变量名全是I0.0、M0.2这种“天书”程序段堆在一起没有注释那这个程序过三个月连你自己都看不懂更别说后面接手的同事了。所以我在上面花了很大篇幅讲变量规划和程序段顺序就是希望大家能养成一个好习惯程序是给人看的顺带让机器执行而已。另外调试这种带移位和边沿检测的程序我最推荐的工具就是“监控表”。每次跑完一个循环看一眼MB20和QB0的数据变化如果和预期不符立刻就能定位是哪一段逻辑出了问题。比拿万用表一支笔一支笔量输出点要高效得多。如果做仿真调试强制IO前也要想清楚强制的输入值不会被外部实际信号覆盖忘了取消强制后续程序可能一直保持在一个错误的状态排查起来非常容易被误导。最后再说一个小技巧如果你是在真实设备上跑这个程序记得给QB0的MOVE指令加上EN条件只在“运行标志M0.0为真”且“延时完成标志M0.1为真”时才执行输出映射。否则会发生什么上电瞬间MB20虽然被OB100清零了但QB0还是在MOVE指令的驱动下持续被写入0虽然输出是灭的但如果你外接的是继电器继电器线圈相当于一直被吸合再释放寿命会受影响。加一个EN使能保证程序启动之前不碰输出既安全又延长设备寿命。这一点是很多教科书里不会写但现场老师傅一定会叮嘱你的细节。