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 (返回一個絕對值)