2.6 数据类型与系统存储区
数据类型用于指定数据元素的大小以及如何解释数据。每个指令参数至少支持一种数据类型,而有些参数支持多种数据类型。PLC在运行时需要处理各种各样的数据和功能。这些不同类型的数据被存放在不同的存储空间,从而形成不同的数据区,所以需要掌握S7-1200 PLC的存储器区域的编排方法。
2.6.1 CPU的存储器
CPU提供了3种用于存储用户程序、数据和组态的存储区。
(1)装载存储器:用于非易失性地存储用户程序、数据和组态。将项目下载到CPU后,CPU会先将程序存储在装载存储区中。该存储区位于存储卡(如存在)或CPU中。CPU能够在断电后继续保持该非易失性存储区。存储卡支持的存储空间比CPU内置的存储空间更大。
(2)工作存储器:是易失性存储器,用于在执行用户程序时存储用户项目的某些内容。CPU会将一些项目内容从装载存储器复制到工作存储器中。该易失性存储区将在断电后丢失,而在恢复供电时由CPU恢复。
(3)保持性存储器:用于非易失性地存储限量的工作存储器值。在断电过程中,CPU使用保持性存储区存储所选用户存储单元的值。如果发生断电或掉电,CPU将在上电时恢复这些保持性值。
要显示编译程序块的存储器使用情况,请右键单击STEP 7项目树中“程序块”(Program blocks)文件夹中的块,然后从上下文菜单中选择“资源”(Resources)。“编译属性”(Compilation properties)显示了编译块的装载存储器和工作存储器。要显示在线CPU的存储器使用情况,请双击STEP 7中的“在线和诊断”(Online and Diagnostics),展开“诊断”(Diagnostics),然后选择“存储器”(Memory)。
CPU仅支持预格式化的SIMATIC存储卡,将存储卡用作传送卡或程序卡。复制到存储卡中的任何程序均包括所有代码块和数据块、所有工艺对象和设备配置。复制的程序不包含强制值。强制值不是程序的一部分,但强制值可存储在装载存储器,即CPU的内部装载存储器或外部装载存储器(程序卡)中。如果在CPU中插入程序卡,则STEP 7仅会将强制值应用到程序卡上的外部装载存储器上。
2.6.2 数制与数据类型
下面讲述数据的数制分类和数据类型。
1. 数制
1)二进制数
二进制数只能取0和1这两个不同的值,可以用来表示开关量的两个不同状态。如果该位为1,则表示梯形图中对应的位编程元件(如位存储器M和过程映像输出位Q)的线圈“通电”,其常开触点接通,常闭触点断开,以后称编程元件为TRUE或1状态。如果该位为0,则对应的编程元件的线圈和触点的状态与上述状态相反,称编程元件为FALSE或0状态。
2)多位二进制整数
计算机和PLC用多位二进制数来表示数字。如表2-5所示为不同进制数的表示方法。
表2-5 不同进制数的表示方法
3)十六进制数
多位二进制数的书写和阅读很不方便,可以用十六进制数来代替二进制数。每个二进制数对应于4位二进制数。在数字后面加H表示十六进制,PLC常用在十六进制数前面加16#来表示十六进制数。
2. 数据类型
数据类型用于指定数据元素的大小以及如何解释数据。每个指令参数至少支持一种数据类型,而有些参数支持多种数据类型。将光标停在指令的参数域上方,便可看到给定参数所支持的数据类型。
如表2-6所示为基本数据类型的属性,其他数据类型将在后面介绍。
表2-6 基本数据类型
3. 位
数字系统内的最小信息单位为“位”(对于“二进制数”)。一位只可以存储一种状态,即0(假或非真)或1(真)。灯开关是只有两种状态的“二进制”系统示例。灯开关决定是“点亮”还是“熄灭”状态,并且该“值”可存储为一位。灯开关的数字值回答了以下问题:“灯是点亮的吗?”如果灯点亮(“真”),则该值为1;如果灯熄灭(“假”),则该值为0。
如图2-13所示,CPU将数据位编成组。8位为一组,称为一个字节(如图中②)。组中的每一位(如图中①)都通过具有自身地址的单独位置来精确定义。每位都具有一个字节地址以及0~7的位地址。
图2-13 字节与位
4. Bool、Byte、Word和DWord数据类型
位和位序列的数据类型如表2-7所示。
表2-7 位和位序列数据类型
5. 整数
整数数据类型共有6种,即有符号短整数类型(SInt)、无符号短整数类型(USInt)、有符号整数类型(Int)、无符号整数类型(UInt)、有符号双整数类型(DInt)、无符号双整数类型(UDInt),如表2-8所示。
表2-8 整型数据类型(U=无符号,S=短,D=双)
6. 浮点数
如ANSI/IEEE 754-1985标准所述,实(或浮点)数以32位单精度数(Real)或64位双精度数(LReal)表示。单精度浮点数的精度最高为6位有效数字,而双精度浮点数的精度最高为15位有效数字。在输入浮点常数时,最多可以指定6位(Real)或15位(LReal)有效数字来保持精度。
7. 时间与日期
TIME数据作为有符号双整数存储,被解释为毫秒。编辑器格式可以使用日期(d)、小时(h)、分钟(m)、秒(s)和毫秒(ms)信息。不需要指定全部时间单位。例如,T#5h10s和500h均有效。所有指定单位值的组合值不能超过以毫秒表示的时间日期类型的上限或下限(-2,147,483,648 ms到+2,147,483,647 ms)。
DATE数据作为无符号整数值存储,被解释为添加到基础日期1990年1月1日的天数,用以获取指定日期。编辑器格式必须指定年、月和日。
8. 字符
每个字符(Char)占一个字节,Char数据类型以ASCII格式存储。WChar(宽字符)占两个字节,可以存储汉字和中文的标点符号。字符常量用英文的单引号来表示,如'A'。
2.6.3 全局数据块与其他数据类型
1. 生成全局数据块
在项目“新建项目”中,单击项目树PLC的“程序块”文件夹中的“添加新块”,在打开的对话框中(如图2-14所示)单击“数据块(DB)”图标,生成一个数据块,可以修改其名称或采用默认的名称,其类型为默认的“全局DB”,生成数据块编号的方式为默认的“自动”。如果选中“手动”单选框,可以修改块的编号。
单击“确定”按钮后自动生成数据块。勾选“新增并打开”复选框,生成新的块后,将自动打开它。右键单击项目树中新生成的“数据块1”,执行快捷菜单命令“属性”,选中打开的对话框左边列表中的“属性”(如图2-15所示),如果勾选右边的“优化的块访问”复选框,只能用符号地址访问生成的块中变量,不能使用绝对地址。这种访问方式可以提高存储器的利用率。
图2-14 添加数据块
图2-15 设置数据块的属性
只有在未勾选复选框“优化的块访问”时,才能使用绝对地址访问数据块中的变量,数据块才会显示“偏移量”列中的偏移量。
2. 字符串
数据类型String(字符串)是字符组成的一维数组,每个字节存放1个字符。第一个字节是字符串的最大字符长度,第二个字是当前有效字符的个数,字符从第三个字节开始存放。一个字符串最多254个字符。
数据类型WSting(宽字符串)存储多个数据类型为WChar的Unicode字符(长度为16位的宽字符,包括汉字)。第一个字是最大字符个数,默认的长度为254个宽字符,最多16382个WChar字符,第二个字是当前的总字符个数。
可以在代码块的接口区和全局数据块中创建字符串、数组和结构。
在“数据块1”的第二行的“名称”列(如图2-16所示)输入字符串的名称“电动机运行状态”,单击“数据类型”列中的按钮,选中下拉列表中的数据类型String,其启动值(初始字符)为“运行”。
图2-16 生成数据块中的变量
3. 数组
数组(Array)是由固定数目的同一种数据类型元素组成的数据结构,允许使用除了Array之外的所有数据类型作为数组的元素,数组的维数最多为6维。如图2-17所示为一个名为“电流”的二维数组Array(1..2,1..3)of Byte的内部结构,它共有6个字节型元素。
图2-17 二维数组的结构
第一维的下标1、2是电动机的编号,第二维的下标1-3是三相电流的序号。数组元素“电流(1,2)”是一号电动机的第B相电流。
在数据块的第二行的“名称”列输入数组的名称“水池液位”,单击数据类型列中的按钮,选中下拉列表中的数据类型Array[lo..hi}of type。其中的lo(low)和hi(high)分别是数组元素的编号(下标)的下限值和上限值,它们用两个小数点隔开,可以是任意整数(−32768~32767),下限值应小于等于上限值。方括号中各维的参数用逗号隔开,type是数组元素的数据类型。
将Array[lo..hi}of type修改为Array[0..5}of lnt,其元素的数据类型为lnt,元素的下标为0~5。
在用户程序中可以用符号地址“数据块1”、水池液位{2}或绝对地址DBI.DBW36访问数组“水池液位”中下标为2的元素。
单击“水池液位”左侧的按钮,它变为,将会显示数组的各个元素,可以监控它们的启动值和监控值。单击“功率”左侧的按钮,它变为,数组的元素被隐藏起来。
4. 结构
可以用数据类型Struct来定义包含其他数据类型的数据结构。Struct数据类型可用来以单个数据单元方式处理一组相关过程数据。在数据块编辑器或块接口编辑器中命名Struct数据类型并声明内部数据结构。数组和结构还可以集中到更大的结构中。一套结构可嵌套8层。例如,可以创建包含数组的多个结构组成的结构。
5. Pointer指针
数据类型Pointer指向特殊变量,其结构如图2-18所示。它会在存储器中占用6个字节(48位),可能包含以下信息:
- □ DB编号或0(如果该数据未存储在DB中)。
- □ CPU中的存储区。
- □ 变量地址。
图2-18 Pointer指针的结构
可以使用指令声明3种类型的指针。
- □ 区域内部的指针:包含变量的地址数据。
- □ 跨区域指针:包含存储区中数据以及变量地址数据。
- □ DB指针:包含数据块编号以及变量地址。
可以输入没有前缀(P#)的Pointer类型的参数,将自动转换为指针格式。存储区的编码如表2-9所示。
表2-9 Pointer指针中存储区编码
6. ANY指针
指针数据类型ANY指向数据区的起始位置,并指定其长度。其结构如图2-19所示,如表2-10所示为具体格式和实例。ANY指针的数据类型编码如表2-11所示,存储区编码如表2-12所示。ANY指针使用存储器中的10个字节,可能包含下面所列的信息。
- □ 数据类型:数据元素的数据类型。
- □ 重复因子:数据元素数目。
- □ DB号:存储数据元素的数据块。
- □ 存储区:CPU中存储数据元素的存储区。
- □ 起始地址:数据的Byte.Bit起始地址。
图2-19 ANY指针的结构
指针无法检测ANY指针的结构,只能将其分配给局部变量。
表2-10 ANY指针的格式和示例
表2-11 ANY指针中的数据类型编码
表2-12 ANY指针中的存储区编码
7. Variant指针
Variant数据类型可以指向不同数据类型的变量或参数。Variant指针可以指向结构和单独的结构元素。Variant指针不会占用存储器的任何空间,其属性如表2-13所示。
表2-13 Variant指针的属性
8. PLC数据类型
PLC数据类型可用来定义可以在程序中多次使用的数据结构。可以通过打开项目树的“PLC数据类型”分支并双击“添加新数据类型”项来创建PLC数据类型。在新创建的PLC数据类型项上,两次单击可重新命名(修改默认名称),双击则会打开PLC数据类型编辑器。可使用与数据块编辑器中相同的编辑方法创建自定义PLC数据类型结构。为任何必要的数据类型添加新的行,以创建所需数据结构。
如果创建新的PLC数据类型,则该新PLC类型名称将出现在DB编辑器和代码块接口编辑器的数据类型选择器下拉列表中。下面列举PLC数据类型的可能应用。
- □ 可将PLC数据类型直接用作代码块接口或数据块中的数据类型。
- □ PLC数据类型可用作模板,以创建多个使用相同数据结构的全局数据块。
例如,PLC数据类型可能是混合颜色的配方。用户可以将该PLC数据类型分配给多个数据块。之后,每个数据块都会调节变量,以创建特定颜色。
9. 使用符号方式访问非结构数据类型变量的“片段”
可以根据大小,按位、字节或字级别访问PLC变量和数据块变量。访问此类数据片段的语法如下所示。
- □ "<PLC变量名称>".xn(按位访问)
- □ "<PLC变量名称>".bn(按字节访问)
- □ "<PLC变量名称>".wn(按字访问)
- □ "<数据块名称>".<变量名称>.xn(按位访问)
- □ "<数据块名称>".<变量名称>.bn(按字节访问)
- □ "<数据块名称>".<变量名称>.wn(按字访问)
双字大小的变量可按位0~31、字节0~3或字0~1访问。一个字大小的变量可按位0~15、字节0~1或字0访问。字节大小的变量则可按位0~7或字节0访问。当预期操作数为位、字节或字时,可使用位、字节和字片段访问方式。双字节中的位、字节和字的结构如图2-20所示。
图2-20 双字节中的位、字节和字
10. 访问带有一个AT覆盖的变量
借助AT变量覆盖,可通过一个不同数据类型的覆盖声明访问标准访问块中已声明的变量。例如,可以通过Array of Bool寻址数据类型为Byte、Word或DWord变量的各个位。
要覆盖一个参数,可以在待覆盖的参数后直接声明一个附加参数,然后选择数据类型AT。编辑器随即创建该覆盖,然后选择将用于该覆盖的数据类型、结构或数组。如图2-21所示,显示一个标准访问FB的输入参数。字节变量B1将由一个布尔型数组覆盖。
图2-21 字节变量B1将由一个布尔型数组覆盖
- □ 只能覆盖可标准(未优化)访问的FB和FC块中的变量。
- □ 可以覆盖所有类型和所有声明部分的变量。
- □ 可以像使用其他块参数一样使用覆盖后的参数。
- □ 不能覆盖VARIANT类型的参数。
- □ 覆盖参数的大小必须小于等于被覆盖的参数。
- □ 必须在覆盖变量并选择关键字AT作为初始数据类型后立即声明覆盖变量。
2.6.4 系统存储区
STEP 7简化了符号编程。用户为数据地址创建符号名称或“变量”,作为与存储器地址和输入/输出点相关的PLC变量或在代码块中使用的局部变量。要在用户程序中使用这些变量,只需输入指令参数的变量名称,系统的存储区如表2-14所示。
表2-14 系统存储区
为了更好地理解CPU的存储区结构及其寻址方式,将对PLC变量所引用的“绝对”寻址进行说明。CPU提供了以下几个选项,用于在执行用户程序期间存储数据。
(1)全局储存器:CPU提供了各种专用存储区,其中包括输入(I)、输出(Q)和位存储器(M)。所有代码块可以无限制地访问该储存器。
(2)PLC变量表:在STEP 7 PLC变量表中,可以输入特定存储单元的符号名称。这些变量在STEP 7程序中为全局变量,并允许用户使用应用程序中有具体含义的名称进行命名。
(3)数据块(DB):可在用户程序中加入DB以存储代码块的数据。从相关代码块开始执行一直到结束,存储的数据始终存在。“全局”DB存储所有代码块均可使用的数据,而背景DB存储特定FB的数据,并且由FB的参数进行构造。
(4)临时存储器:只要调用代码块,CPU的操作系统就会分配要在执行块期间使用的临时或本地存储器(L)。代码块执行完成后,CPU将重新分配本地存储器,以用于执行其他代码块。
每个存储单元都有唯一的地址。用户程序利用这些地址访问存储单元中的信息。对输入(I)或输出(Q)存储区(如I0.3或Q1.7)的引用会访问过程映像。要立即访问物理输入或输出,请在引用后面添加:P(如I0.3:P、Q1.7:P或"Stop:P")。
绝对地址由以下元素组成:
- □ 存储区标识符(如I、Q或M)。
- □ 要访问的数据的大小(B表示Byte、W表示Word或D表示DWord)。
- □ 数据的起始地址(如字节3或字3)。
访问布尔值地址中的位时,不需要输入大小的助记符号,仅需输入数据的存储区、字节位置和位位置(如I0.0、Q0.1或M3.4)。
图2-22中,存储区和字节地址(M代表位存储区,3代表Byte3)通过后面的句点(“.”)与位地址(位4)分隔。
图2-22 位寻址图
1. 过程映像输入/输出
CPU仅在每个扫描周期的循环OB执行之前对外围(物理)输入点进行采样,并将这些值写入到输入过程映像。可以按位、字节、字或双字访问输入过程映像。允许对过程映像输入进行读写访问,但过程映像输入通常为只读。
通过在地址后面添加:P,可以立即读取CPU、SB、SM或分布式模块的数字量和模拟量输入。使用I_:P访问与使用I访问的区别是,前者直接从被访问点而非输入过程映像获得数据。这种I_:P访问称为“立即读”访问,因为数据是直接从源而非副本获取的,这里的副本是指在上次更新输入过程映像时建立的副本。因为物理输入点直接从与其连接的现场设备接收值,所以不允许对这些点进行写访问。与可读或可写的I访问不同的是,I_:P访问为只读访问。I_:P访问也仅限于单个CPU、SB或SM所支持的输入大小(向上取整到最接近的字节)。例如,如果2 DI/2 DQ SB的输入被组态为从I4.0开始,则可按I4.0:P和I4.1:P形式或者按IB4:P形式访问输入点。不会拒绝I4.2:P到I4.7:P的访问形式,但没有任何意义,因为这些点未使用。但不允许IW4:P和ID4:P的访问形式,因为它们超出了与该SB相关的字节偏移量。使用I_:P访问不会影响存储在输入过程映像中的相应值。
CPU将存储在输出过程映像中的值复制到物理输出点。可以按位、字节、字或双字访问输出过程映像。过程映像输出允许读访问和写访问。
通过在地址后面添加“:P”,可以立即写入CPU、SB、SM或分布式模块的物理数字量和模拟量输出。使用Q_:P访问与使用Q访问的区别是,前者除了将数据写入输出过程映像外还直接将数据写入被访问点(写入两个位置)。这种Q_:P访问有时称为“立即写”访问,因为数据是被直接发送到目标点;而目标点不必等待输出过程映像的下一次更新。因为物理输出点直接控制与其连接的现场设备,所以不允许对这些点进行读访问。与可读或可写的Q访问不同的是,Q_:P访问为只写访问。Q_:P访问也仅限于单个CPU、SB或SM。
所支持的输出大小(向上取整到最接近的字节)。例如,如果2 DI/2 DQ SB的输出被组态为从Q4.0开始,则可按Q4.0:P和Q4.1:P形式或者按QB4:P形式访问输出点。不会拒绝Q4.2:P到Q4.7:P的访问形式,但没有任何意义,因为这些点未使用。但不允许QW4:P和QD4:P的访问形式,因为它们超出了与该SB相关的字节偏移量。
使用Q_:P访问既影响物理输出,也影响存储在输出过程映像中的相应值。
2. 位存储器区
针对控制继电器及数据的位存储区(M存储器)用于存储操作的中间状态或其他控制信息。可以按位、字节、字或双字访问位存储区。M存储器允许读访问和写访问。
3. 数据块
数据块(Data Block)简称DB,用来存储代码块使用的各种类型的数据,包括中间操作状态或FB的其他控制信息参数,以及某些指令(如定时器、计数器指令)需要的数据结构。
数据块可以按位(如DB1.DBX3.5)、字节(如DBB)、字(如DBW)、双字(如DBD)来访问。在访问数据块中的数据时,应指明数据块的名称,如DB1.DBW20。
如果启用了块属性“优化的块访问”,不能用绝对地址访问数据块和代码块的接口区中的临时局部数据。
4. 临时存储器
CPU根据需要分配临时存储器。启动代码块(对于OB)或调用代码块(对于FC或FB)时,CPU将为代码块分配临时存储器并将存储单元初始化为0。
临时存储器与M存储器类似,但有一个主要的区别:M存储器在“全局”范围内有效,而临时存储器在“局部”范围内有效。
(1)M存储器:任何OB、FC或FB都可以访问M存储器中的数据,也就是说这些数据可以全局性地用于用户程序中的所有元素。
(2)临时存储器:CPU限定只有创建或声明了临时存储单元的OB、FC或FB才可以访问临时存储器中的数据。临时存储单元是局部有效的,并且其他代码块不会共享临时存储器,即使在代码块调用其他代码块时也是如此。例如,当OB调用FC时,FC无法访问对其进行调用的OB的临时存储器。