
简介《欧姆龙ST编程中文手册》面向刚接触欧姆龙PLC的电气工程师、自动化专业学生及现场调试人员以CX-Programmer 6.1为软件环境系统讲解ST语言与功能块编程的入门知识帮助读者解决结构化文本语法不熟、功能块调用与变量定义不清等实际问题。手册从功能块这一基础单元讲起区分基本功能块与高级功能块并延伸到变量声明、功能块转换为库文件、技术规格与功能块限制等章节编程指导部分覆盖编程环境设置、赋值语句、条件与循环语句等基本语法注意事项部分则单独列出安全规范以及设备选型、安装和调试中的要点。压缩包内为1个PDF文件约2.26MB单册结构完整、目录层级清晰既可从头通读也便于调试时按功能块类型快速查阅。目前已有7329人学习适合作为入门指南和日常参考手册使用。1. 先说说这份手册到底是什么一份写给零基础的 ST 编程地图很多人第一次接触 PLC 编程是被一句“用 ST 写”劝退的。梯形图还能看出个所以然ST 一上来就是:、IF、CASE像突然换了一门语言。这份欧姆龙 ST 编程中文手册解决的正是这个卡点它把功能块、变量、数据类型这些绕不开的概念按“先认识、再动手、后避坑”的顺序摊开讲还把编译报错、下载风险、数组长度不匹配这类容易栽跟头的地方单独拎出来提醒。它是写给零基础或者只写过梯形图的人看的不要求你先懂计算机原理也不要求你会 C 语言。整份材料的主线其实很简单先搞明白一个功能块是由哪几块拼起来的再照着一个最小例子敲一遍最后知道哪几个地方不能乱碰。2. 为什么要学 ST梯形图写不下去的那一天就是它上场的时候2.1 梯形图的天花板三类活儿它干得很别扭梯形图这套东西本质上是从继电器控制柜搬过来的。左边一条母线右边一条母线触点串并联能流从左流到右线圈得电。会看电路图的人一眼就能看懂这是它最大的优点也是它几十年不倒的原因。但优点同时也是边界——它能表达的东西基本停留在“哪个开关通了、哪个线圈亮了”这个层级。一旦活儿超出这个层级梯形图就开始别扭了。最常见的三类第一类是数值运算。举个例子八个温度传感器取平均值再做滑动滤波超限报警。梯形图得写八条加法指令累加再一条除法再两条比较中间还得占好几个数据寄存器。一整屏梯形图铺下来看着很唬人其实只是算了个平均数。ST 里这件事一行就完了Avg : (T1 T2 T3 T4 T5 T6 T7 T8) / 8.0;想改成十个传感器改一行。梯形图就得再插两条指令、重排一片触点。第二类是复杂条件组合。比如某台设备的启动条件是处在自动模式并且 A 工位到位或者 B 工位到位并且液压在正常区间并且没有任何报警并且上一次停机已经超过三秒。这个条件用梯形图表达就是一大片串并联中间还常常要借一堆中间继电器来“过渡”一下因为这些条件没法一口气连起来。过两个月你回来看这段程序得从头捋一遍才能想起来当初为什么这么画。ST 里就是一个IF语句条件用AND、OR、NOT和括号组合从上往下读一遍就懂。第三类是重复逻辑。一条产线二十个工位每个工位都有一套一模一样的加热控制加热、恒温、超温保护、故障复位。梯形图的做法基本只能是复制粘贴二十遍占二十份程序空间。哪天客户说恒温的死区要从 ±2 度改成 ±1.5 度你就得改二十个地方改漏一个就是一次事故。ST 的思路完全不同把这段逻辑做成一个功能块定义一次二十个工位调用二十次参数各传各的。要改逻辑只改功能块里面那一份。这三类活儿但凡你的项目里出现一类ST 就值得学。出现两类以上那就是必须学。2.2 ST 到底长什么样三段代码先感受一下概念说再多不如看一眼。下面三段都是 ST语法接近 Pascal用分号结尾赋值用:注释用(* *)或者//。第一段条件判断对应刚才说的“复杂启动条件”(* 设备启动许可判断把所有条件写在一个表达式里 *) IF AutoMode (* 自动模式 *) AND (StationA_Ready OR StationB_Ready) (* A 或 B 工位到位 *) AND (Pressure PressureLow AND Pressure PressureHigh) (* 液压在区间内 *) AND NOT AnyAlarm (* 无任何报警 *) AND StopElapsed T#3S (* 距上次停机超过 3 秒 *) THEN StartPermit : TRUE; ELSE StartPermit : FALSE; END_IF;这段代码从上往下读几乎就是中文句子的顺序。T#3S是 ST 里的时间常量写法T#后面跟时间和单位3S就是三秒。这种写法在梯形图里要靠一个定时器指令加一个比较指令拼出来在 ST 里就是一个值。第二段循环加数组对应“八个传感器求平均”(* 数组求和Sensors 是一个长度为 8 的 REAL 数组 *) Sum : 0.0; FOR i : 1 TO 8 DO Sum : Sum Sensors[i]; (* 逐个累加 *) END_FOR; Avg : Sum / 8.0; (* 求平均值 *)FOR ... TO ... DO ... END_FOR就是循环i是循环变量每次加一。数组下标从 1 开始这一点和很多通用编程语言从 0 开始不一样从梯形图转过来的人第一次写容易顺手写成 0编译能过但取到的是错位的数据。第三段状态机对应“设备有多个工序阶段”(* 用 CASE 描述工序状态机比一堆串联触点清楚得多 *) CASE Step OF 0: (* 待机 *) IF StartBtn THEN Step : 10; END_IF; 10: (* 上料 *) DoLoad : TRUE; IF LoadDone THEN DoLoad : FALSE; Step : 20; END_IF; 20: (* 加工 *) DoProcess : TRUE; IF ProcessDone THEN DoProcess : FALSE; Step : 0; END_IF; END_CASE;Step是一个整数变量每个数字代表一个工序阶段。这种写法在行业里叫状态机好处是任何一个时刻设备只可能处在某一个CASE分支里不会出现“两个工序同时被触发”的混乱。梯形图要实现同样的效果通常得靠一堆SET、RSET指令互相牵制出了问题非常难查。2.3 零基础不用先学的东西给入门减负一听到“编程语言”很多人的第一反应是“我是不是得先去学个 C 语言”。不需要。ST 的设计目标就是给做自动化的人用不是给软件工程师用。它没有指针没有内存手动管理没有面向对象那一套也不需要你懂算法复杂度。真正需要的前置知识只有三样而且写过梯形图的人基本都已经有了第一知道什么是常开触点、常闭触点。因为 ST 里IF NOT StopBtn这种写法对应的就是常闭触点的逻辑。你不理解常闭看NOT就会绕。第二知道输入输出点是什么。按钮接在哪个点、接触器线圈接在哪个点这个不说清楚程序写出来也没法落地。第三知道扫描周期是怎么回事。PLC 是循环执行的从上到下扫一遍读输入、算逻辑、写输出然后再来一遍。ST 程序也是按这个节奏跑的所以写循环的时候心里要有数这个循环每扫描一次就跑一遍别在里面塞太重的活儿。除此之外的东西都可以边看手册边补。数据类型不熟手册附录专门有一章讲。功能块没概念第一章就在讲。变量怎么定义第三章有完整流程。入门阶段最忌讳的就是“先把基础打牢再动手”因为 ST 这门东西光看不写是学不会的看三页就得动手敲一行。3. 翻开手册前先搞懂三个词功能块、变量、数据类型3.1 功能块一个装好逻辑的黑匣子只留几个插口给你功能块这个词听着唬人其实生活里到处都是。你家的洗衣机面板上就几个按钮电源、模式、启动。你按下去它自己进水、投放、转筒、排水、甩干中间怎么控制水位、怎么判断不平衡你完全不用管。这个面板就是它的“接口”里面那一套就是它的“实现”。功能块就是这么一个东西。你把一段逻辑写进去定义好“从哪几个口子进数据”“从哪几个口子出数据”然后就可以在程序里反复调用它。调用的时候你只需要管两头往里塞什么从里拿什么。中间那段逻辑写一次就够了。这份手册里对功能块的描述核心就是三个组成部分输入变量就是面板上的按钮外面把值传进来。比如一个“加热控制”功能块输入可以是设定温度、当前温度、使能开关。输出变量就是面板上的指示灯功能块把结果送出去。比如加热输出、超温报警、当前状态。内部变量就是洗衣机肚子里面那些你看不见的零件只在功能块内部使用外面碰不到。这三者的划分非常重要因为它直接决定了你写出来的东西能不能复用。新手最容易犯的毛病是把所有东西都往输入输出上挂结果功能块变成一个空壳子里面还在直接读写全局地址。这样的东西调二十次二十次互相打架。手册里还提到一个概念叫“实例”。功能块是定义实例是“按这个定义造出来的一个具体对象”。同一个功能块定义可以造出二十个实例每个实例有自己的内部变量、自己的状态互不干扰。就像同一款洗衣机买了二十台每台各自转各自的。再往下走一步功能块可以转成库文件。转成库以后换个新工程不用重新写直接把这个库挂上去就能调用。手册里专门有一节讲这个转换动作不多但对长期干活的人来说是省时间的关键一步。3.2 变量给冷冰冰的地址起一个人能看懂的名字写梯形图的时候你面对的是0.01、W0.05、D100这样的地址。程序小的时候还行程序一大你打开监控画面看到一片D区数值在跳根本不知道哪个是温度、哪个是压力。这时候就得翻注释表一页一页对。变量就是把这件事翻过来你先给地址起个名字之后写程序全用名字。D100从此叫CurrentTemp0.01从此叫StartBtn。程序读起来就是一句话。变量大致分这么几类入门阶段搞清楚它们的区别就够了变量类型在哪里定义谁能用典型用途内部变量功能块内部只有这个功能块自己中间计算结果、计时器、边沿标志输入变量功能块接口外面传进来里面读按钮状态、设定值、使能信号输出变量功能块接口里面写外面读输出线圈、报警标志、状态码外部变量全局范围多个程序共用和其他程序块交换数据、对接触摸屏全局符号全局范围整个工程可见物理 I/O 点、系统公共信号这份表格不用背写两三个功能块自然就记住了。真正需要注意的是最后两行。外部变量和全局符号的区别是新手最容易糊在一起的地方全局符号是“整个工程都能看见的名字”外部变量是“这个功能块愿意跟外界交换的那几个口子”。一个功能块可以访问很多全局符号但它只应该通过输入输出和外部变量跟外面打交道这样它才是一个干净的黑匣子。3.3 数据类型和 AT 设定新手最容易在这一步懵PLC 里的数据不像数学里那样只有“数”它分好几种类型每种占的地方不一样能表示的范围也不一样。写 ST 的时候类型不匹配编译直接报错这是新手遇到的第一批红色错误。数据类型占位能表示什么常见场景BOOL1 位TRUE / FALSE按钮、线圈、报警标志WORD16 位0 到 65535按位看也行状态字、位组合INT16 位-32768 到 32767温度、压力等有符号量UINT16 位0 到 65535计数、序号DINT32 位大范围整数累计产量、时间戳REAL32 位浮点数平均值、比例计算STRING若干字字符串配方名、设备编号看这张表的时候记住一句话就行整数和浮点数别混着算。Avg : Sum / 8;如果Sum是整数除完小数点后面直接没了。写成8.0编译器才会按浮点数算。这一条不注意程序不报错但结果永远是错的而且错得很隐蔽。另一个新手绕不过去的东西叫 AT 设定。说白了就是“把这个变量钉死在某个物理地址上”。比如你定义了一个变量叫MotorOutputAT 设定成0.00那么这个变量一变 TRUE物理输出点 0.00 就真的输出电压了。没有 AT 设定这个变量就只是一个内存里的名字跟外界没有任何关系。什么时候必须用 AT 设定三种情况。一是要对接实际的输入输出点比如按钮、接触器、指示灯。二是要跟触摸屏、上位机交换数据人家按地址来读写的。三是某些指令要求操作数必须落在连续的地址上你得用 AT 把它固定住否则编译过不去。手册里屡次强调“指定多个字的首地址或末地址时必须用 AT 设定”说的就是这个第三种情况。这句话第一次看很难懂等你写到涉及数据块搬移的指令时编译报错会把你逼回来重读一遍那时候就懂了。4. 第一个 ST 例子从新建功能块到跑通一段启停逻辑4.1 动手前的三样东西先说清楚要准备什么不然后面每一步都卡。第一是编程软件。手册对应的是 CX-Programmer 6.1 这个版本功能块相关的操作都在这个版本里。版本不对菜单长得不一样照着做会找不到地方。软件装好之后建议先随便建个空工程点一遍菜单把“工程树”“功能块”“变量表”这几个面板的位置记住这是后面所有操作的坐标系。第二是目标 CPU 型号。手册覆盖的是支持功能块的那几个系列包括 CS/CJ/CP 系列的一部分型号。你手上如果没有实物也不影响学前面几步——建工程、写功能块、编译——纯离线就能做完编译通过就说明语法没问题。真正要下载到设备的时候才需要型号对得上。第三是一个明确的小目标。不要一上来就想写整台设备的程序那是给自己找挫折。第一个例子就定一个小目标写一个带延时确认的启停控制按启动按钮两秒后电机才转按停止立刻停。这个逻辑够小小到能一次看懂又够完整完整到能覆盖输入、输出、定时器、条件判断四件事。4.2 建立功能块并写第一段 ST 代码在工程树里新建一个功能块给它起个名字比如MotorStartStop。然后打开变量表按下面这张表把变量敲进去。变量名方向数据类型说明StartBtn输入BOOL启动按钮按下为 TRUEStopBtn输入BOOL停止按钮常闭未按下为 TRUEConfirmTime输入TIME启动确认延时例如 T#2SMotorRun输出BOOL电机运行输出StartTimer内部TON启动延时定时器StartEdgeOld内部BOOL上一周期的按钮状态用来取边沿变量定义完切到代码编辑区把下面这段敲进去(* 第一步取启动按钮的上升沿长按不会反复触发 *) StartEdge : StartBtn AND NOT StartEdgeOld; StartEdgeOld : StartBtn; (* 第二步上升沿来了就开始计时PT 由外部传入 *) StartTimer(IN : StartEdge, PT : ConfirmTime); (* 第三步计时到并且停止按钮没有被按下才允许运行 *) IF StartTimer.Q AND StopBtn THEN MotorRun : TRUE; END_IF; (* 第四步停止按钮断开常闭点动作立刻复位优先于启动 *) IF NOT StopBtn THEN MotorRun : FALSE; END_IF;逐段说一下这段代码在干什么别只是抄。第一步是取边沿。StartEdge : StartBtn AND NOT StartEdgeOld;这一行的意思是这一周期按钮是 TRUE上一周期是 FALSE两个条件同时成立说明按钮刚刚被按下去。为什么要这么写因为 PLC 是循环扫描的你按住按钮不放每一个扫描周期读到的都是 TRUE。如果直接拿StartBtn去启动程序每个周期都在“启动”虽然结果看起来差不多但一旦后面接了计数器或者触发型指令就会疯狂累加。取边沿是 ST 里最常见的自保手段血泪经验级别的习惯。第二步调用定时器。StartTimer(IN : ..., PT : ...)这种写法叫“功能块调用带参数赋值”括号里用:给输入参数传值用.Q读输出。IN是使能为 TRUE 时开始计时PT是设定时间。ConfirmTime的类型是TIME调用方传T#2S就是两秒。为什么启动要延时确认现实里按钮抖动、干扰、误碰都很常见加两秒确认能挡掉一大半误启动。第三步和第四步是两个独立的IF不是一个IF ... ELSE。为什么拆开因为停止必须优先。如果把启动和停止写在一个IF ... ELSE里某些边界情况下停止条件成立时启动分支可能还在执行输出会被重新拉高。拆成两段先判断启动、再判断停止停止永远在后面执行天然具有最高优先级。这个写法不优雅但极其稳。4.3 编译、下载与在线监控代码敲完点编译。编译窗口会给你两类反馈错误和警告。错误必须清零警告要看内容。常见的错误有三类。一是类型不匹配比如给BOOL变量赋了个整数。二是变量没定义就用了多半是变量表里拼错了名字。三是操作数长度不对这个下一章专门讲。看到错误列表别慌双击错误条目一般能跳到出错那一行从那一行往上往下各看三行问题基本就在附近。编译通过之后如果手上有设备就可以下载。下载这一步有几个动作要留心。第一确认 CPU 处在可写的状态不在运行锁定的模式里。第二如果程序里有功能块下载过程和普通程序一样但要注意“包含功能块的任务”在某些情况下不能单独下载到任务单元里这时候得整体下载。第三下载完成后如果设备执行了备份面板上的备份指示灯会亮灯亮着的时候千万别断电断了这次备份就废了。在线监控是学习阶段最有价值的一步。把MotorRun、StartTimer.Q、StartEdge这三个变量挂到监控窗口然后按按钮。你会亲眼看到按下按钮StartEdge闪一下变 TRUE 又变回 FALSEStartTimer.Q在两秒后变 TRUEMotorRun跟着变 TRUE。松手之后StartEdge是 FALSE但MotorRun保持住了。这一套看下来比读十页书都管用因为扫描周期这个抽象概念第一次变成了你能看见的东西。4.4 把功能块转成库文件下次直接拖出来用第一个功能块跑通之后做一件小事把它存成库文件。动作不复杂在功能块上右键找到库相关的选项把它注册进去然后新建一个工程试试能不能直接调用出来。为什么要专门做这一步因为这是“写一次、用一辈子”的起点。你现在写的这个启停功能块改一改就能变成十种设备都能用的通用件。等你手上攒了十几个这样的库新项目开工的时候很多基础逻辑根本不用重写拖出来填参数就行。很多人干了几年还在每个项目里复制粘贴梯形图区别就在这里。存库的时候有个小习惯值得养成给功能块写一段说明写清楚每个输入输出的含义、取值范围、有什么前提条件。不用写得多正式几句话就行。三个月后你自己回来调用会感谢当时的自己。5. 新手避坑五个最容易翻车的地方5.1 编译期就拦下你的两个坑坑一数组元素数量和指令要处理的长度对不上。现象编译直接报错提示操作数长度不匹配但你看着变量表觉得明明定义对了。原因ST 里很多指令是按“处理几个字”来工作的比如某个指令要处理 16 个字的数据你的数组只定义了 10 个元素。编译器一算长度不够拦下来。反过来如果长度是由另一个变量动态给出的编译器算不出来这时它不报错只给一条警告。解决把数组长度和指令要求对齐。固定长度的场合元素数量必须完全相等不固定长度的场合数组元素数量必须大于或等于可能用到的最大长度。看到警告别当没看见警告在这类问题上往往是最后一次提醒。坑二输入参数里直接敲了个数字结果被当成地址。现象你给某个输入参数填了20本来想传数值 20运行结果完全不对。原因在参数输入框里纯数字会被解析成 CIO 区的地址20就是地址0020那个地址里当前存的是什么传进去的就是什么。手册里专门写了这一条但第一次遇到的人基本都会中招。解决输入纯数值必须加前缀。20表示十进制常数#20表示十六进制常数正负号也可以。养成习惯只要是想传数就先敲。地址是地址数值是数值这两者在输入框里长得太像了。5.2 在线操作最容易出事的两个动作坑三在线编辑的时候顺手改了程序结果输入信号读不到了。现象设备正在跑你在线上改了一小段逻辑改完发现某个输入点怎么都不响应了。原因在线编辑会改变扫描周期。周期一拉长本来能捕捉到的短脉冲信号就可能整个被跳过。这不是程序写错了是时序变了。解决在线改程序之前先想清楚这段逻辑对时序敏不敏感。涉及高速输入、短脉冲捕捉、精确定时的部分不要在线上改停机改。手册里明确写了“仅在确认周期时间的延长不会造成不良影响之后再进行在线编辑”这句话不是客套。坑四监控窗口里手滑按了强制置位或强制复位。现象监控着好好的某个输出突然一直亮着程序里怎么改都不灭。原因强制置位/复位是直接改写存储器状态优先级高于程序逻辑。你按下去的那一下程序就管不住这个点了。更要命的是如果这个点接的是接触器线圈设备会真的动起来。解决监控之前先确认安全尤其是手放在键盘上的时候。强制功能用完立刻取消别留着。多人协作的现场强制状态最好口头交接一句这是最基本的规矩。5.3 那个不报错但会咬人的坑坑五长度不匹配导致的静默越界读写。现象编译通过警告可能只有一条甚至没有程序跑起来偶尔出怪事某个不相关的变量莫名其妙被改了值。原因这是最阴的一个。当指令要处理的长度由另一个变量动态给出时编译器不会逐值检查。假设指令要处理 16 个字你的数组只注册了 10 个元素指令就会老老实实往后读/写 6 个字——而后面那 6 个字很可能是别的变量正在用的地方。它不报错它只是把别人的数据踩了。解决凡是涉及“由变量指定长度”的指令写完必须自己核一遍数组元素数量是不是一定大于等于可能传入的最大长度。核不出来就把长度固定死写成常量让编译器帮你把关。手册里对这条的措辞很重提到可能引起严重事故不是吓唬人。6. 接下来学什么从“能编译”到“能交付”的三步第一个功能块跑通之后最容易走的两条歪路一条是就此停住另一条是一头扎进手册附录从头看到尾。都不太好。比较省力的走法是这样三步。第一步把功能块用熟先不求写得多。找三个你现场真实存在的小逻辑各写成一个功能块一个延时启停、一个报警锁存、一个简单的模拟量上下限判断。三个就够。写的时候强迫自己遵守两条规矩——内部变量不许直接读写全局地址所有对外交互都走输入输出。这两条守住了你写出来的东西才可能被别人复用。这一步大概花一周的业余时间。第二步把数据类型和数组吃透。这是分水岭。很多人 ST 写了大半年一遇到数组和长度就绕道走结果永远只能写单点的逻辑。手册附录里的数据类型那一章配合第 2 章的技术规格一起看重点看“功能块限制”和“指令支持和操作数限制”这两节它们告诉你在什么情况下会撞墙。看完之后回头改你第一步写的那三个功能块把里面所有硬编码的数字改成参数把所有可能变长的数据改成数组。第三步学着读别人的程序结构。找一份现成的、带功能块的工程不要看它实现了什么只看它的组织方式功能块怎么分层哪些是通用件、哪些是专用件外部变量是怎么规划的。这个阶段看的不是语法是结构。结构看懂了你自己写的东西才会开始有“骨架”。阶段时间投入判断自己过关的标准用熟功能块约一周能独立写出三个可复用的功能块内部不碰全局地址吃透类型与数组约两周看到长度相关的编译警告能立刻判断是哪里出的问题读懂程序结构持续拿到一份陌生工程能在半小时内说清它的功能块分层最后说个我自己的教训。刚开始写 ST 那阵子我特别迷信“能跑就行”变量名随手起功能块里直接读写全局地址编译过了就当完事。结果半年后那个项目要扩产工位从八个加到二十个我打开自己写的程序发现所有逻辑都是硬编码的一行都复用不了最后只能重新写一遍。从那以后我每次新建功能块都强制走一遍那两条规矩先定接口再写逻辑内部绝不碰全局地址。慢是慢了一点但再也没返工过。希望帮到你。本文还有配套的精品资源点击获取