CodeSys_3.5学习
1、CodeSys简介:
CodeSys官网:CODESYS-标准IEC61131-3控制器开发平台软件
CodeSys PLC Control是为PLC设计的一种完整的开发环境。CodeSys PLC Control为PLC编程提供了一种简便的方法,可以自由地处理功能强大地IEC语言。编辑器和调试功能地使用则基于先进编程语言和已验证地程序开发环境。
①、项目组件:
一个项目包含一个PLC程序中地所以对象。项目保存在项目后期命名地一个文件内。一个项目包含以下对象:
POU(程序组织单元),数据类型,资源和软件库。
POU(程序组织单元)
1、功能、功能块和程序都是POU,它们可以使用动作(Action)加以补充。
2、每个POU都由一个声明和程序主体组成。程序由IEC编程语言中的一种语言编写(这些语言包括IL(指令表)、ST(结构化文本)、SFC(顺序功能图)、FBD(功能块图)、LD(梯形图)或CFC(连续功能图)),CodeSys PLC Control支持所有的IEC的标准POU。如果你需要在项目中使用这些POU,则必须在你的项目中包含这些标准库(Standdard.lib)。
3、一个POU可以调用其他POU。然而不允许进行递归调用。
②、功能:
1、 一个功能即是一个POU,当对他进行处理时,它可以准确的生成数据元素(诸如由几个字段或结构等元素组成),并在文本语言调用时作为表达式内的一个操作符出现。
2、当声明一个功能时,不要忘记功能必须返回一个类型。这意味着,在功能名后,必须输入一个冒号,后跟一个类型。
一个正确的功能声明如下:FUNCTION Fct :INT 。 此外,必须对功能分配一个结果。这意味着,功能名作为一种输出变量使用。
③、功能块实例:
1、可以创建一个功能块的拷贝或实例(复制)。每个实例都具有器自身的标识符(实例名),以及包含有输入、输出和内部变量的数据结构。实例可以作为本地全局变量加以声明,而功能块名是作为标识符类型予以指示的。
2、
注:
1、在学习CodeSys的时候一定要分清这是一个已经搭建好的平台,类似于Linux系统移植一样,有很多的库API可供直接调用;
2、在CodeSys中也需要命名一个main的PRG来作为程序入口,有次仅有一个;
3、CodeSys相对于C语言来说,其中所创建的每一个PRG、FUN等都类似于C语言中的一个函数,代表的是某一个功能;
4、在CodeSys中对于引脚的定义已经在IDE中做好了处理,不需要像使用STM32一样去控制寄存器进行操作,在INPUT和OUTPUT两个文件中包含着对所有引脚的定义(不过这两个文件需要CodeSys扫描的所支持的PLC后才能进行添加,个人推测原因是在于CodeSys实际上是根据不同的硬件版本而进行定制化的一种开发环境的原因)
ST
结构化文本是一种高级的文本语言,可以用来描述功能,功能块和程序的行为,还可以在顺序功能流程图中描述步、动作和转变的行为。
程序执行顺序
使用结构化文本的程序执行顺序根据“行号”依次从上至下开始顺序执行;
表达式执行顺序
表达式中包括操作符和操作数,操作数按照操作符指定的规则进行运算,得到结果并返回。操作数可以是变量、常量、寄存器地址、函数等;
如果在表达式中有若干个操作符,则操作符会按照约定的优先级顺序执行:先执行优先级最高的操作符运算,再顺序执行优先级低的操作符运算。如果在表达式中具有优先级相应的操作符,则这些操作符按照书写顺序从左至右执行。
操作符优先级 | ||
操作符 | 符号 | 优先级 |
小括号 | () | 最高 |
函数调用 |
Function name (Parameter list) |
|
求幂 | EXPT | |
取反 | NOT | |
乘法 除法 取模 |
* / MOD |
|
加法 减法 |
+ - |
|
比较 | <,>,<=,>= | |
等于 不等于 |
= <> |
|
逻辑与 | AND | |
逻辑异或 | XOR | |
逻辑或 | OR | 最低 |
注:取模运算是求两个相除的余数。(https://blog.csdn.net/qq_51026595/article/details/120312458)
取模运算和取余运算两个概念有重叠的部分但又不完全一致。主要的区别在于对负整数进行除法运算时操作不同。取余主要是用于计算机术语中。取余则更多是数学概念。
计算公式:求整数商:c = a / b;
计算模或者余数:r = a - c * b;
求模运算和求余运算在第一步:求余运算在取c时,向0方向舍入(向上取整);而取模运算在计算c的值时,向负无穷方向舍入(向下取整)。
例如:计算 -7 MOD 4
那么 a = -7 ,b = 4;
如是取模运算则得c = -2(向下取整);如是取余则c = -1(向上取整)代入公式得:取模时r = 1,取余时r = -3;
结构化文本语句表 | ||
指令类型 | 指令语句 | 举例 |
赋值语句 | := | bFan := TRUE; |
功能块/函数调用 | 功能块/函数调名(); |
|
选择语句 | IF |
IF<布尔表达式> THEN <语句内容> END_IF |
CASE | ||
迭代语句 | FOR | |
WHILE | ||
REPEAT | ||
跳转语句 | EXIT | |
CONTINUE | ||
JMP | ||
返回语句 | RETURN | |
NULL语句 | ; |
1、赋值语句
赋值语句是结构化文本中最常用的语句之一,作用是将其右侧的表达式产生的值赋值给左侧的操作数(变量或地址),使用":="表示(CodeSys中将其称之为“海象符”)。
<变量> := <表达式>;
示例:分别给两个布尔型赋值;
VAR
bFan : BOOL;
BHeater : BOOL;
END_VAR;
bFan := TRUE;
bHeater := TRUE;
2、函数及功能块调用
功能块调用采用将功能块名进行实例化实现调用,如Timer为TON功能块的实例名,具体格式如下:
Timer : TON;
如果需要在ST中调用功能块,可直接输入功能块的实例名称,并在随后的括号中给功能块的各参数分配数值或变量,参数之间以逗号隔开;功能块调用以分号结束;
例如在结构化文本中调用功能块TON定时器,假设其实例名为TON1,具体实现如下所示:
PROGRAM POU_1
VAR
TON1 : TON;
END_VAR
TON1(IN:= , PT:= Q => , ET =>);
3、选择语句
1、IF语句
用IF语句实现单分支选择结构,基本格式如下:
IF<布尔表达式> THEN <语句内容>; END_IF
如果使用以上格式,值有当<布尔表达式>为TRUE时,才执行语言内容,否则不执行IF语句的<语句内容>。语句内容可以为一条语句或者可以为空语句,也可以并列多条语句。
示例:使用PLC判断当前温度是否超过了60摄氏度,如果超过,始终打开风扇进行散热处理,具体代码实现如下:
VAR
nTemp : BYTE;
bFan : BOOL;
END_VAR
nTemp := 80; IF nTemp > 60 THEN bFan := TRUE; END_IF
FOR循环
INT_Var:INT; FOR <INT_Var> := <INIT_VALUE> TO <END_VALUE> {BY<stepsize>} DO <instructions> END_FOR;
只要计数器<INT_Var>不大于<END_VALUE>就一直执行<Instructions>。这在执行<Instructions>之前进行检查,以便在<INT_VALUE>大于<END_VALUE>时不执行<Instructions>。当执行
<Instructions>时,<INT_Var>总是增加<stepsize(步长)>.步长可以是任何整数值。若没有给定这个值,则它设置为1.由于<INT_Var>只会逐步变大,因而循环也必须结束。
示例:
FOR counter := 1 TO 5 BY 1 DO Var1 := Var 1* 2; END_FOR;
WHILE循环
可以像FOR循环那样使用WHILE循环,其区别是,后者的终止条件可以是任何布尔表达式。这意味着可以指定条件,当条件满足时就可以执行循环。
语法:
WHILE<Boolean expression> DO <instructions> END_WHILE;
只要<Boolean expression>返回TRUE,就重复执行<Instructions>。如第一次求值时<Boolean expression>已经是FALSE,则不会执行<Instructions>。若<Boolean expression>从不出现
值FALSE,则<Instructions>将无休止的重复,并导致一个相应的死循环
REPEAT循环
REPEAT循环与WHILE循环不同,这是因为前者只是循环已完成后才检查终止条件。
REPEAT <Instructions> UNTIL<Boolean expression> END_REPEAT;
直到<Boolean expression>返回TRUE为止,一直执行<instructions>。如果在第一个TRUE求值时已经生成<Boolean expression>,则只执行一次<Instructions>.
若<BooLean expression>从不出现值TRUE,则<Instructions>将无休止的重复,并导致一个相应的死循环。
EXIT指令
若在FOR、WHILE或REPEAT循环中出现EXIT指令,则与终止条件无关,结束最内层的循环。
数据类型
当编程时,你可以使用标准类型和用户定义的数据类型,分配给数据类型的每个标识符将指示保留多少储存空间和保存什么类型的数值。
不同的数据覆盖不同的数值范围。如果使用的类型转换是从较大类型到较小类型,则可能丢失信息。
类型 | 上限 | 下限 | 占用内存(Bit) | 备注 |
BOOL(布尔) | 8 | |||
BYTE(整型数据类型) | 0 | 255 | 8 | |
WORD(整型数据类型) | 0 | 65535 | 16 | |
DWORD(整型数据类型) | 0 | 4294967295 | 32 | |
SINT(有符号(短)整型数据类型) | -128 | 127 | 8 | |
USINT(无符号(短)整型数据类型) | 0 | 255 | 8 | |
INT(有符号整型数据类型) | -32768 | 32767 | 16 | |
UINT(无符号整数据类型) | 0 | 65535 | 16 | |
DINT(有符号的整型数据类型) | -2147483648 | 2147483647 | 32 | |
UDINT(无符号的整型数据类型) | 0 | 4294967295 | 32 | |
REAL(32位浮点型数据类型。需要表述成有理数) | 32 | |||
LREAL(64位浮点数据类型。需要表示成有理数) | 64 | |||
TIME(时间以ms表示,并在内部作为DWORD进行处理) | 32 | |||
TOD(一天中的时间,以秒表示,并在内部作为DWORD处理) | 32 | |||
DATE(日期在内部作为DWORD进行处理,最高位表示1秒) | 32 | |||
DT(日期和时间,最高位表示1秒。数据类型在内部作为DWORD进行处理) | 32 | |||
STRING
一个字符串型的变量可以包含任何字符串。在声明中有关其大小的输入项确定了该变量应保留多少内存空间,它对应于字符串中的字符个数,并可置于括弧或方括号内。
有35个字符的字符串声明示例:
str : STRING(35) := 'This is a String';
类型 占用内存:
STRING 如果没有指定大小,则使用默认值,即80个字符:内存使用[字节数]= 80 + 1个由于结束字符串的NULL字符;
如果指定了大小:内存使用[字节数]= 字符串大小 + 1个用于结束字符串的NULL字符;
数组
一维、二维、三维字段是被作为所支持的基本数据类型。数组可以在POU的声明部分和全局变量表中定义。
语法:
<Field_Name>:ARRAY[<LowLim1>..<UpLim1>, <LowLim2>..<UpLim2>] OF <elem Type>
初始化数组
arr1 : ARRAY[1..5] OF INT := 1,2,3,4,5; //一维 arr2 : ARRAY[1..2, 3..4] OF INT := 1,3(7);(*1, 7 ,7 , 7的缩写形式*) //二维 arr3 : ARRAY[1..2, 2..3, 3..4] OF INT := 2(0), 4(4) ,2 , 3;(* 0, 0, 4, 4, 4, 4, 2, 3的缩写形式*) //三维
机构中的数组初始化示例:
TYPE STRUCT1 STRUCT p1 : int; p2 : int; p3 : dword; END_STRUCT; ARRAY[1..3]OF STRUCT1 := (p1 := 1, p2 :=10, p3 := 4723) , (p1 := 2, p2 := 0, p3 := 299), (p1 := 14, p2 := 5, p3 := 112);
数组的部分初始化示例:
arr1 : ARRAY[1..10] OF INT := 1,2;
没有预置的数组成员,则使用其基本类型的默认初始化进行初始化。在上例中,数组成员arr1[3]到arr1[10]均被初始化为0.
二维数组的数组成员使用一下语法:
<Field_Name>[Index1, Index2]
指针
当程序运行时,变量或功能块的地址保存在指针中,使用下面的语法声明指针:
<identifier> : POINTER TO <Datatype/Functionblock>;
指针可以指向任何数据类型,或功能块,甚至是用户定义的·数据类型。Address operator(地址运算符)ADR的功能是将一个变量或功能块的地址分配给一个指针;
通过在指针标识符后添加内容运算符 “^” 可以提取指针内容值。借助于SIZEOF运算符可以对指针进行增量运算;
示例:
pt : POINTER TO INT; var_int1 : INT := 5; var_int2 : INT; pt := ADR(var_int1); var_int2 := pt^;
枚举(ENUM)
枚举是用户定义的数据类型,它由一定数量的字符串常数组成。这些常数作为枚举值。在整个项目中均可识别枚举值,即使它们是在一个POU中作为本地声明。最好在对象
管理器的数据类型属性页中,将枚举值作为对象创建。他们以关键字TYPE开始,并以END_TYPE结束;
TYPE<Identifier> : (<Enum_0>, <Enum_1>...<Enum_n>); END_TYPE
结构(STRUCT)
在对象管理器(Object Organizer)的数据类型(Data Types)属性页中,结构作为对象进行创建。并使用关键字TYPE开始,END_TYPE结束。结构声明的语法如下:
TYPE<Structurename>: STRUCT <Declaration of Variables 1> . . <Declaration of Variables n> END_STRUCT END_TYPE
<Structurename>(结构名)是可以在整个项目中识别的一种类型,并可以像标准数据类型一样使用。允许结构内部联锁。唯一的限制是变量不能防止地址符(不允许使用AT声明)
定义Polygonline(多边形线)的结构示例:
TYPE Polygonline: STRUCT Start :ARRAY [1..2] OF INT; Point1 :ARRAY [1..2] OF INT; Point2 :ARRAY [1..2] OF INT; Point3 :ARRAY [1..2] OF INT; Point4 :ARRAY [1..2] OF INT; END_STRUCT END_TYPE
使用以下语法,可以操作结构成员:
<Structurename> . <componentname>
参考类型(别名)
可以使用由用户定义的派生数据类型,为变量、常量或功能块创建一个可供选择的名称。可以在对象管理器的数据类型属性页中,
将你的参考类型值作为对象进行创建。该参考值以关键字TYPE开始,以END_TYPE结束。
语法:
TYPR <Identifier> : <Assignment term>;
END_TYPE
子范围类型
子范围数据类型,是一种数据类型,其数值范围只是其基本类型的一个子集。它可以在数据类型属性页中进行声明,但一个
变量也可以使用子范围数据类型直接声明。
声明语法:
TYPE <Name> : <Inttype>(<ug>..<og>)END_TYPE;
类型说明:Name必须是一个有效的IEC标识符 , Inttype是数据类型SINT ,USINT, INT, UINT, DINT, UDINT, BYTE, WORD, DWORD之一
ug是一个常数,必须兼容基本类型,并作为子范围类型的下边界; og是一个常数,必须兼容基本类型,并作为子范围类型的上
边界;
示例:
1 TYPE SubInt : INT (-2000..2000); END_TYPE
1 (*声明一个子类型的变量:*) Data0 : SubInt; (*或者*) Data0 : INT(1..5);
数值操作符
1、ABS (返回一个绝对值)
本文来自博客园,作者:伽椰子真可爱,转载请注明原文链接:https://www.cnblogs.com/jiayezi/p/15524109.html