FUNCTION_BLOCK "fbFIFO"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
bInPush { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 入队命令
vInPushElement : Variant; // 入队元素
bInPeek { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 查看队首命令
bInPop { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 出队命令
bInClear { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 清空队列命令
END_VAR
VAR_OUTPUT
iOutErrorCode { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int; // 错误码输出
diOutCount { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt; // 队列元素数量
bOutQueueFull { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 队列满标志
bOutQueueEmpty { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 队列空标志
END_VAR
VAR_IN_OUT
vInOutQueue : Variant; // 队列数组
vInOutPopPeekElement : Variant; // 出队/查看元素
END_VAR
VAR
diPushIndex { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt; // 入队索引
diPopIndex { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt; // 出队索引
diCount { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt; // 队列计数
ONS_Push { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 入队上升沿检测
ONS_Pop { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 出队上升沿检测
ONS_Peek { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 查看上升沿检测
ONS_Clear { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // 清空上升沿检测
END_VAR
VAR_TEMP
iTemp : Int; // 临时变量
diQueueSize : DInt; // 队列大小
byTemp : Byte; // 临时变量
END_VAR
VAR CONSTANT
ciError_None : Bool; // 无错误
ciError_InvalidQueueSize : Int := 1; // 队列大小无效
ciError_InvalidQueueTypes : Int := 2; // 队列类型不一致
ciError_MultipleCommandsReceived : Int := 3; // 同时收到多个命令
END_VAR
BEGIN
// 使用Variant实现的先进先出队列(FIFO)
// 获取队列数组的总元素数
#diQueueSize := CountOfElements(#vInOutQueue);
// 队列大小为0,说明不是数组,队列对象无效
IF (#diQueueSize <= 0) THEN
#iOutErrorCode := #ciError_InvalidQueueSize;
RETURN;
END_IF;
// 检查队列元素类型是否一致
IF (TypeOfElements(#vInOutQueue) <> TypeOf(#vInPushElement) OR TypeOf(#vInOutPopPeekElement) <> TypeOf(#vInPushElement)) THEN
#iOutErrorCode := #ciError_InvalidQueueTypes;
RETURN;
END_IF;
// 检查同一时刻只允许一个命令(push和pop/peek可同时)
#byTemp := BOOL_TO_BYTE(#bInPop) +
BOOL_TO_BYTE(#bInPeek) +
BOOL_TO_BYTE(#bInClear);
IF (#byTemp > 1 OR (#bInPush AND #bInClear)) THEN
#iOutErrorCode := #ciError_MultipleCommandsReceived;
RETURN;
END_IF;
// 入队操作,队列未满时执行
IF (#bInPush AND NOT #ONS_Push AND #diCount < #diQueueSize) THEN
#iTemp := MOVE_BLK_VARIANT(SRC := #vInPushElement, COUNT := 1, SRC_INDEX := 0, DEST_INDEX := #diPushIndex, DEST => #vInOutQueue);
#diCount += 1;
#diPushIndex := (#diPushIndex + 1) MOD #diQueueSize;
END_IF;
// 出队或查看操作,队列非空时执行
IF ((#bInPop AND NOT #ONS_Pop) OR (#bInPeek AND NOT #ONS_Peek) AND #diCount > 0) THEN
#iTemp := MOVE_BLK_VARIANT(SRC := #vInOutQueue, COUNT := 1, SRC_INDEX := #diPopIndex, DEST_INDEX := 0, DEST => #vInOutPopPeekElement);
IF (#bInPop) THEN
#diCount -= 1;
#diPopIndex := (#diPopIndex + 1) MOD #diQueueSize;
END_IF;
// 清空队列,重置索引
ELSIF (#bInClear AND NOT #ONS_Clear) THEN
#diCount := 0;
#diPushIndex := 0;
#diPopIndex := 0;
END_IF;
// 设置队列满/空标志
IF (#diCount >= #diQueueSize) THEN
#bOutQueueFull := TRUE;
#bOutQueueEmpty := FALSE;
ELSIF (#diCount <= 0) THEN
#bOutQueueFull := FALSE;
#bOutQueueEmpty := TRUE;
ELSE
#bOutQueueFull := FALSE;
#bOutQueueEmpty := FALSE;
END_IF;
// 记录本周期命令状态,用于上升沿检测
#ONS_Pop := #bInPop;
#ONS_Peek := #bInPeek;
#ONS_Push := #bInPush;
#ONS_Clear := #bInClear;
// 清除错误码并输出队列计数
#iOutErrorCode := 0;
#diOutCount := #diCount;
END_FUNCTION_BLOCK