24 KiB
24 KiB
1. System Architecture
1.1 Call Structure
OB1
├── FC_Ttop_Run
│ ├── FC_Table_Motor_M316() → "DB Motor M316"(FB_Motors_Manage)
│ ├── FC_Table_Motor_M317() → "DB Motor M317"(FB_Motors_Manage)
│ ├── FC_Table_Motor_M318() → "DB Motor M318"(FB_Motors_Manage)
│ ├── FC_Table_Motor_M319() → "DB Motor M319"(FB_Motors_Manage)
│ ├── FC_Table_Motor_M328() → "DB Motor M328"(FB_Motors_Manage) // Channel 1
│ ├── FC_Table_Motor_M329() → "DB Motor M329"(FB_Motors_Manage) // Channel 2
│ ├── FC_Table_Motor_M330() → "DB Motor M330"(FB_Motors_Manage) // Channel 3
│ ├── FC_Table_Motor_M331() → "DB Motor M331"(FB_Motors_Manage) // Channel 4
│ ├── FC_Table_Motor_M332() → "DB Motor M332"(FB_Motors_Manage) // Channel 5 (center)
│ ├── FC_Table_Motor_M333() → "DB Motor M333"(FB_Motors_Manage) // Channel 6
│ ├── FC_Table_Motor_M334() → "DB Motor M334"(FB_Motors_Manage) // Channel 7
│ ├── FC_Table_Motor_M335() → "DB Motor M335"(FB_Motors_Manage) // Channel 8
│ ├── FC_Table_Motor_M336() → "DB Motor M336"(FB_Motors_Manage) // Channel 9
│ ├── FC_Table_Motor_M340() → "DB Motor M340"(FB_Motors_Manage)
│ ├── FC_Table_Motor_M341() → "DB Motor M341"(FB_Motors_Manage)
│ ├── FC_Table_Motor_M342() → "DB Motor M342"(FB_Motors_Manage)
│ └── FC_Table_Motor_M343() → "DB Motor M343"(FB_Motors_Manage)
└── FC_Table_Devices
└── "DB Table"(FB_Table)
1.2 Component Mapping
- M316, M317: Input feeders (left, right)
- M318: Format change input feeders
- M319: Input selector
- M328-M336: Channels 1-9 (1=leftmost, 5=center/bypass, 9=rightmost)
- M340: Output selector
- M341, M342: Output feeders (left, right)
- M343: Format change output feeders
2. Data Structures
2.1 Format Data Structure
TYPE T_Format_Data:
STRUCT
Format_Number : Int; // Format number (1 or 2)
Accumulation_Side : Int; // 1=Left (channels 1-4), 2=Right (channels 6-9)
Bottle_Dimension_mm : Real; // Bottle dimension in mm
Max_Speed_mm_min : Real; // Maximum speed in mm/min
Target_Channels : Array[1..4] of Int; // Channels to use for this format
END_STRUCT;
2.2 External Exchange Database
DB_ATable_Exchange:
STRUCT
// === INPUT SIGNALS (from external systems) ===
IN : STRUCT
// From Ring/Divider
Ring_Input_Product_Available : Bool; // Product available at input
Ring_Output_Request : Bool; // Ring requests product output
Ring_Empty_And_Auto : Bool; // Ring empty and divider in auto
Ring_Bypass_Speed_Request : Real; // Requested bypass speed
// Commands
Load_Request : Bool; // Request to start loading
Format_Change_Command : Bool; // Format change command from HMI
Unload_Enable : Bool; // Enable automatic unload after format change
// System status
System_Auto_Mode : Bool; // System in automatic mode
Emergency_Stop : Bool; // Emergency stop signal
END_STRUCT;
// === OUTPUT SIGNALS (to external systems) ===
OUT : STRUCT
// To Ring/Divider
Input_Request_Product : Bool; // Table ready and requesting input
Format_Change_Allowed : Bool; // Loading complete and ring empty
Output_Speed_Reference : Real; // Speed reference for output motor
Table_In_Bypass : Bool; // Table in bypass mode
// Status
Table_State : Int; // Current table state
Current_Format : Int; // Currently stored format
Table_Ready : Bool; // Table ready for operation
Loading_Complete : Bool; // Loading sequence complete
Unloading_Complete : Bool; // Unloading sequence complete
END_STRUCT;
END_STRUCT;
2.3 Table States
CONST
TABLE_STATE_STOPPED : Int := 0;
TABLE_STATE_LOADING : Int := 1;
TABLE_STATE_BYPASS : Int := 2;
TABLE_STATE_UNLOADING : Int := 3;
TABLE_STATE_ERROR : Int := 4;
END_CONST;
3. Main Function Block - FB_Table
3.1 Interface
FB_Table:
VAR_INPUT
Enable : Bool; // Table enable
Target_Format : Int; // Target format (1 or 2)
Manual_Mode : Bool; // Manual operation mode
END_VAR
VAR_IN_OUT
// Motor structure references (pointers)
Motor_M316 : UDT_Motor_Manage; // Input feeder left
Motor_M317 : UDT_Motor_Manage; // Input feeder right
Motor_M318 : UDT_Motor_Manage; // Format change input
Motor_M319 : UDT_Motor_Manage; // Input selector
Motor_M328 : UDT_Motor_Manage; // Channel 1
Motor_M329 : UDT_Motor_Manage; // Channel 2
Motor_M330 : UDT_Motor_Manage; // Channel 3
Motor_M331 : UDT_Motor_Manage; // Channel 4
Motor_M332 : UDT_Motor_Manage; // Channel 5 (center)
Motor_M333 : UDT_Motor_Manage; // Channel 6
Motor_M334 : UDT_Motor_Manage; // Channel 7
Motor_M335 : UDT_Motor_Manage; // Channel 8
Motor_M336 : UDT_Motor_Manage; // Channel 9
Motor_M340 : UDT_Motor_Manage; // Output selector
Motor_M341 : UDT_Motor_Manage; // Output feeder left
Motor_M342 : UDT_Motor_Manage; // Output feeder right
Motor_M343 : UDT_Motor_Manage; // Format change output
Exchange : DB_ATable_Exchange; // External communication
END_VAR
VAR_OUTPUT
Table_State : Int; // Current state
Error_Code : Word; // Error code
Diagnostics : T_Table_Diagnostics; // Diagnostic information
END_VAR
VAR_STAT
// === COMMAND STRUCTURE (Read by FC motors) ===
Status : STRUCT
// Input feeders
Input_Feeders_Enable : Bool;
Input_Feeders_Speed_mm_min : Real;
Input_Feeders_Stop_After_Bottle : Bool;
// Output feeders
Output_Feeders_Enable : Bool;
Output_Feeders_Speed_mm_min : Real;
Output_Feeders_Stop_After_Bottle : Bool;
// Input selector
Input_Selector_Enable : Bool;
Input_Selector_Target_Channel : Int;
Input_Selector_Positioning_Mode : Bool;
// Output selector
Output_Selector_Enable : Bool;
Output_Selector_Target_Channel : Int;
Output_Selector_Positioning_Mode : Bool;
// Channels
Channel_Enable : Array[1..9] of Bool;
Channel_Speed_mm_min : Array[1..9] of Real;
// Format change motors
Format_Change_Input_Enable : Bool;
Format_Change_Input_Target_mm : Real;
Format_Change_Output_Enable : Bool;
Format_Change_Output_Target_mm : Real;
END_STRUCT;
// === INTERNAL LOGIC VARIABLES ===
Current_State : Int;
Previous_State : Int;
Loading_Step : Int;
Unloading_Step : Int;
Current_Loading_Channel : Int;
Current_Unloading_Channel : Int;
// Format configuration
Format_Data : Array[1..2] of T_Format_Data;
Current_Format_Stored : Int;
// Timers
State_Timer : TON;
Operation_Timeout : TON;
// Area management instances
Area_Input_Selector : FB_Area_Management;
Area_Channel : Array[1..9] of FB_Area_Management;
Area_Output_Selector : FB_Area_Management;
// Virtual encoders for position tracking
Encoder_M332 : FB_Virtual_Encoder; // Center channel for bypass tracking
Encoder_Input_Selector : FB_Virtual_Encoder;
Encoder_Output_Selector : FB_Virtual_Encoder;
END_VAR
3.2 Main Logic (Pseudocode)
// === STATE MACHINE MANAGEMENT ===
CASE Current_State OF
TABLE_STATE_STOPPED:
IF Enable AND Exchange.IN.System_Auto_Mode THEN
IF Exchange.IN.Load_Request THEN
Current_State := TABLE_STATE_LOADING;
Loading_Step := 1;
ELSIF Exchange.IN.Ring_Output_Request AND (Current_Format_Stored > 0) THEN
Current_State := TABLE_STATE_UNLOADING;
Unloading_Step := 1;
END_IF;
END_IF;
TABLE_STATE_LOADING:
Execute_Loading_Sequence();
IF Loading_Complete THEN
Current_State := TABLE_STATE_BYPASS;
Exchange.OUT.Loading_Complete := TRUE;
END_IF;
TABLE_STATE_BYPASS:
Execute_Bypass_Mode();
IF Exchange.IN.Format_Change_Command AND Exchange.IN.Ring_Empty_And_Auto THEN
Current_State := TABLE_STATE_UNLOADING;
Unloading_Step := 1;
END_IF;
TABLE_STATE_UNLOADING:
Execute_Unloading_Sequence();
IF Unloading_Complete THEN
Current_State := TABLE_STATE_BYPASS;
Exchange.OUT.Unloading_Complete := TRUE;
Current_Format_Stored := 0;
END_IF;
TABLE_STATE_ERROR:
Execute_Error_Recovery();
END_CASE;
// === UPDATE EXTERNAL SIGNALS ===
Exchange.OUT.Table_State := Current_State;
Exchange.OUT.Current_Format := Current_Format_Stored;
Exchange.OUT.Table_Ready := (Current_State <> TABLE_STATE_ERROR);
Exchange.OUT.Format_Change_Allowed := (Current_State = TABLE_STATE_BYPASS) AND
(Current_Format_Stored > 0) AND
Exchange.IN.Ring_Empty_And_Auto;
// === AREA MANAGEMENT UPDATES ===
FOR i := 1 TO 9 DO
Area_Channel[i](
Motor := Get_Channel_Motor_Reference(i),
Enable := Status.Channel_Enable[i],
Area_Length_mm := Get_Channel_Length(i),
Bottle_Length_mm := Format_Data[Target_Format].Bottle_Dimension_mm
);
END_FOR;
4. Loading Sequence Logic
4.1 Loading Sequence Steps
PROCEDURE Execute_Loading_Sequence:
VAR
Target_Channels : Array[1..4] of Int;
Current_Channel : Int;
Channel_Index : Int;
BEGIN
// Get target channels for current format
Target_Channels := Get_Target_Channels_For_Format(Target_Format);
CASE Loading_Step OF
1: // Initialize loading
Current_Loading_Channel := Get_Outermost_Channel(Target_Format);
Channel_Index := 1;
Position_Input_Selector(Target_Channels[Channel_Index]);
Loading_Step := 2;
2: // Wait for selector positioning
IF Input_Selector_In_Position THEN
Enable_Channel_Motors_For_Loading(Current_Loading_Channel);
Enable_Input_Feeders();
Loading_Step := 3;
END_IF;
3: // Load current channel
IF Channel_Loading_Complete(Current_Loading_Channel) THEN
Disable_Input_Feeders();
Channel_Index := Channel_Index + 1;
IF Channel_Index <= 4 THEN
Current_Loading_Channel := Target_Channels[Channel_Index];
Position_Input_Selector(Current_Loading_Channel);
Loading_Step := 2;
ELSE
Loading_Step := 4; // All channels loaded
END_IF;
END_IF;
4: // Loading complete
Disable_All_Channel_Motors();
Position_Selectors_To_Bypass();
Current_Format_Stored := Target_Format;
Loading_Complete := TRUE;
END_CASE;
END_PROCEDURE;
FUNCTION Get_Target_Channels_For_Format(Format : Int) : Array[1..4] of Int:
BEGIN
IF Format_Data[Format].Accumulation_Side = 1 THEN // Left side
RETURN [1, 2, 3, 4]; // Load from outside to inside
ELSE // Right side
RETURN [9, 8, 7, 6]; // Load from outside to inside
END_IF;
END_FUNCTION;
FUNCTION Get_Outermost_Channel(Format : Int) : Int:
BEGIN
IF Format_Data[Format].Accumulation_Side = 1 THEN
RETURN 1; // Leftmost channel
ELSE
RETURN 9; // Rightmost channel
END_IF;
END_FUNCTION;
PROCEDURE Enable_Channel_Motors_For_Loading(Target_Channel : Int):
BEGIN
// Enable all channels from center to target channel
FOR i := 5 TO Target_Channel DO // or FROM Target_Channel TO 5
Status.Channel_Enable[i] := TRUE;
Status.Channel_Speed_mm_min[i] := Format_Data[Target_Format].Max_Speed_mm_min;
END_FOR;
END_PROCEDURE;
5. Unloading Sequence Logic
5.1 Unloading Sequence Steps
PROCEDURE Execute_Unloading_Sequence:
VAR
Stored_Channels : Array[1..4] of Int;
Current_Channel : Int;
Channel_Index : Int;
BEGIN
// Get channels where current format is stored
Stored_Channels := Get_Target_Channels_For_Format(Current_Format_Stored);
CASE Unloading_Step OF
1: // Initialize unloading - start from innermost channel
Channel_Index := 4; // Start from innermost
Current_Unloading_Channel := Stored_Channels[Channel_Index];
Position_Output_Selector(Current_Unloading_Channel);
Unloading_Step := 2;
2: // Wait for selector positioning
IF Output_Selector_In_Position THEN
Enable_Channel_Motors_For_Unloading(Current_Unloading_Channel);
Enable_Output_Feeders();
Unloading_Step := 3;
END_IF;
3: // Unload current channel
IF Channel_Unloading_Complete(Current_Unloading_Channel) THEN
Disable_Output_Feeders();
Channel_Index := Channel_Index - 1;
IF Channel_Index >= 1 THEN
Current_Unloading_Channel := Stored_Channels[Channel_Index];
Position_Output_Selector(Current_Unloading_Channel);
Unloading_Step := 2;
ELSE
Unloading_Step := 4; // All channels unloaded
END_IF;
END_IF;
4: // Unloading complete
Disable_All_Channel_Motors();
Position_Selectors_To_Bypass();
Unloading_Complete := TRUE;
END_CASE;
END_PROCEDURE;
PROCEDURE Enable_Channel_Motors_For_Unloading(Target_Channel : Int):
BEGIN
// Enable all channels from target channel to center
FOR i := Target_Channel TO 5 DO // or FROM 5 TO Target_Channel
Status.Channel_Enable[i] := TRUE;
Status.Channel_Speed_mm_min[i] := Format_Data[Current_Format_Stored].Max_Speed_mm_min;
END_FOR;
END_PROCEDURE;
6. Bypass Mode Logic
6.1 Bypass Operation
PROCEDURE Execute_Bypass_Mode:
BEGIN
// Enable only center channel for bypass
Status.Channel_Enable[5] := TRUE;
Status.Channel_Speed_mm_min[5] := Exchange.IN.Ring_Bypass_Speed_Request;
// Disable all other channels
FOR i := 1 TO 9 DO
IF i <> 5 THEN
Status.Channel_Enable[i] := FALSE;
END_IF;
END_FOR;
// Position selectors to bypass (channel 5)
Status.Input_Selector_Target_Channel := 5;
Status.Output_Selector_Target_Channel := 5;
Status.Input_Selector_Enable := TRUE;
Status.Output_Selector_Enable := TRUE;
// Update external signals
Exchange.OUT.Table_In_Bypass := TRUE;
Exchange.OUT.Output_Speed_Reference := Exchange.IN.Ring_Bypass_Speed_Request;
Exchange.OUT.Input_Request_Product := Exchange.IN.Ring_Input_Product_Available;
END_PROCEDURE;
7. Auxiliary Function Blocks
7.1 FB_Virtual_Encoder
FB_Virtual_Encoder:
VAR_IN_OUT
Motor : UDT_Motor_Manage; // Motor structure reference
END_VAR
VAR_INPUT
Enable : Bool; // Enable calculation
Ratio_Hz_to_mm_min : Real; // Conversion factor Hz to mm/min
Reset_Position : Bool; // Reset total position
END_VAR
VAR_OUTPUT
Displacement_mm : Real; // Displacement since last call
Current_Speed_mm_min : Real; // Current speed in mm/min
Total_Distance_mm : Real; // Total accumulated distance
Motor_Running : Bool; // Motor running status
END_VAR
VAR_STAT
Last_Frequency_Hz : Real;
Last_Scan_Time : Time;
Position_Accumulated : Real;
END_VAR
// Pseudocode:
BEGIN
IF Enable THEN
Current_Frequency := Read_Motor_Frequency(Motor);
Current_Time := Get_System_Time();
IF First_Scan THEN
Last_Frequency_Hz := Current_Frequency;
Last_Scan_Time := Current_Time;
ELSE
Time_Delta := Current_Time - Last_Scan_Time;
Avg_Frequency := (Current_Frequency + Last_Frequency_Hz) / 2;
Speed_mm_min := Avg_Frequency * Ratio_Hz_to_mm_min;
Displacement_mm := Speed_mm_min * Time_Delta_In_Minutes;
IF NOT Reset_Position THEN
Total_Distance_mm := Total_Distance_mm + Displacement_mm;
ELSE
Total_Distance_mm := 0;
END_IF;
Last_Frequency_Hz := Current_Frequency;
Last_Scan_Time := Current_Time;
END_IF;
Current_Speed_mm_min := Current_Frequency * Ratio_Hz_to_mm_min;
Motor_Running := Motor.STATUS_RUN;
ELSE
Displacement_mm := 0;
Current_Speed_mm_min := 0;
END_IF;
END_FUNCTION_BLOCK;
7.2 FB_Area_Management
FB_Area_Management:
VAR_IN_OUT
Motor : UDT_Motor_Manage; // Motor of this area
END_VAR
VAR_INPUT
Enable : Bool; // Area enable
Area_Length_mm : Real; // Total area length
Bottle_Length_mm : Real; // Bottle dimension
Photocell_Pulse : Bool; // Entry photocell pulse
Reset_Bottles : Bool; // Reset bottle tracking
END_VAR
VAR_OUTPUT
First_Bottle_Position : Real; // Position of first bottle
Last_Bottle_Position : Real; // Position of last bottle
Area_Empty : Bool; // Area completely empty
Bottles_In_Initial_Zone : Bool; // Bottles in initial zone
Bottles_In_Final_Zone : Bool; // Bottles in final zone
Bottle_Count : Int; // Number of bottles in area
END_VAR
VAR_STAT
Virtual_Encoder : FB_Virtual_Encoder;
Bottle_Positions : Array[1..50] of Real; // Track up to 50 bottles
Active_Bottles : Int;
Photocell_Pulse_Edge : R_TRIG;
END_VAR
// Pseudocode:
BEGIN
Virtual_Encoder(
Motor := Motor,
Enable := Enable,
Ratio_Hz_to_mm_min := Calculate_Area_Ratio()
);
// Detect new bottle entry
Photocell_Pulse_Edge(CLK := Photocell_Pulse);
IF Photocell_Pulse_Edge.Q THEN
Add_New_Bottle_To_Tracking();
END_IF;
// Update all bottle positions
FOR i := 1 TO Active_Bottles DO
Bottle_Positions[i] := Bottle_Positions[i] - Virtual_Encoder.Displacement_mm;
// Remove bottles that have exited the area
IF Bottle_Positions[i] <= 0 THEN
Remove_Bottle_From_Tracking(i);
END_IF;
END_FOR;
// Calculate outputs
IF Active_Bottles = 0 THEN
Area_Empty := TRUE;
First_Bottle_Position := 0;
Last_Bottle_Position := 0;
ELSE
Area_Empty := FALSE;
First_Bottle_Position := Find_Minimum_Position();
Last_Bottle_Position := Find_Maximum_Position();
END_IF;
Bottles_In_Initial_Zone := Check_Bottles_In_Zone(Area_Length_mm * 0.8, Area_Length_mm);
Bottles_In_Final_Zone := Check_Bottles_In_Zone(0, Area_Length_mm * 0.2);
Bottle_Count := Active_Bottles;
END_FUNCTION_BLOCK;
8. Motor-Specific Function Examples
8.1 FC_Table_Motor_M316 (Input Feeder Left)
FC_Table_Motor_M316:
VAR_IN_OUT
Motor : UDT_Motor_Manage;
Table_Status : T_Table_Status_Commands; // Reference to FB_Table.Status
END_VAR
// Pseudocode:
BEGIN
// === MOTOR CONFIGURATION ===
Motor.CFG_VFD := TRUE;
Motor.CFG_PN := TRUE;
Motor.CFG_Inverter_Type := Inverter_Type_MINIMOTOR;
Motor.CFG_Min_Speed_Hz := 10;
Motor.CFG_Max_Speed_Hz := 500;
// === READ COMMANDS FROM TABLE LOGIC ===
Motor.REQ_EN_Run := Table_Status.Input_Feeders_Enable;
IF Table_Status.Input_Feeders_Enable THEN
Motor.REQ_Speed_Fix_01 := TRUE;
Motor.OUT_VFD_REQ_Speed_User := Convert_mm_min_to_User_Units(Table_Status.Input_Feeders_Speed_mm_min);
// Feeder-specific logic: synchronized operation with M317
Check_Synchronization_With_M317();
// Stop after bottle detection if requested
IF Table_Status.Input_Feeders_Stop_After_Bottle THEN
Implement_Stop_After_Bottle_Logic();
END_IF;
ELSE
Motor.REQ_Speed_Fix_01 := FALSE;
END_IF;
// === CALL MOTOR MANAGEMENT FB ===
FB_Motors_Manage(Motor);
END_FUNCTION;
8.2 FC_Table_Motor_M319 (Input Selector)
FC_Table_Motor_M319:
VAR_IN_OUT
Motor : UDT_Motor_Manage;
Table_Status : T_Table_Status_Commands;
END_VAR
// Pseudocode:
BEGIN
// === MOTOR CONFIGURATION ===
Motor.CFG_VFD := TRUE;
Motor.CFG_PN := TRUE;
Motor.CFG_Inverter_Type := Inverter_Type_MINIMOTOR;
// === POSITIONING MODE SETUP ===
IF Table_Status.Input_Selector_Positioning_Mode THEN
Setup_Positioning_Mode();
Target_Position := Get_Position_For_Channel(Table_Status.Input_Selector_Target_Channel);
Motor.REQ_Target_Position := Target_Position;
Motor.REQ_Positioning_Enable := Table_Status.Input_Selector_Enable;
ELSE
Setup_Velocity_Mode();
Motor.REQ_EN_Run := Table_Status.Input_Selector_Enable;
END_IF;
// === CALL MOTOR MANAGEMENT FB ===
FB_Motors_Manage(Motor);
END_FUNCTION;
8.3 FC_Table_Motor_M332 (Center Channel - Bypass)
FC_Table_Motor_M332:
VAR_IN_OUT
Motor : UDT_Motor_Manage;
Table_Status : T_Table_Status_Commands;
END_VAR
// Pseudocode:
BEGIN
// === MOTOR CONFIGURATION ===
Motor.CFG_VFD := TRUE;
Motor.CFG_PN := TRUE;
Motor.CFG_Inverter_Type := Inverter_Type_G120C_SIEMENS;
// === READ COMMANDS FROM TABLE LOGIC ===
Motor.REQ_EN_Run := Table_Status.Channel_Enable[5]; // Channel 5 = center
IF Table_Status.Channel_Enable[5] THEN
Motor.REQ_Speed_Fix_01 := TRUE;
Motor.OUT_VFD_REQ_Speed_User := Convert_mm_min_to_User_Units(Table_Status.Channel_Speed_mm_min[5]);
ELSE
Motor.REQ_Speed_Fix_01 := FALSE;
END_IF;
// === CALL MOTOR MANAGEMENT FB ===
FB_Motors_Manage(Motor);
END_FUNCTION;
9. Error Handling
9.1 Basic Error Detection
PROCEDURE Check_Basic_Errors:
BEGIN
Error_Code := 0;
// Check motor inverter errors
IF Motor_M316.Alarm_02 OR Motor_M317.Alarm_02 THEN
Error_Code := Error_Code OR 16#0001; // Input feeders inverter error
END_IF;
IF Motor_M341.Alarm_02 OR Motor_M342.Alarm_02 THEN
Error_Code := Error_Code OR 16#0002; // Output feeders inverter error
END_IF;
// Check selector positioning errors
IF Motor_M319.Alarm_02 THEN
Error_Code := Error_Code OR 16#0004; // Input selector error
END_IF;
IF Motor_M340.Alarm_02 THEN
Error_Code := Error_Code OR 16#0008; // Output selector error
END_IF;
// Check channel motor errors
FOR i := 1 TO 9 DO
IF Get_Channel_Motor_Alarm(i) THEN
Error_Code := Error_Code OR (16#0010 SHL i); // Channel motor error
END_IF;
END_FOR;
// Transition to error state if errors detected
IF Error_Code <> 0 THEN
Current_State := TABLE_STATE_ERROR;
END_IF;
END_PROCEDURE;
10. Configuration and Initialization
10.1 Format Configuration Example
PROCEDURE Initialize_Format_Data:
BEGIN
// Format 1 - Left side accumulation
Format_Data[1].Format_Number := 1;
Format_Data[1].Accumulation_Side := 1; // Left side
Format_Data[1].Bottle_Dimension_mm := 85.0;
Format_Data[1].Max_Speed_mm_min := 12000.0;
Format_Data[1].Target_Channels := [1, 2, 3, 4];
// Format 2 - Right side accumulation
Format_Data[2].Format_Number := 2;
Format_Data[2].Accumulation_Side := 2; // Right side
Format_Data[2].Bottle_Dimension_mm := 65.0;
Format_Data[2].Max_Speed_mm_min := 15000.0;
Format_Data[2].Target_Channels := [9, 8, 7, 6];
END_PROCEDURE;
10.2 Area Configuration
PROCEDURE Initialize_Area_Management:
BEGIN
// Configure each area with its specific dimensions
Area_Input_Selector.Area_Length_mm := 500.0;
Area_Output_Selector.Area_Length_mm := 500.0;
FOR i := 1 TO 9 DO
Area_Channel[i].Area_Length_mm := Get_Channel_Length(i);
END_FOR;
END_PROCEDURE;
11. Integration Points
11.1 FC_Table_Devices Integration
FC_Table_Devices:
BEGIN
// Call Table FB with all motor references and exchange data
"DB Table"(
Enable := System_Enable,
Target_Format := HMI_Selected_Format,
Manual_Mode := System_Manual_Mode,
Motor_M316 := "DB Motor M316".Manage,
Motor_M317 := "DB Motor M317".Manage,
Motor_M318 := "DB Motor M318".Manage,
Motor_M319 := "DB Motor M319".Manage,
Motor_M328 := "DB Motor M328".Manage,
Motor_M329 := "DB Motor M329".Manage,
Motor_M330 := "DB Motor M330".Manage,
Motor_M331 := "DB Motor M331".Manage,
Motor_M332 := "DB Motor M332".Manage,
Motor_M333 := "DB Motor M333".Manage,
Motor_M334 := "DB Motor M334".Manage,
Motor_M335 := "DB Motor M335".Manage,
Motor_M336 := "DB Motor M336".Manage,
Motor_M340 := "DB Motor M340".Manage,
Motor_M341 := "DB Motor M341".Manage,
Motor_M342 := "DB Motor M342".Manage,
Motor_M343 := "DB Motor M343".Manage,
Exchange := "DB ATable Exchange"
);
// Additional device coordination logic if needed
END_FUNCTION;
This specification provides a complete framework for implementing the table accumulation system while maintaining consistency with the existing motor management framework. The design allows for clear separation of concerns, easy debugging, and flexible implementation of motor-specific behaviors.