D7功能块编程
SIMATIC D7 功能块的编程
D7功能块可以用D7-SYS Function Block Generator 软件编程并组成自己的功能库,由D7-SYS软件调用来编写FM458、SIMADYN-D及TDC用户程序。
目录
SIMATIC D7 功能块的编程 (1)
目录 (2)
D7-SYS中使用功能块库 (3)
操作系统的特性 (4)
功能块运行特性 (4)
数据连续性保证 (4)
过程映像功能 (4)
SIMATIC D7 功能块生成器: (5)
功能块编成说明 (6)
概述 (6)
功能块名称 (7)
I/O和CFC 信息 (8)
输入输出描述 (9)
关键字的值的字符序列长度和字符范围 (10)
可选数据的关键字 (11)
可选数据的关键字 (11)
FB头部的可选关键字 (11)
I/O描述中的可选关键字 (12)
输入输出和本地变量的数据类型 (13)
输入输出和本地变量的数据类型 (13)
只有本地变量才有的数据类型 (13)
I/O初始值的范围 (14)
FB运行代码 (15)
函数的定义 (15)
外部函数 (16)
在FB主函数中访问FB输入输出 (17)
在FB辅助函数中访问FB输入输出 (18)
外部模块中的函数访问FB输入输出 (19)
常数、宏和函数原形 (20)
常数 (20)
宏 (20)
FB的I/O类型转换 (20)
限制一个值的范围 (21)
设定或评估BOOL类型的FB的I/O类型 (21)
范围检查 (21)
函数原形 (22)
Malloc函数 (22)
malloc_save函数 (22)
ta_info_msec函数 (22)
get_compile_date函数 (23)
D7-SYS中使用功能块库
在安装了D7-SYS的CFC编辑器中菜单栏:Options->Block Types 中左边窗口指明在Step7目录下S7cfc\sdblocks目录中所有的功能块库。这些库由.a库文件和.msk接口说明文件组成。他们可以被导入到右边程序使用库的窗口中。导入后这些库可以在用户编程时被使用。在D7-SYS的CFC编辑器的块目录中相应的块属类(FAMIL Y)可以找到库中的功能块。当需要从用户程序中删除库时该库的任何块都不能在程序中出现,否则不允许删除。
操作系统的特性
功能块运行特性
当系统启动时自动调用功能块中初始化程序执行初始化处理。
功能块可以被配置在循环中断任务和报警中断任务中。
循环中断任务是以基本时钟的以2为底的幂为倍数的时间间隔循环调用的任务,共5个。报警中断任务是由硬件、软件或系统计数器等触发的中断任务,共8个,优先级高于循环中断任务。配置报警中断任务时需要设定其近似时间间隔,用于自动化任务估算采样时间。
数据连续性保证
配置在同一循环任务的功能块编译时被放在一起,各块间数据直接通过变量传递。不同循环任务中的各块间传递数据时,系统把这些数据存储到缓存中,在任务开始时从缓存中读入、结束时写入缓存。因此会出现T1数据传给T3时某些循环数据不能被T3接收到的情况。
过程映像功能
对于硬件输入输出数据,为了保证在循环(中断)任务中数据一致性。在任务开始时调用硬件写出读入程序,之后才进行正常的处理程序,来保证数据一致性。
综上,功能块编程可分为三部分程序:NMR()正常模式;INI()初始化模式;SYS()系统模式。
NMR()用于功能块在循环中断任务中执行的指令。
INI()用于功能块在FM458启动初始化期间执行的指令。
SYS()用于功能块在循环中断任务开始时(更新过程映像)执行的指令。
SIMATIC D7 功能块生成器:
使用SIMA TIC D7 功能块生成器你可以为D7-SYS 配置工具生成自己的功能块并把他们组合在一个库中。
注意:
SIMATIC D7 功能块生成器生成的目标码是与R3000/R4000兼容的代码。安装SIMATIC D7 功能块生成器后请不要反安装编译器程序。
功能块编成说明
概述
功能块(FB) 从定义文件生成。这些定义文件通过SIMATIC D7 功能块生成器转换成目标码和说明。
一个FB
这个文档首先提供了关于功能块的符号和他的I/O的信息。
文档还提供了I/O的格式和CFC信息及必要的和可选的输入项目的信息。
文档说明了功能块代码必须是可重复使用的,为了完成这一点,FB的I/O 和本地变量可以在FB的主函数中访问也可以从另外的FB-本地函数和从外部模块的函数访问。
文档说明了包含文件p32.h 定义用于FB的常数、宏和函数原形。
功能块名称
FB名由1至6个字符组成。
文件名:
定义文件、包含文件、临时文件和生成的文件的名字, 必须用FB名字作开头,文件名必须是小写字母。
在定义文件中的FB名:
FB名必须使用大写字母。
注释中的FB名:
没有任何限制。(大小写都可)
I/O和CFC 信息
功能块
●< >中的名字(包括尖括号本身)必须由合法字符代替。
●所有的FB的数据和定义必须放在FUNCTION_BLOCK 和END_FUNCTION_BLOCK
两个关键字中间。仅有注释可以放在关键字FUNCTION_BLOCK之前。任何放在关键字END_FUNCTION_BLOCK 后面的文本都将被忽略。
●各段数据必须由一个关键字作开头(例如COMMENT)而且必须使用大写字母。
例外:I/O(连接)的描述和本地变量不用关键字作开头。
●在{ }之间输入的数据是可选数据。某个或若干数据片段可以省略。在大括号内所有数
据都省略时{ }也可省略。
●省略的数据一般由缺省值代替。
●白空(空格、制表符、换行符)用于分隔数据的结构,因此白空不可被写在关键字、名
字、多位数字等之中。
●注释必须写在/*和*/之间(多行), 或跟在//标记之后(一行)。
●如果FB既没有I/O也没有本地变量,那么块的接口部分包括关键字VAR_INPUT、
V AR_OUTPUT 和V AR 及结束关键字END_V AR 都可以忽略。
●所有数据可以写在一行里这里没有限制,但最好每行写一个条目,这样看起来比较清晰。
●输入的字符或字符序列必须用单引号括起来。
●字符序列中的单引号前面必须加$前缀:$’,而$字符则需要写成$$。
●生产代码时,字符序列中的制表符、换行符都用空格代替。
/*
; 定义文件格式, I/O 和CFC 信息
; 模块头部
*/
FUNCTION_BLOCK
{<可选的块头参数>};
NAME_FB:<块类型名>;
RUNTIME:<在PM5上运行的计算时间1/10毫秒>;
V AR_INPUT
<输入描述>
END_V AR
V AR_OUTPUT
<输出描述>
END_V AR
V AR
<本地变量描述>
END_V AR
END_FUNCTION_BLOCK
输入输出描述
<输入或输出的名字>
{< I/O描述的可选参数>}:
<数据类型>:=<缺省值>;
I/O的初始值可以省略,这种情况下整个字符序列:=<缺省值> 必须被省略。本地变量描述
<本地变量名>:<数据类型>;
可选参数数据的结构
<关键字>:=<值>;
关键字的值的字符序列长度和字符范围
NAME_FB:功能块名
名字长度: 1~6 字符
允许的字符: 第一个字符[A-Z],剩余字符[A-Z] 或[0-9] 或_
RUNTIME: 在PM5 / T400上运行的计算时间1 / 10 毫秒
计算时间长度: 1~4 字符
允许的字符: [0-9]
输入输出及本地变量名字
名字长度: 1~3 字符
允许的字符: 第一个字符[A-Z],剩余字符[A-Z] 或[0-9] 或_
可选数据的关键字
可选数据的关键字
这里定义一些缩略语用于本说明
Empty string:两个单引号内没有任何字符。
String_1:1个字符。范围是:[0-9] 或[A-Z] 或[a-z] | ‘’(两单引号内有空格)或empty string。
String_8:最大8个任意字符。
String_80:最大80个任意字符。
关键字COMMENT 和FAMIL Y 可以由不同的语言ID多次使用。
语法描述:
COMMENT <语言ID>:=String_80;
FAMIL Y <语言ID>:=String_8;
语言ID : 任意个空格表示缺省语言;2个小写字符代表语言ID
语言ID 只作上述两种情况检查,他编译后存在.msk文件中,由CFC编辑器评估。CFC编
辑器定义语言ID是:gr 表示德语;us 表示英语。
FB头部的可选关键字
1)如果FB的I/O有SDTIME类型数据,关键字TIMEDEP(在FB头部中独立的数据)总是设定为TRUE
I/O描述中的可选关键字
1)STRING类型的I/O(在I/O描述中独立的数据) CONNECTABLE关键字值总是FALSE.
输入输出和本地变量的数据类型
输入输出和本地变量的数据类型
以下是输入输出和本地变量允许的数据类型
注意:
D7 功能块生成器检查用户输入的缺省值数据类型是否与定义类型相兼容。
SDTIME数据类型用户提供数据单位为毫秒ms。
STRING数据类型只允许作为输入。
WORD / DWORD类型被描述为*int16 / *int32。如果他们确实作为字或双字使用,必须作类型转换处理。
只有本地变量才有的数据类型
注意:
本地变量既无可选部分也无缺省值,不同于I/O本地变量被分配给一个内存地址而不是指针。
I/O初始值的范围
注意:BYTE、INT、WORD、DINT、DWORD类型初值可以指定进制:2# 二进制数, 10# 10进制数, 16# 16进制数。
如果不指定进制,BYTE、WORD、DWORD 表示为16进制数,INT、DINT 表示为10进制数。
浮点数(REAL、SDTIME)能被存成非规格化的样子, 范围大约从-1.1755e-38 到+1.1755e-38。这些没有规格化的数比正常数精度低,因为他们的尾数左边填0。
FB运行代码
FB 运行代码使用C语言格式输入到
下列规则应用于FB 运行代码定义文件:
模块标示使用FBTNAM(
为了程序编写者方便,FB正常模式和初始化模式的主函数的不包含FB名字和参数,只使用符号:NRM()和INI()表示。D7功能块生成器自动产生函数头部包括FB名字和参数。
以下说法用于D7功能块生成器运行码检查:
从文件开始到FB名字前所有的行都略过。
D7功能块生成器评估FB名字。
从FB名字开始到文件结束的所有行都作为运行码考虑。
运行码由几个函数组成:由操作系统直接调用的主函数NRM()和INI(),和由主函数直接或间接调用的其他辅助函数。FB编程者必须完整地输入辅助函数,例如,这些函数必须在程序开始处声明函数及参数。而函数放在主函数之后。函数原形必须在调用之前定义,调用通常在NRM()中。
注意:所有辅助函数及其原形必须是静态函数。
函数的定义
FB 和他的函数都必须是可重入的。
因此下列规则必须遵守:
FB主函数接口中不能有变量。
如果FB主函数接口中定义了变量,则变量被分配的内存类型extern或static。在整个系统运行中FB模块为这样的变量只分配一次内存,因此这样的FB是不可重入的。这意味着在FB中各函数(NRM INI SYS)之间不能使用变量来传递数据。只可使用FB定义文件中的参数,即本地变量来传递数据。
FB函数内不可使用静态变量。
FB函数内变量内存类型应为auto或register,static类型是不允许的。
外部函数
编程者可以定义和使用外部函数(函数代码没整合到FB代码中而是位于另一个C语言文件中),为力使用外部函数下列规则必须遵守:
调用的外部函数在另一个C语言文件中。
在头文件中定义外部函数的原形。
使用#include 指令,在FB运行码文件中包含有外部函数的原形定义的那个头文件。
使用#include 指令,在已经包含了头文件之后包含C 文件。
举例:
先写外部函数文件,再被FB1和FB2使用。
/*外部函数存放的文件c:\foo.c*/
int foo()
{
return 314;
}
----------------------------------------------------
/*头文件c:\foo.h*/
external int foo(); /* 头文件中定义了外部函数的原形*/
/*头文件c:\foo.h 结束*/
----------------------------------------------------
/* FB1的代码文件FB1.c */
#include "c:\foo.h" /*包含外部函数的头文件*/
#include "c:\foo.c" /*包含外部函数的代码文件*/
...
INI() /* 主函数入口*/
{
int i;
...
i = foo(); /*使用外部函数*/
...
}
----------------------------------------------------
/* FB2的代码文件FB2.c*/
#include "c:\foo.h" /*包含外部函数的头文件,代码文件在FB1中已经包含了就不在写了*/ INI() /*主函数入口*/
{
int i;
i = foo();
}
----------------------------------------------------
在FB主函数中访问FB输入输出
FB只需写I/O和本地变量的名字就可以访问这些数据。D7功能块生成器在建立FB时自动生成包含文件
举例:
I1 : BOOL;
I2 : BOOL;
Q : BOOL;
Q = I1 & I2;
STRING类型访问的例子:
STRING 输入的长度被放在字符串的第一个字节里。.
举例:
ST : STRING;
char anzahl, nam_2;
nam_2= ST[2];
(void)printf( "Name:%c%c%c\n",ST[1], ST[2], ST[3] );
anzahl = ST[0];
在FB辅助函数中访问FB输入输出
FB的I/O和本地变量可以在FB主函数中访问,从FB主函数中读或写。FB中的辅助函数访问FB的I/O时除了可以使用I/O指针作为参数来使用外,还可以使用下述方法:(特别是有很多I/O要访问,参数特别多时)。
D7 功能块生成器定义了3个常量:(用户程序不用写)
#define ALE_PRO struct {fbtname}_ale *
#define ALE_PTR c_ale
#define ALE_STR struct {fbtname}_ale *c_ale
FB中的辅助函数使用这3个常量时,ALE_PRO写在函数原形的声明中;ALE_PTR在程序中作为调用函数的参数;ALE_STR放在定义辅助函数的参数表中。
举例说明:
/* 主程序前声明子函数原形子函数名unt_funkt */
static void unt_funkt(int,...,ALE_PRO);
:
:
unt_funkt(par1,...,ALE_PTR); /* 主程序中调用子函数unt_funkt */
:
:
/* ============================================== */
/*主程序后定义被调用的子函数unt_funkt */
static void unt_funkt(int param1,...,ALE_STR)
{ ...}
在被调用的子函数unt_funkt中,FB的I/O和本地变量访问就像在主函数中一样,直接使用变量名,D7 功能块生成器自动把I/O和本地变量的指针传给子函数。
外部模块中的函数访问FB输入输出
外部模块中定义的函数可以被多个FB块调用。有时这些外部函数也要读写FB的I/O。定义函数参数表时,为FB的I/O定义指针类型的参数,该参数类型一定要与FB的I/O类型一致名字可以不同。
指针可以指向“real”或FB本地变量。
调用外部函数使用指令:(void)ext_funkt( param1, &STB, &QW );
ext_funkt函数在一个FB主函数中调用。param1是一个参数STB和QW 是FB的I/O的指针。
外部函数必须在FB开始处声明其原形,这也通常通过包含文件来实现。
声明:external void ext_funkt( int, float*, char* );
外部函数通常在外部模块中定义:
void ext_funkt( int kennung, float *wert, char *zust )
{
if( kennung > 10 && *wert <= 12.0 ) *zust = 1;
else *zust = 0;
}
指向I/O的指针被传给函数。因此访问I/O时变量名前一定要有前缀操作符* 。用户必须保证类型正确。
常数、宏和函数原形
FB的I/O可能会经常改变类型(如从DINT到INT)、对某值进行限幅处理、二进制信号(BOOL类型)的设定或评估,这些经常性固定形式的操作可以定义为宏,不必每次使用时进行编程。一些已经做好的宏包含在p32.h 文件中供使用。使用前在程序最前面使用指令:#include "p32.h".
常数
下列常数已经被定义:
#define PI_HALBE 1.57079632679489661923
#define PI_WERT 3.14159265358979323846
#define M_PI_2 1.57079632679489661923
#define M_PI 3.14159265358979323846
宏
FB的I/O类型转换
计算中FB的I/O数据类型的值的范围可能不够用,中间计算结果值超出类型范围,这时就需要把小值域的类型转换为大值域类型进行计算,最后在转回原类型。下列宏可以实现这个功能。
inf 是一个BOOL类型的I/O或char型的C变量。
应用例子:
Y = CONVERT_N4_N2_INF(sum,QW);