第二章:PLC基础回顾——工作原理、编程语言、数据类型与寻址方式
各位工程师朋友,大家好。这一章我们聊聊PLC的基础。我知道很多朋友觉得PLC基础太简单,直接上手干就完了。但说实话,我在现场调试伺服驱动时,遇到的大部分坑,根源都出在对PLC基础的理解不够扎实。你想想看,伺服跑飞了、位置对不上了,最后查出来往往是数据类型搞错了,或者寻址方式没搞对。所以,咱们还是踏踏实实把地基打牢。
2.1 PLC的工作原理:扫描周期与执行机制
PLC说白了就是一个循环执行的计算机。它不像我们写C语言那样顺序执行完就结束,而是周而复始地扫描。这个扫描周期,是理解一切PLC行为的基础。
一个完整的扫描周期包含三个阶段:
- 输入采样:PLC先把所有物理输入点的状态(比如按钮按没按、传感器通没通)一次性读入到内存的“输入映像区”。
- 程序执行:CPU从上到下、从左到右执行用户程序。注意,它只从输入映像区读数据,结果写到“输出映像区”。
- 输出刷新:程序执行完后,把输出映像区的数据一次性全部送到物理输出点(比如继电器、伺服使能信号)。
核心要点:PLC在一个扫描周期内,输入信号只在开始时采样一次,输出信号只在结束时刷新一次。程序执行过程中,即使外部输入变了,PLC也“视而不见”,直到下一个周期。
我在项目中遇到过这样一个问题:一个急停按钮,我用它来切断伺服使能。程序里我直接读急停的物理点,结果伺服有时能停,有时停不了。查了半天,发现是因为急停信号在程序中间被改变了,但PLC要到下一个周期才处理。后来我改成用立即刷新指令,问题才解决。嗯,这里要注意,立即刷新会延长扫描周期,别滥用。
为什么会这样?因为PLC的设计初衷是可靠性优先。它要保证在一个周期内,程序看到的输入状态是“一致”的,输出状态也是“一致”的。这和我们伺服驱动的实时性要求有时是矛盾的,联调时一定要心里有数。
2.2 常用编程语言:梯形图与结构化文本(ST)
PLC的编程语言有很多种,但咱们做伺服驱动联调,最常用的就两种:梯形图(LD)和结构化文本(ST)。
2.2.1 梯形图(LD)—— 电气工程师的“母语”
梯形图,说白了就是把继电器电路图“翻译”成PLC能懂的语言。它直观、易读,适合做逻辑控制和顺序控制。
我个人习惯,凡是涉及互锁、使能、报警这类逻辑,都用梯形图。因为一眼就能看出逻辑关系,现场调试时拿万用表一量,心里踏实。
举个例子,伺服驱动的“使能”逻辑:
// 梯形图示例:伺服使能控制
// 条件:急停未按下 & 无报警 & 启动按钮按下
// 输出:伺服使能线圈
| 急停常闭 | 报警常闭 | 启动按钮 | 伺服使能 |
|----|----|----|----|
|--||--+--||--+--||--+--( )--|
| | | | 自锁触点 |
| | | |--||--|
你看,这个逻辑用梯形图画出来,谁都能看懂。但梯形图有个缺点:处理复杂数学运算和数组时,非常痛苦。比如你要算一个S型速度曲线,用梯形图写,那代码量能让你怀疑人生。
2.2.2 结构化文本(ST)—— 高级语言的“降维打击”
ST语言,长得像Pascal或C语言。它适合做数据处理、算法实现、通讯解析。我个人建议,凡是涉及位置计算、速度规划、PID调节,都用ST写。
比如,计算伺服的目标位置:
// ST语言示例:计算绝对位置
IF bStart THEN
// 目标位置 = 当前位置 + 脉冲增量
lTargetPos := lCurrentPos + lPulseIncrement;
// 限位保护
IF lTargetPos > lMaxPos THEN
lTargetPos := lMaxPos;
bLimitAlarm := TRUE;
END_IF;
// 写入伺服驱动器
uaSetPosition(lTargetPos);
END_IF;
你看,用ST写,逻辑清晰,变量名一看就懂。而且ST支持数组、结构体、函数,写复杂控制逻辑非常方便。
我的建议:梯形图做“壳”,ST做“核”。外壳逻辑(使能、报警、模式切换)用梯形图,核心算法(位置计算、速度规划)用ST。这样既好读,又高效。
2.3 数据类型:别让“整型”和“浮点”坑了你
数据类型,是PLC编程里最容易出问题的地方。我在现场见过太多因为数据类型不匹配导致的“灵异事件”。
PLC常用的数据类型有:
| 类型 | 关键字 | 位数 | 范围 | 典型用途 |
|---|---|---|---|---|
| 布尔 | BOOL | 1位 | TRUE / FALSE | 开关信号、使能位 |
| 字节 | BYTE | 8位 | 0~255 | 状态字、小数据 |
| 整型 | INT | 16位 | -32768~32767 | 计数器、小范围位置 |
| 双整型 | DINT | 32位 | -2^31~2^31-1 | 编码器位置、大范围计数 |
| 浮点 | REAL | 32位 | ±1.18e-38 ~ ±3.4e38 | 速度、加速度、PID参数 |
避坑指南:我曾经在调试一个电子凸轮项目时,用INT类型存储编码器位置。结果运行到一半,位置突然跳变。查了一下午,才发现是编码器位置超过了32767,INT溢出了。从那以后,凡是涉及位置、脉冲数,一律用DINT。记住,伺服编码器动不动就是几百万脉冲,INT根本不够用。
还有一个常见坑:浮点数的精度问题。REAL类型只有32位,精度约7位有效数字。如果你要计算高精度的位置,比如0.0001mm级别,REAL可能会丢精度。这时候,我建议用LREAL(64位浮点),或者干脆用DINT做定点数运算。
2.4 寻址方式:找到你想要的“那个”数据
寻址,就是告诉PLC“你要操作哪个数据”。PLC的寻址方式比计算机简单,但也有一些细节需要注意。
2.4.1 直接寻址
最常用的方式。直接指定地址,比如:
%I0.0:输入点,第0个模块的第0个通道%Q1.2:输出点,第1个模块的第2个通道%MW100:内存字,地址100
直接寻址简单粗暴,但可读性差。我一般只在简单的逻辑里用,复杂程序里还是用符号寻址。
2.4.2 符号寻址(推荐)
给变量起个名字,比如 bServoEnable、lActualPosition。程序里直接用名字,PLC自动映射到物理地址。
这样做的好处是:程序可读性强,移植方便。你想想看,如果程序里全是 %MW100,三个月后你自己都看不懂。
2.4.3 间接寻址(指针)
这个在伺服联调里用得不多,但处理数组时很有用。比如你要批量读取10个轴的位置:
// 间接寻址示例:循环读取轴位置
FOR i := 0 TO 9 DO
// 通过指针访问数组元素
lPosArray[i] := uaReadPosition(pAxisBase + i * 4);
END_FOR;
注意,不同PLC的间接寻址语法差别很大,用之前一定要看手册。
2.5 知识体系总览
为了让你对本章内容有个整体印象,我画了一张图。这张图把PLC基础的核心知识点串了起来,你一看就明白它们之间的关系。
这张图把PLC基础的四个核心模块串起来了。你记住:工作原理是“骨架”,编程语言是“血肉”,数据类型是“细胞”,寻址方式是“神经”。四者缺一不可。
个人经验:每次开始一个新项目,我都会花半小时把PLC的数据类型和寻址方式先规划好。变量命名规范、数据类型选对、地址分配合理,后面写程序就像搭积木一样顺畅。如果这一步偷懒,后面调试时你会花十倍的时间来填坑。
好了,这一章的内容就到这里。PLC基础看似简单,但它是伺服驱动联调的基石。下一章,我们会正式进入伺服驱动的世界,聊聊它的内部结构和控制模式。到时候你会发现,今天讲的这些基础,全都会用上。
公众号:蓝海资料掘金营,微信deep3321