做这套“单部四层,基于西门子1200博图v15.1版本,可直接仿真运行”的电梯程序,前后断断续续折腾了两周时间。视频里那段画面不是剪辑效果,也不是拿实物PLC拍的,就是在博图V15.1里把S7-1200程序和HMI画面一起下载到PLCSIM仿真器里跑出来的真实录屏。这套东西没有外接任何电气元件,纯靠软件内部的变量模拟了按钮、平层开关、门区信号和上下行接触器,适合刚入门PLC又想搞懂电梯运行逻辑的人拿来敲一遍、改一遍,也适合工控老手在没硬件的情况下快速验证控制思路。
先说清楚它能解决什么问题:四层楼单台电梯的完整控制逻辑,包括内呼、外呼、记忆召唤、顺向截停、开关门控制、楼层判断、运行方向锁定,以及仿真环境下的联调方法。和市面上那些只画个时序图、放几张梯形图截图的教学帖不同,这套程序是实打实能在PLCSIM里跑起来的。你下载到仿真器之后,可以直接在HMI画面上按楼层按钮,看电梯按调度逻辑一层一层走,门开、门关、上下行指示灯全部跟着变,整个过程和真实电梯的操作体验非常接近。
1. 一个四层电梯仿真项目的价值到底在哪?
很多人觉得四层电梯简单,外呼按钮总共才6个、内呼按钮4个、加几个限位和门区开关,用“起保停电路”拼一拼也能凑合跑。但真要把调度逻辑做到“顺路截停”“反向记忆”“相同方向优先”,再配合HMI做成人能看懂的画面,复杂度立刻上来了。这套程序表面上是电梯控制,实际上覆盖了PLC编程里最值钱的三块内容:状态机设计、数据管理和逻辑优先级排序。
1.1 这套程序解决了什么问题?
先说最核心的调度问题。电梯不是“收到哪个按钮就往哪层走”这么简单的逻辑。真实运行里,电梯在2楼往上走,这时候3楼有人按下行外呼,电梯应不应该停?按完3楼内呼之后,1楼又按了上行外呼,电梯是直接掉头还是先把3楼跑完?四层电梯虽然楼层少,但这些问题一个都不少。程序里需要把每个呼叫信号“记住”,然后按方向规则排优先级,这种“记忆召唤+方向判断”正是所有多楼层电梯的基础,也是几乎所有新人最容易写崩的地方。
其次是仿真可运行的问题。S7-1200不像S7-300/400那样随便在软件里点两下就能跑仿真,博图V15.1里的PLCSIM对程序写法有隐性要求。比如某些用真实硬件中断组织的程序、某些直接访问输入映像区的写法,在仿真里就会踩坑。这套程序从结构上就按“可仿真优先”来设计,变量全部走DB块和M区,输入输出通过统一的变量映射,保证你在没有任何硬件的情况下能把整个流程跑通。
1.2 为什么组合是S7-1200 + 博图V15.1
选S7-1200而不是200 Smart或者1500,主要是三个原因。第一,1200的指令集在博图V15.1里已经非常完整,数组、结构体、SCL、定时器、计数器全都有,足够实现复杂调度;第二,1200的仿真资源占用很轻,普通笔记本就能带得动PLCSIM加HMI仿真两个进程;第三,1200在当下中小型设备里保有量非常大,读者学完这套逻辑,很容易迁移到实际项目里。
至于博图V15.1这个版本,说实话不是最新的,但目前是兼容性最稳的版本之一。V16、V17甚至V18、V20、V21都有,但越新的版本对电脑配置要求越高,而且工程文件格式一旦升级就回不去了。V15.1能打开几乎所有老项目,也能被后续高版本直接打开并升级,加上网上关于V15.1的安装、破解、外设驱动的资料非常多,遇到问题基本都能搜到答案,所以拿它做教程工程最合适。
1.3 仿真运行意味着什么
“可直接仿真运行”这几个字的分量,只有真在PLCSIM里摔过跟头的人才懂。很多程序在真实PLC里能跑,一放到仿真器里就各种问题。S7-1200的PLCSIM对硬件中断、脉冲捕捉、高速计数器的处理都和实物有差异。这套电梯程序完全抽离了物理传感器模型,用内部定时器模拟电梯运行时间,用变量强置模拟平层信号,所以仿真环境和真实逻辑完全一致。
还有一点很重要:PLCSIM是支持HMI联合仿真的。视频里那个画面,就是博图V15.1里的WinCC Runtime仿真界面,通过S7-1200 PLCSIM通讯驱动和PLC仿真进程建立连接,相当于你在电脑上同时开了一台虚拟PLC和一块虚拟触摸屏,两个进程实时交换数据。这种联调方式极其适合在项目前期验证工艺流程,尤其是电梯这种状态多的设备,你可以在仿真里把各种极端情况都试一遍,不用站在实梯旁边冒着危险测逻辑。
2. 控制系统核心逻辑与程序架构拆解
这套四层电梯程序最值得研究的不是某一行指令,而是整体架构。整个控制逻辑分为四个层次:信号采集层、目标计算层、执行决策层、输出显示层。每一层职责单一,层与层之间通过DB块交换数据。
2.1 I/O分配与变量表设计
先看输入输出规划。四层电梯的典型I/O清单如下表所示,这套程序按标准写法把输入输出点全部映射到符号表里,方便仿真时按名称强置。
| 信号类型 | 地址 | 名称 | 说明 |
|---|---|---|---|
| 输入 | I0.0 | LS_1F | 1楼平层感应 |
| 输入 | I0.1 | LS_2F | 2楼平层感应 |
| 输入 | I0.2 | LS_3F | 3楼平层感应 |
| 输入 | I0.3 | LS_4F | 4楼平层感应 |
| 输入 | I0.4 | DOOR_OPEN_LS | 开门到位 |
| 输入 | I0.5 | DOOR_CLOSE_LS | 关门到位 |
| 输入 | I0.6 | DOOR_ZONE | 门区信号 |
| 输入 | I0.7 | BTN_OPEN | 轿厢开门按钮 |
| 输入 | I1.0 | BTN_CLOSE | 轿厢关门按钮 |
| 输入 | I1.1 | SAFE_OVERLOAD | 超载保护 |
| 输入 | I1.2 | SAFE_ESTOP | 急停 |
| 输入 | I1.3 | CALL_1F_UP | 1楼上行外呼 |
| 输入 | I1.4 | CALL_2F_UP | 2楼上行外呼 |
| 输入 | I1.5 | CALL_2F_DN | 2楼下行外呼 |
| 输入 | I1.6 | CALL_3F_UP | 3楼上行外呼 |
| 输入 | I1.7 | CALL_3F_DN | 3楼下行外呼 |
| 输入 | I2.0 | CALL_4F_DN | 4楼下行外呼 |
| 输出 | Q0.0 | MOTOR_UP | 上行接触器 |
| 输出 | Q0.1 | MOTOR_DN | 下行接触器 |
| 输出 | Q0.2 | DOOR_OPEN | 开门继电器 |
| 输出 | Q0.3 | DOOR_CLOSE | 关门继电器 |
| 输出 | Q0.4 | BUZZER | 到站蜂鸣 |
这里特别注意:1楼只有上行外呼,4楼只有下行外呼,中间层各有一个上行和一个下行外呼,所以外呼按钮一共6个。很多新手画I/O表时容易把4楼写成也能上呼、1楼也放下呼,这在物理上是不存在的,虽然仿真里多两个变量不影响运行,但从专业角度是错的。
变量表设计上,我没有把所有信号都直接丢给I区Q区,而是建了一个全局数据块DB1“Elevator_Data”,里面有当前楼层、目标楼层、运行方向、门状态、各召唤数组,以及各种中间标志位。这样做的目的是让控制逻辑的“数据中枢”和“外部IO”分开。仿真时你只需要强置几个输入点,剩下的内部状态全部可以由程序自由翻转,调试体验会舒服很多。
2.2 楼层判断、召唤记忆与方向优先
楼层判断是所有电梯控制的基础。这套程序里楼层的获取方式很简单:四个平层感应开关,谁的信号有效,当前楼层就是哪层。但这里有个比较隐蔽的工程细节:电梯在两层之间运动时,所有平层信号都无效,此时必须“保持上一拍的楼层值”,不能因为平层信号全部为0就把当前楼层清零。我是用一个FC_FLOOR_CALC功能块实现的:扫描四个平层信号,只要其中某个有效就更新当前楼层,全部无效则保持原值。
召唤记忆是整个程序的核心,也是最容易写乱的地方。我的做法是在DB1里定义三个数组:
// 召唤记忆数组 VAR upCall : ARRAY[1..4] OF BOOL; // 上行外呼 dnCall : ARRAY[1..4] OF BOOL; // 下行外呼 cabCall : ARRAY[1..4] OF BOOL; // 轿厢内呼 END_VAR每个数组的下标就是楼层号,值为TRUE就代表这一层有对应方向的呼叫。当电梯响应完某一层的呼叫之后,就把对应位清零。这种“位图式”的召唤表优势非常明显:查找任意楼层是否有未被响应的召唤,只需要遍历数组元素;判断电梯是否还有任务,只需要做一次数组或运算,逻辑表达极其紧凑。
方向优先规则是电梯“智慧”的来源,我是用FC_DIRECTION_CALC来实现的。核心思路分成三步:
- 如果电梯当前没有方向(待机),从所有召唤里选出距离当前楼层最近的一层作为第一目标;
- 如果电梯当前上行,就只检索当前楼层以上的召唤,从底层往高层依次扫描,遇到第一个有效召唤就作为顺路目标;当前楼层以上的召唤全部完成之后,如果仍有当前楼层以下的召唤,电梯才掉头下行;
- 下行方向的处理正好对称。
用一句生活化的话来理解:电梯不是哪层有人就去哪层,而是在一个方向上“顺着走”,把同方向的乘客都带上,直到这个方向没有需求了,才转向反方向。这套逻辑对应到真实电梯里就是“顺向截停”和“反向记忆保留”。
2.3 开关门与安全逻辑
开关门看着简单,其实暗含了至少四个条件判断。开门条件包括:电梯处于平层状态、在门区范围内、速度为零(或者仿真里运行方向输出为False)、没有超载和急停故障。关门条件包括:超载信号无效、开门到位信号消失(即门已处于关闭过程)、没有开门按钮被持续按下、关门延时时间到。
程序里我专门做了一个FC_DOOR_CTRL,它接收来自调度模块的“开门请求”和“关门请求”信号,内部通过两个定时器实现开门延时的自动关门功能:
// 开门保持定时器:开门到位后开始计时,默认6秒后自动关门 TON_OPEN_HOLD(IN := DOOR_OPEN_LS, PT := T#6S); IF TON_OPEN_HOLD.Q AND NOT BTN_OPEN THEN doorCloseReq := TRUE; END_IF;安全逻辑方面,急停信号一旦有效,所有运行输出全部切断,包括上下行接触器、开门继电器,只保留蜂鸣器和报警显示;超载信号有效时,电梯不允许启动,并且蜂鸣器持续鸣响,HMI画面显示“超载”报警。这些在仿真环境下都能通过强置输入完整验证。
3. 在博图V15.1中完整搭建并仿真运行
前面把逻辑讲清楚了,接下来是实操环节。这一部分我会从创建工程开始,一步一步把整套程序在博图V15.1里搭起来,并且在PLCSIM里跑通。
3.1 工程创建与模块划分
打开博图V15.1,新建项目,在“添加新设备”里选择CPU。这里我选的是CPU 1214C DC/DC/DC,订货号6ES7 214-1AG40-0XB0,固件版本V4.4。1214C的I/O点数、程序块容量完全够四层电梯使用,属于1200系列里最均衡的型号。选完之后,再添加一块精简面板,我这里用的是KTP700 Basic PN,尺寸适中,仿真时分辨率也合适。
程序结构上,我把所有逻辑拆成了四个FC加一个主OB1,没有用FB,原因很简单:FC在仿真里更容易观察中间变量,而且没有背景数据块的嵌套,新手看程序时不用一层层点进去找数据。四个FC分别是:
- FC_CALL_SCAN:扫描所有输入状态,把外呼、内呼、急停、超载等信号写入DB1;
- FC_FLOOR_CALC:根据平层信号更新当前楼层;
- FC_DIRECTION_CALC:计算运行方向和目标楼层;
- FC_MOTOR_CTRL:根据方向和目标执行上下行输出、平层停止、开门请求;
- FC_DOOR_CTRL:控制开关门流程。
注意这里列了五个FC,实际工程里可以灵活合并,但功能要分开。每个FC只干一件事,出了问题能快速定位。OB1按顺序调用它们即可,这种“顺序扫描+共享数据区”的架构,和真实电梯PLC程序的模块化思路是一致的。
3.2 关键SCL逻辑实现
电梯移动在真实设备里由变频器和编码器共同驱动,但仿真环境下没有这些东西,所以我用定时器模拟楼层间运行时间。核心思路是:当电梯确定目标楼层之后,每到一个“楼层运行周期”就更新一次当前楼层,直到当前楼层等于目标楼层,然后触发平层停止。
下面这段是方向分配的核心示意代码:
// 上行方向目标搜索 i := iCurrentFloor + 1; WHILE i <= 4 DO IF upCall[i] OR cabCall[i] OR dnCall[i] THEN iTargetFloor := i; EXIT; END_IF; i := i + 1; END_WHILE; // 如果上方没有召唤,检查下方是否有召唤,有则掉头 IF iTargetFloor = 0 THEN i := iCurrentFloor - 1; WHILE i >= 1 DO IF upCall[i] OR cabCall[i] OR dnCall[i] THEN iTargetFloor := i; eDirection := -1; // 改为下行 EXIT; END_IF; i := i - 1; END_WHILE; END_IF;这个搜索逻辑覆盖了电梯最常见的场景:先满足同方向,再考虑反方向。目标楼层确定之后,电机控制模块只需要比较当前楼层和目标楼层的大小关系即可决定输出上行还是下行。到达目标层时,清空该楼层的对应召唤位,同时发出平层停车信号。
3.3 仿真调试步骤:从下载到跑通
这里应该是很多人真正卡住的地方,我把步骤写完整:
- 先编译整个项目,保证0错误0警告。博图V15.1的编译信息里如果有“程序块未完全编译”之类的警告,必须处理干净再下载;
- 点击“开始仿真”按钮,或者在“在线”菜单里选择“下载到PLCSIM”。如果还没有启动PLCSIM,博图会弹窗提示,选择“启动仿真”即可;
- 下载程序到虚拟PLC后,将PLCSIM切到RUN状态。这里要提醒一点:PLCSIM默认是STOP状态,直接测试会发现输出全部不动作,必须先点RUN;
- 打开“仿真表”,在仿真表里添加需要强制的变量,比如I0.3(4楼平层)、I1.3(1楼上呼)等。把“启用”列勾选,修改“修改值”列,然后点击“立即将所有修改值送入PLCSIM”;
- 观察程序块在线状态和输出点变化。在OB1里可以实时看到每个FC调用后的中间变量值,在“监控”模式下所有变量显示为绿色或红色状态,调试体验和真机几乎一样;
- 如果是HMI联合仿真,先在PLCSIM里把PLC跑起来,然后再点HMI画面的“开始仿真”,此时HMI运行画面会自动连接PLCSIM中的PLC。连接成功后,你在HMI上点按钮,PLC变量就会跟着变化。
视频里那个真实运行画面,就是按住HMI上的楼层按钮、观察梯形图里各个FC的状态翻转、同时录屏得到的。整个过程和真实调试的高度相似。
3.4 HMI联调:画面设计与按键变量映射
HMI画面设计这块,KTP700仿真面板上主要放了几组元素:四层楼的外呼按钮、轿厢内呼按钮、当前楼层数字显示、上下行方向箭头、门状态指示灯、急停复位按钮。
一个极其常见的坑是:HMI按钮按下去,PLC变量没反应。这通常不是程序问题,而是按钮的“事件”没有正确配置。很多新人把按钮拖到画面上就完事了,但博图里按钮默认没有任何功能,你必须在按钮的“事件”选项卡里添加一个“按”事件,并且把事件的动作设置为“置位变量”或者“取反变量”,然后再关联到DB1里的对应召唤位。
另外,HMI仿真联调还有一个顺序问题:必须先启动PLC仿真,再启动HMI仿真。如果先启动HMI仿真,再启动PLCSIM,WinCC Runtime启动了通讯就找不到S7-1200仿真PLC,结果就是HMI上所有按钮点了都没反应,或者画面上的变量显示“#####”。遇到这种“博图HMI仿真按钮无反应”的情况,先不要怀疑程序,把两个仿真器全部关掉,按“先PLC后HMI”的顺序重新启动一次,十次里有八次能解决。
4. 仿真调试中的常见问题与排查记录
写这部分的时候,我把做这个视频之前踩过的坑都翻出来。可以说,前面所有逻辑加起来,都不如这些问题浪费的时间多。
4.1 PLCSIM启动失败与运行不稳定
第一条就是PLCSIM启动失败,或者启动后程序下载不进去。在博图V15.1里最常见的现象是点击“开始仿真”后,长时间卡在“正在启动S7-PLCSIM...”然后报错。排查思路按优先级排:
- 检查杀毒软件和防火墙是否拦截了PLCSIM的虚拟网卡服务,西门子软件的许可服务、通讯服务经常被误杀,建议把博图相关进程加入白名单;
- 检查Windows帐户权限,尽量用管理员身份启动博图V15.1,PLCSIM需要访问系统级的虚拟通讯接口;
- 如果系统里同时装了多个博图版本,比如V15.1和V18共存,要留意PLCSIM版本是否冲突。V15.1的PLCSIM和V18的PLCSIM不能同时在后台驻留,启动前先看任务管理器里有没有残留的S7-PLCSIM进程;
- 如果是博图V18甚至更高版本弹出“PLC启动失败”的提示,多半是兼容性问题。V18、V20这些新版本对系统组件要求更高,很多是Windows系统补丁缺失导致虚拟机通讯组件启动异常,可以尝试以兼容模式运行软件,或者把虚拟网卡驱动禁用再启用。
4.2 定时器不走、变量不刷新类问题
在PLCSIM仿真里,定时器是需要“执行条件”的。很多人写了一段TON,仿真时发现定时器的ET一直为零,以为是程序不对,其实是输入条件从来没满足过。比如自动关门定时器,它的使能条件是“开门到位信号有效”,如果你没有在仿真表里把开门到位变量I0.4强制成TRUE,那么定时器根本不会被调用到。
还有一个更隐蔽的问题:在PLCSIM中强制的变量只作用于输入映像区,如果你在程序里使用“P“指令(上升沿)读取输入点,仿真时第一次点击按钮只能产生一个很短的扫描周期脉冲,但你在仿真表里强制的TRUE值会持续多个扫描周期,导致沿信号不触发。解决办法是使用HMI仿真界面的按钮来控制内部变量,或者在仿真表里手动模拟“先置TRUE再置FALSE”的过程,才能产生正确的上升沿。
4.3 博图版本与工程迁移的典型坑
版本问题在这类项目里几乎躲不开。V15.1工程用V16、V17打开时会提示“需要升级”,升级后你会发现旧的仿真配置可能需要重新添加,一些老的HMI画面字体和布局也可能变化。反过来,高版本工程无法用低版本打开,这个是不可逆的,所以发布工程时一定要明确标注版本。
卸载重装也是重灾区。博图V17、V18这类新版软件卸载不干净,会导致后续安装时提示“已有更高版本存在,无法继续安装”。建议卸载时先停掉所有西门子服务,再用官方卸载工具清理注册表,最后删除C盘残留目录。另外“博图有损加密”这个功能在V15.1以后很常用,它会把程序块内部逻辑隐藏,只保留接口和注释,做商业项目交付时很有用,但要注意:加密后的程序块无法再编辑源码,只能重新导入原工程,所以加密前一定备份。
4.4 常见问题速查表
我把遇到的和同行反馈较多的问题整理成一个速查表,方便对号入座:
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| PLCSIM无法启动 | 杀毒拦截/权限不足/版本冲突 | 加白名单、管理员运行、清理残留进程 |
| HMI仿真按钮无反应 | 按钮未配置事件/PLC仿真未先启动 | 检查按钮事件,按先PLC后HMI顺序重启 |
| 定时器不累计 | 使能条件不满足 | 在仿真表中强置前置条件 |
| 程序下载后输出无变化 | PLCSIM未切到RUN | 点PLCSIM工具栏的RUN按钮 |
| 无法用低版本打开高版本工程 | 版本不兼容 | 用高版本重新导出/另存为低版本格式 |
| 块被加密无法修改 | 已启用有损加密 | 删除加密块并重新导入源码 |
| 运行画面显示“#####” | HMI未建立PLC连接 | 检查PLCSIM与HMI仿真先后顺序 |
5. 从仿真到实战:还能怎么玩?
四层电梯仿真是学习路径上很典型的一站,但做完之后别急着收手,我建议按下面的方向继续扩展。
5.1 扩展到多层和群控
四层电梯的召唤数组固定是1..4,改成多层非常简单,只需要把数组上限改成实际楼层数。但楼层多了以后,方向优先算法需要处理更多边界条件:顶层和底层没有双向外呼;运行中突然插入远端呼叫;高峰时段电梯长期在中间楼层来回跑,底层乘客长时间等不到电梯。这些问题在四层机上很难暴露,一旦想明白了,对整个调度系统的理解会加深很多。
再往上就是群控。多部电梯共用一个召唤队列,需要解决“分配优先级”和“防碰撞”问题。四层单梯用PLC基本是“顺序扫描+数组遍历”就能搞定,但多梯群控就要考虑交叉通讯了。如果是在仿真环境里做群控,可以用两台S7-1200分别仿真两台电梯,PLC之间通过以太网通讯交换召唤信息和位置状态,甚至可以用UDP组播让多台PLC共享同一份召唤数据,模拟真实的群控调度逻辑。
5.2 仿真程序移植到实物设备的改造清单
如果想把这套仿真程序真正跑在实物电梯模型上,至少要补三块内容:第一,位置检测。仿真里平层信号是用变量强置的,实物上需要换成接近开关、光电开关或者旋转编码器,用高速计数或中断实时计算楼层位置;第二,安全回路。急停、超载、门锁这些在仿真里可以用布尔变量模拟,但实物上必须接成硬接线安全回路,直接切断主接触器控制电源;第三,电机驱动。1200本身不输出变频器模拟量,你需要扩展模拟量模块或者用通讯方式控制变频器,同时还要加入抱闸打开延时、启动加速斜坡这些物理特性。
改造时有一个常见的低级错误:直接把仿真程序里的楼层定时器逻辑搬到实物上。仿真里电梯“走一层”是固定2秒的定时器模拟,实物里电梯楼层距离不一样,加减速时间也不一样,再用定时器算楼层就会出错,必须换成编码器计数或传感器位置来判断。
5.3 博图里几个值得掌握的进阶技巧
做完电梯项目,博图的基本用法算是过关了,但还有几个进阶功能非常值得研究:
- AT指令覆盖视图:S7-1200的SCL里可以用AT关键字把变量强制覆盖成另一个数据类型,比如把一个字节变量映射成8个独立的Bool,这在处理电梯召唤位图时非常方便;
- 指针寻址:用ARRAY和索引变量访问召唤数组,本质上用到了间接寻址。博图里指针用法虽然比STEP7简洁,但对内存地址的直接操作仍然能帮你写出更精简的代码;
- 程序块加密与库功能:V15.1支持将写好的FC/FB封装成库,在多个项目间复用。电梯这类成熟逻辑封装成库之后,新项目只需要改I/O映射和楼层参数,开发效率会几何级提升。
最后再做几点提醒
这套四层电梯程序的完整思路和运行演示已经说明白了。我个人最大的感触是:电梯控制逻辑听起来复杂,真正拆开之后,核心就是“当前楼层、目标楼层、方向、召唤表、开关门状态”这几个变量在互相博弈,程序写的不是某一条指令,而是这些变量之间的约定。你先把状态定义清楚,再画数据流,最后再去写梯形图或SCL,整个过程会顺畅得多。
如果你也要在博图V15.1里复现这套电梯仿真,我的建议是从I/O表和变量表开始抄,先别碰程序。把每层外呼、内呼、平层信号、门区信号这些变量在DB块里全部建好,仿真表格里预先填好测试值,然后再逐段调试逻辑。遇到HMI按钮无反应或者PLCSIM启动失败这类问题,先别急着重装软件,对照速查表按顺序排查,多数情况下都是变量映射、仿真顺序这类小细节。
最后再分享一个小技巧:视频录制时,我特意把PLCSIM的“在线监控”窗口和HMI仿真画面放在同一个屏幕上,左侧是对应的梯形图触点,右侧是运行画面。这样录出来,观众既能看见电梯在跑,也能看见背后的逻辑在翻转,比单纯录一个HMI画面要有说服力得多。以后你做大项目调试记录时也可以试一试这个录制布局。