该数据块提供了一个滑块寄存器(LIFO,后进先出),最多包含50个存储寄存器。每个寄存器都具有格式 DWORD。




功能块说明:
当LIFO未满时,使用输入端IN的上升沿将一个数据项存入LIFO。
当LIFO不为空时,使用输入端Out的上升沿将一个数据项取出。
注意:输入端IN和OUT不能进入同一周期,否则不会执行任何动作。储存和取出功能是相互锁定的。
可以从可视化干预数据 array。可以插入、覆盖或删除数据。
其中将待处理的元素添加到标记位置,进行处理或删除。在插入时将所有后面的数据向前移动一个存储位置,并且使得指针递增,在删除时则将所有后面的数据记录向后移动一个位置。
在可视化中编辑某个数据记录的时间受到监控。如果带有按钮“更改”、“插入”、“删除”或“取消”的输入端在20秒后仍未结束,则SPS将撤回对数据项的处理。


LIFO功能块详细解读:
1、功能块调用:

2、全部代码:

REGION (/* Aenderungsjournal */)
(*
******************************************************************************************
** Copyright 2016 SIEMENS AG D-90475 Nuernberg **
** All Rights Reserved VOLKSWAGEN AG, 38436 Wolfsburg **
** AUDI AG, D-85045 Ingolstadt **
******************************************************************************************
Datum Version Autor Beschreibung
----------------------------------------------------------------------------------------------------------------
06.01.22 1.5.00 Gruber Vorbereitung fuer Mehrsprachige Kommentare durchgefuehrt
28.01.19 1.4.00 Schulz Korrektur: Button "Abbrechen" wird auch eingeblendet
bei FRG_Korr; Zuweisung dwvisuwerte
19.12.18 1.2.00 VASS_V6 Bildbaustein neu
12.04.18 1.1.00 VASS_V6 TIA Startversion
17.01.18 0.0.07 Waldeck VASS-Merker nach DB_ARG verschoben
13.02.17 0.0.00 Waldeck Migration TIA V14
05.03.12 3.0.00 Jablonski Uebernahme in VASS_Standard aus V1.6
****************************************************************************************
*)
END_REGION
(/* LIFO fuer die Zwischenspeicherung von Pufferdaten */)
(/* Ruecksetzen der Befehle durch externe Quittierung */)
REGION (/* Programm */)
(/* Umladen der Nutzdaten */)
FOR #iZeiger := 0 TO 50 DO
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #Typ_Daten[#iZeiger];
END_FOR;
#iZeiger := BYTE_TO_INT(#"HMI-UDT".arVisuWerte[0].D_Word.%B2);
(/* Laengenpruefung */)
#iLaenge := #Laenge;
IF #iLaenge < 1 OR #iLaenge > 50 THEN
#iLaenge := 50;
END_IF;
(/* Grenzen des LIFOs ueberpruefen */)
#xLeer := (#iZeiger < 1);
#xVoll := (#iZeiger >= #iLaenge);
(/* Einspeichern eines neuen Datensatzes */)
#R_TRIG_In(CLK := #In AND NOT #xVoll);
IF #R_TRIG_In.Q AND NOT #In_Done THEN
#iZeiger := #iZeiger + 1;
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #Daten_In;
#In_Done := True;
END_IF;
(/* Austragen eines Datensatzes*) */)
#R_TRIG_Out(CLK := #Out AND (#In_Done OR NOT #In) AND NOT #xLeer);
IF #R_TRIG_Out.Q AND NOT #Out_Done THEN
#Daten_Out := #"HMI-UDT".arVisuWerte[#iZeiger].D_Word;
(/* Freigewordenes Datenfeld abloeschen und #iZeiger anpassen */)
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #dwLeerdaten;
#iZeiger := #iZeiger - 1;
#Out_Done := True;
END_IF;
(/* #Anzahl arVisuWerte #In Puffer */)
#Anzahl := #iZeiger;
(/* - Sichtbarkeit der Buttons zuruecksetzen */)
#"HMI-UDT".dwVisuWerte1.%X0 := FALSE;
#"HMI-UDT".dwVisuWerte1.%X1 := FALSE;
#"HMI-UDT".dwVisuWerte1.%X2 := FALSE;
#"HMI-UDT".dwVisuWerte1.%X3 := FALSE;
(/* - Setzen der Buttons-Sichtbarkeit */)
IF #Frg_Korr THEN
(/* Wenn Freigabe, dann */)
IF (#iZeiger <= 0) THEN
(/* Wenn kein Element */)
#"HMI-UDT".arVisuWerte[0].D_Word.%X25 := True; (/* Aendern */)
#"HMI-UDT".arVisuWerte[0].D_Word.%X26 := True; (/* Loeschen */)
#"HMI-UDT".dwVisuWerte1.%X1 := True; (/* Aendern */)
#"HMI-UDT".dwVisuWerte1.%X2 := True; (/* Loeschen */)
END_IF;
IF (#iZeiger >= #iLaenge) THEN
(/* Wenn #Voll */)
#"HMI-UDT".arVisuWerte[0].D_Word.%X24 := True; (/* Einfuegen */)
#"HMI-UDT".dwVisuWerte1.%X0 := True; (/* Einfuegen */)
END_IF;
ELSE
(/* Wenn kein Freigabe: */)
#"HMI-UDT".arVisuWerte[0].D_Word := #"HMI-UDT".arVisuWerte[0].D_Word AND DWORD#16#FFFFFF00;
#"HMI-UDT".dwVisuWerte1.%B0 := Byte#16#F; (/* Alle Unsichtbar */)
END_IF;
IF NOT #Frg_Korr THEN
#"HMI-UDT".dwVisuTasten2 := DWORD#0;
#"HMI-UDT".dwVisuTasten2.%B2 := Byte#0; (/* Position (1..50) */)
#"HMI-UDT".dwVisuTasten2.%B3 := Byte#0; (/* Befehl (1: Einfuegen 2: Aendern 3: Loeschen) */)
END_IF;
(/* Typkennung fuer Lifo */)
#"HMI-UDT".arVisuWerte[0].D_Word.%X2 := True;
#bBefehl := #"HMI-UDT".dwVisuTasten2.%B3; (/* Befehl (1: Einfuegen 2: Aendern 3: Loeschen) */)
#iVisuZeiger := BYTE_TO_INT(#"HMI-UDT".dwVisuTasten2.%B2); (/* Position (1..50) */)
REGION (/* Visutasten */)
(/* Schreibbefehle von der Visualisierung ueberwachen */)
IF "DB_ARG".PC_AKTIV = DWORD#16#00000000 OR NOT #Frg_Korr THEN
#bBefehl := Byte#0;
#iVisuZeiger := INT#0;
END_IF;
(/* Pruefung auf gueltige Werte */)
IF #iVisuZeiger > 0 AND #iVisuZeiger <= 50 THEN
(/* Einfuegen eines neuen Datensatzes aus der Visu */)
IF #bBefehl = Byte#1 AND NOT #xVoll THEN
#"HMI-UDT".dwVisuWerte1.%X7 := NOT #"HMI-UDT".dwVisuWerte1.%X7;
IF #iVisuZeiger <= #iZeiger THEN
#iZeiger := #iZeiger + 1;
#iHM_Zaehler1 := #iZeiger;
REPEAT
#iHM_Zaehler2 := #iHM_Zaehler1 - 1;
#"HMI-UDT".arVisuWerte[#iHM_Zaehler1] := #"HMI-UDT".arVisuWerte[#iHM_Zaehler2];
#iHM_Zaehler1 := #iHM_Zaehler1 - 1;
UNTIL #iHM_Zaehler2 = #iVisuZeiger
END_REPEAT;
#"HMI-UDT".arVisuWerte[#iVisuZeiger].D_Word := #"HMI-UDT".dwVisuTasten1;
ELSE
#iZeiger := #iZeiger + 1;
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #"HMI-UDT".dwVisuTasten1;
END_IF;
#"HMI-UDT".dwVisuTasten2.%B3 := Byte#0;
#"HMI-UDT".dwVisuTasten2.%B2 := Byte#0;
END_IF;
(/* Ueberschreiben eines Datensatzes aus der Visualisierung */)
IF #bBefehl = Byte#2 AND #iVisuZeiger <= #iZeiger THEN
#"HMI-UDT".arVisuWerte[#iVisuZeiger].D_Word := #"HMI-UDT".dwVisuTasten1;
#"HMI-UDT".dwVisuTasten2.%B3 := Byte#0;
#"HMI-UDT".dwVisuTasten2.%B2 := Byte#0;
END_IF;
(/* Loeschen eines Datensatzes aus der Visualisierung */)
IF #bBefehl = Byte#3 AND #iVisuZeiger <= #iZeiger THEN
#iZeiger := #iZeiger - 1;
#iHM_Zaehler2 := #iVisuZeiger; (/* Initialisierung, fuer iVisuZeiger > iZeiger */)
FOR #iHM_Zaehler1 := #iVisuZeiger TO #iZeiger DO
#iHM_Zaehler2 := #iHM_Zaehler1 + 1;
#"HMI-UDT".arVisuWerte[#iHM_Zaehler1] := #"HMI-UDT".arVisuWerte[#iHM_Zaehler2];
END_FOR;
#"HMI-UDT".arVisuWerte[#iHM_Zaehler2].D_Word := #dwLeerdaten;
#"HMI-UDT".dwVisuTasten2.%B3 := Byte#0;
#"HMI-UDT".dwVisuTasten2.%B2 := Byte#0;
END_IF;
(/* Aenderung des Ausgangs #Daten_Out */)
ELSIF #iVisuZeiger = 55 AND #bBefehl = Byte#2 THEN
#Daten_Out := #"HMI-UDT".dwVisuTasten1;
#"HMI-UDT".dwVisuTasten2.%B3 := Byte#0;
#"HMI-UDT".dwVisuTasten2.%B2 := Byte#0;
END_IF;
END_REGION
END_REGION
(/* arVisuWerte fuer Visu aufbereiten------------------------------------------------- */)
REGION (/* Farbanimation */)
(/* ********Farbcodetabelle********** */)
(/* BK=Black/Schwarz, BU=Blue/Blau */)
(/* GN=Green/Gruen, GR=Gray/Grau */)
(/* LT=Light/Hell, WH=White/Weiss */)
(/* YE=Yellow/Gelb, RD=Red/Rot */)
(/* st=Statisch, bl=blinkend */)
(/* HEX Flaechenfarben Textfarben */)
(/* 00: Flaeche GR st Text BK st */)
(/* 01: nicht sichtbar */)
(/* 02: Flaeche GN st Text BK st */)
(/* 03: Flaeche BU st Text WH st */)
(/* 04: Flaeche RD st Text WH st */)
(/* 05: Flaeche LTBU st Text WH st */)
(/* 06: Flaeche YE st Text BK st */)
(/* 07: Flaeche LTBU st Text YE st */)
(/* 08: Flaeche GR st Text GN st */)
(/* 09: Flaeche GR st Text BU st */)
(/* 0A: Flaeche GR st Text YE st */)
(/* 0B: Flaeche GN bl Text BK st */)
(/* 0C: Flaeche BU bl Text WH bl */)
(/* 0D: Flaeche RD bl Text WH bl */)
(/* 0E: Flaeche LTBU bl Text WH bl */)
(/* 0F: Flaeche YE bl Text BK st */)
(/* 10: Flaeche GR st Text GN bl */)
(/* 11: Flaeche GR st Text BU bl */)
(/* 12: Flaeche GR st Text YE bl */)
(/* 13: Flaeche GN st Text YE bl */)
(/* 14: Flaeche BU st Text YE bl */)
(/* 15: Flaeche LTBU st Text YE bl */)
(/* 16: Flaeche LTBU bl Text YE bl */)
(* ********************************)
#"HMI-UDT".arVisuWerte[0].D_Word.%X0 := #Frg_Korr;
#"HMI-UDT".dwVisuWerte1.%B3 := BOOL_TO_BYTE(#Frg_Korr);
(/* - (#Laenge) */)
#"HMI-UDT".arVisuWerte[0].D_Word.%B1 := INT_TO_BYTE(#iLaenge);
#"HMI-UDT".dwVisuWerte1.%B2 := INT_TO_BYTE(#iLaenge);
(/* - (#iZeiger) */)
#"HMI-UDT".arVisuWerte[0].D_Word.%B2 := INT_TO_BYTE(#iZeiger);
#"HMI-UDT".dwVisuWerte1.%B1 := INT_TO_BYTE(#iZeiger);
END_REGION
REGION (/* Ausgaben */)
(/* Umladen der Nutzdaten */)
FOR #iZeiger := 0 TO 50 DO
#Typ_Daten[#iZeiger] := #"HMI-UDT".arVisuWerte[#iZeiger].D_Word;
END_FOR;
(/* Status ausgeben */)
#Leer := #xLeer;
#Voll := #xVoll;
END_REGION
(/* Ende */)
3、功能块深度解读:
1. 功能块概述
这是一个**LIFO(Last In First Out,后进先出)**数据缓冲区功能块,主要用于:
- 数据的临时存储和管理
- HMI人机界面的数据交互
- 支持可视化操作(插入、修改、删除)
2. 输入输出接口分析
输入参数(Input)
- In:
Bool - 数据输入触发信号
- Out:
Bool - 数据输出触发信号
- Daten_In:
DWord - 要存入LIFO的数据
- Laenge:
Int - LIFO缓冲区长度设置
- Frg_Korr:
Bool - 修正/编辑权限标志
输出参数(Output)
- Leer:
Bool - LIFO为空标志
- Voll:
Bool - LIFO已满标志
- Anzahl:
Int - 当前LIFO中数据个数
- Daten_Out:
DWord - 从LIFO输出的数据
输入输出参数(InOut)
- In_Done:
Bool - 输入完成标志
- Out_Done:
Bool - 输出完成标志
- Typ_Daten:
Array[0..50] of DWord - 数据类型数组
3. 核心程序逻辑解读
3.1 数据初始化和长度检查
(/* 数据载入 */)
FOR #iZeiger := 0 TO 50 DO
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #Typ_Daten[#iZeiger];
END_FOR;
#iZeiger := BYTE_TO_INT(#"HMI-UDT".arVisuWerte[0].D_Word.%B2);
(/* 长度检查 */)
#iLaenge := #Laenge;
IF #iLaenge < 1 OR #iLaenge > 50 THEN
#iLaenge := 50;
END_IF;
解读:
- 将外部数据数组复制到内部HMI数据结构
- 从数据的第2字节获取当前指针位置
- 限制LIFO长度在1-50范围内,超出则默认为50
3.2 LIFO状态检查
(/* LIFO边界检查 */)
#xLeer := (#iZeiger < 1);
#xVoll := (#iZeiger >= #iLaenge);
解读:
- xLeer:
当指针小于1时,LIFO为空
- xVoll:
当指针大于等于设定长度时,LIFO已满
3.3 数据入栈操作
(/* 存入新数据记录 */)
#R_TRIG_In(CLK := #In AND NOT #xVoll);
IF #R_TRIG_In.Q AND NOT #In_Done THEN
#iZeiger := #iZeiger + 1;
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #Daten_In;
#In_Done := True;
END_IF;
解读:
- 使用上升沿检测(R_TRIG)确保只在In信号上升沿时执行一次
- 条件:In信号有效 且 LIFO未满 且 未完成输入
- 执行:指针加1,存入数据,设置完成标志
3.4 数据出栈操作
(/* 取出数据记录 */)
#R_TRIG_Out(CLK := #Out AND (#In_Done OR NOT #In) AND NOT #xLeer);
IF #R_TRIG_Out.Q AND NOT #Out_Done THEN
#Daten_Out := #"HMI-UDT".arVisuWerte[#iZeiger].D_Word;
(/* 清除已释放的数据字段并调整指针 */)
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #dwLeerdaten;
#iZeiger := #iZeiger - 1;
#Out_Done := True;
END_IF;
解读:
- 条件:Out信号有效 且 (输入已完成或无输入) 且 LIFO非空
- 执行:输出栈顶数据,清空该位置,指针减1,设置完成标志
4. HMI可视化控制
4.1 按钮可见性控制
(/* 重置按钮可见性 */)
#"HMI-UDT".dwVisuWerte1.%X0 := FALSE; // 插入按钮
#"HMI-UDT".dwVisuWerte1.%X1 := FALSE; // 修改按钮
#"HMI-UDT".dwVisuWerte1.%X2 := FALSE; // 删除按钮
#"HMI-UDT".dwVisuWerte1.%X3 := FALSE;
(/* 根据权限和状态设置按钮可见性 */)
IF #Frg_Korr THEN
IF (#iZeiger <= 0) THEN
// LIFO空时显示修改和删除按钮
#"HMI-UDT".arVisuWerte[0].D_Word.%X25 := True; // 修改
#"HMI-UDT".arVisuWerte[0].D_Word.%X26 := True; // 删除
END_IF;
IF (#iZeiger >= #iLaenge) THEN
// LIFO满时显示插入按钮
#"HMI-UDT".arVisuWerte[0].D_Word.%X24 := True; // 插入
END_IF;
END_IF;
4.2 HMI操作处理
#bBefehl := #"HMI-UDT".dwVisuTasten2.%B3; // 命令类型
#iVisuZeiger := BYTE_TO_INT(#"HMI-UDT".dwVisuTasten2.%B2); // 操作位置
(/* 插入操作 - 命令=1 */)
IF #bBefehl = Byte#1 AND NOT #xVoll THEN
IF #iVisuZeiger <= #iZeiger THEN
// 在指定位置插入,需要移动后续数据
#iZeiger := #iZeiger + 1;
#iHM_Zaehler1 := #iZeiger;
REPEAT
#iHM_Zaehler2 := #iHM_Zaehler1 - 1;
#"HMI-UDT".arVisuWerte[#iHM_Zaehler1] := #"HMI-UDT".arVisuWerte[#iHM_Zaehler2];
#iHM_Zaehler1 := #iHM_Zaehler1 - 1;
UNTIL #iHM_Zaehler2 = #iVisuZeiger
END_REPEAT;
#"HMI-UDT".arVisuWerte[#iVisuZeiger].D_Word := #"HMI-UDT".dwVisuTasten1;
ELSE
// 在末尾插入
#iZeiger := #iZeiger + 1;
#"HMI-UDT".arVisuWerte[#iZeiger].D_Word := #"HMI-UDT".dwVisuTasten1;
END_IF;
END_IF;
(/* 修改操作 - 命令=2 */)
IF #bBefehl = Byte#2 AND #iVisuZeiger <= #iZeiger THEN
#"HMI-UDT".arVisuWerte[#iVisuZeiger].D_Word := #"HMI-UDT".dwVisuTasten1;
END_IF;
(/* 删除操作 - 命令=3 */)
IF #bBefehl = Byte#3 AND #iVisuZeiger <= #iZeiger THEN
#iZeiger := #iZeiger - 1;
// 将后续数据前移
FOR #iHM_Zaehler1 := #iVisuZeiger TO #iZeiger DO
#iHM_Zaehler2 := #iHM_Zaehler1 + 1;
#"HMI-UDT".arVisuWerte[#iHM_Zaehler1] := #"HMI-UDT".arVisuWerte[#iHM_Zaehler2];
END_FOR;
#"HMI-UDT".arVisuWerte[#iHM_Zaehler2].D_Word := #dwLeerdaten;
END_IF;
5. 颜色动画和状态显示
程序包含详细的颜色编码表,用于HMI界面的状态显示:
颜色代码表:
00: 灰色背景,黑色文字(静态)
01: 不可见
02: 绿色背景,黑色文字(静态)
03: 蓝色背景,白色文字(静态)
04: 红色背景,白色文字(静态)
05: 浅蓝背景,白色文字(静态)
06: 黄色背景,黑色文字(静态)
...
0B-0F: 闪烁效果
10-16: 文字闪烁效果
6. 数据输出和状态更新
(/* 输出数据更新 */)
FOR #iZeiger := 0 TO 50 DO
#Typ_Daten[#iZeiger] := #"HMI-UDT".arVisuWerte[#iZeiger].D_Word;
END_FOR;
(/* 状态输出 */)
#Leer := #xLeer;
#Voll := #xVoll;
#Anzahl := #iZeiger;
7. 主要特点总结
1 标准LIFO操作:
支持后进先出的数据存取
2 HMI集成:
完整的人机界面交互支持
3 可视化操作:
支持插入、修改、删除操作
4 权限控制:
通过Frg_Korr参数控制编辑权限
5 状态反馈:
提供空、满状态和数据数量信息
6 错误防护:
包含边界检查和参数验证
7 多语言支持:
代码注释支持多语言
766
