博文

IEC61131-3 ST语言实战 - 错误处理与通信指令

ST/PLC

IEC61131-3 ST 语言实战 - 错误处理与通信指令

1. 错误处理

1.1 手动错误检查(通用方法)

// 输入验证
FUNCTION FC_SafeDivide : REAL
VAR_INPUT
    Numerator : REAL;
    Denominator : REAL;
END_VAR
VAR_OUTPUT
    Error : BOOL;
    ErrorMsg : STRING[80];
END_VAR

IF Denominator = 0.0 THEN
    Error := TRUE;
    ErrorMsg := 'Error: Division by zero';
    FC_SafeDivide := 0.0;
    RETURN;
END_IF;

Error := FALSE;
FC_SafeDivide := Numerator / Denominator;

END_FUNCTION

1.2 错误码管理

// 定义错误枚举
TYPE ErrorCodes : (
    ERR_NONE = 0,
    ERR_OVERFLOW = 1,
    ERR_UNDERFLOW = 2,
    ERR_TIMEOUT = 3,
    ERR_COMMUNICATION = 4,
    ERR_INVALID_PARAM = 5
); END_TYPE

VAR
    LastError : ErrorCodes := ErrorCodes.ERR_NONE;
END_VAR

// 检查并清除错误
IF LastError <> ErrorCodes.ERR_NONE THEN
    Handle_Error(LastError);
    LastError := ErrorCodes.ERR_NONE;  // 清除错误
END_IF;

1.3 TRY-CATCH(部分平台支持)

TRY
    // 可能出错的代码
    Result := Value1 / Value2;
    Parse_Result := STRING_TO_INT(InputStr);
CATCH
    // 错误处理
    Error_Flag := TRUE;
    Error_Message := 'Division by zero or parse error';
END_TRY

// 带具体异常类型
TRY
    Process_Data();
CATCH E_DIVISION_BY_ZERO
    Handle_Zero_Division();
CATCH E_OUT_OF_RANGE
    Handle_Range_Error();
CATCH
    Handle_Generic_Error();
END_TRY

2. Modbus 通信

2.1 读保持寄存器

VAR
    MB_Read : MB_READ_HOLDING;
    Read_Data : ARRAY[0..9] OF WORD;
    Read_Done : BOOL;
    Read_Error : BOOL;
END_VAR

MB_Read(
    ENABLE := TRUE,
    MB_ADDR := 1,           // 站号
    START_ADDR := 100,      // 起始地址
    QUANTITY := 10,         // 读取数量
    DATA_PTR := Read_Data,  // 数据存储地址
    DONE => Read_Done,
    ERROR => Read_Error
);

IF Read_Done THEN
    // 处理读取的数据
    Value1 := Read_Data[0];
    Value2 := Read_Data[1];
END_IF;

2.2 写单个寄存器

VAR
    MB_Write : MB_WRITE_SINGLE;
    Write_Value : WORD;
    Write_Done : BOOL;
END_VAR

MB_Write(
    ENABLE := Write_Trigger,
    MB_ADDR := 1,
    START_ADDR := 200,
    DATA_VALUE := Write_Value,
    DONE => Write_Done,
    ERROR => Write_Error
);

IF Write_Done THEN
    Write_Trigger := FALSE;  // 清除触发
END_IF;

2.3 Modbus 功能块封装

FUNCTION_BLOCK FB_ModbusManager
VAR_INPUT
    Enable : BOOL;
    ReadTrigger : BOOL;
    WriteTrigger : BOOL;
    WriteAddress : INT;
    WriteValue : WORD;
END_VAR
VAR_OUTPUT
    ReadData : ARRAY[0..15] OF WORD;
    ReadDone : BOOL;
    WriteDone : BOOL;
    CommError : BOOL;
END_VAR
VAR
    MB_Read : MB_READ_HOLDING;
    MB_Write : MB_WRITE_SINGLE;
    ReadState : INT := 0;
    WriteState : INT := 0;
    ErrorCounter : INT := 0;
END_VAR

IF NOT Enable THEN
    ReadDone := FALSE;
    WriteDone := FALSE;
    RETURN;
END_IF;

// 读操作状态机
CASE ReadState OF
    0:  // 空闲
        IF ReadTrigger THEN
            ReadState := 1;
        END_IF;
    1:  // 执行读取
        MB_Read(
            ENABLE := TRUE,
            MB_ADDR := 1,
            START_ADDR := 0,
            QUANTITY := 16,
            DATA_PTR := ReadData,
            DONE => ReadDone,
            ERROR => CommError
        );
        IF ReadDone OR CommError THEN
            MB_Read.ENABLE := FALSE;
            ReadState := 0;
            IF CommError THEN
                ErrorCounter := ErrorCounter + 1;
            END_IF;
        END_IF;
END_CASE;

// 写操作
IF WriteTrigger AND WriteState = 0 THEN
    WriteState := 1;
END_IF;

IF WriteState = 1 THEN
    MB_Write(
        ENABLE := TRUE,
        MB_ADDR := 1,
        START_ADDR := WriteAddress,
        DATA_VALUE := WriteValue,
        DONE => WriteDone,
        ERROR => CommError
    );
    IF WriteDone OR CommError THEN
        MB_Write.ENABLE := FALSE;
        WriteState := 0;
    END_IF;
END_IF;

END_FUNCTION_BLOCK

3. 串行通信

3.1 发送数据

VAR
    Serial_Send : SERIAL_SEND;
    Send_Buffer : ARRAY[0..63] OF BYTE;
    Send_Length : INT;
END_VAR

Serial_Send(
    ENABLE := Send_Request,
    DATA_PTR := Send_Buffer,
    LENGTH := Send_Length,
    DONE => Send_Complete,
    ERROR => Send_Error
);

3.2 接收数据

VAR
    Serial_Receive : SERIAL_RECEIVE;
    Receive_Buffer : ARRAY[0..63] OF BYTE;
    Receive_Length : INT;
END_VAR

Serial_Receive(
    ENABLE := TRUE,
    DATA_PTR := Receive_Buffer,
    MAX_LENGTH := 64,
    LENGTH => Receive_Length,
    DONE => Receive_Complete
);

IF Receive_Complete THEN
    // 处理接收到的数据
    Process_Received_Data(Receive_Buffer, Receive_Length);
END_IF;

4. 通信超时处理

FUNCTION_BLOCK FB_CommWithTimeout
VAR_INPUT
    Start : BOOL;
    Timeout : TIME := T#5s;
END_VAR
VAR_OUTPUT
    Done : BOOL;
    TimeoutFlag : BOOL;
    Error : BOOL;
END_VAR
VAR
    Comm_Timer : TON;
    Comm_Started : BOOL;
END_VAR

IF Start AND NOT Comm_Started THEN
    Comm_Started := TRUE;
    Comm_Timer(IN := TRUE, PT := Timeout);
    Done := FALSE;
    TimeoutFlag := FALSE;
    Error := FALSE;
    
    // 启动通信
    Start_Communication();
END_IF;

// 检查超时
IF Comm_Started THEN
    IF Comm_Timer.Q THEN
        TimeoutFlag := TRUE;
        Error := TRUE;
        Comm_Started := FALSE;
    END_IF;
    
    // 通信完成
    IF Comm_Done_Signal THEN
        Done := TRUE;
        Comm_Started := FALSE;
        Comm_Timer(IN := FALSE);
    END_IF;
END_IF;

END_FUNCTION_BLOCK

5. 实战:通信重试机制

FUNCTION_BLOCK FB_CommRetry
VAR_INPUT
    Trigger : BOOL;
    MaxRetries : INT := 3;
    RetryDelay : TIME := T#1s;
END_VAR
VAR_OUTPUT
    Success : BOOL;
    Failed : BOOL;
    RetryCount : INT;
END_VAR
VAR
    RetryTimer : TON;
    State : INT := 0;
    Attempts : INT := 0;
END_VAR

CASE State OF
    0:  // 空闲
        IF Trigger THEN
            Attempts := 0;
            Success := FALSE;
            Failed := FALSE;
            State := 1;
        END_IF;
    
    1:  // 发起通信
        Start_Communication();
        State := 2;
    
    2:  // 等待结果
        IF Comm_Success THEN
            Success := TRUE;
            State := 0;
        ELSIF Comm_Error THEN
            Attempts := Attempts + 1;
            IF Attempts >= MaxRetries THEN
                Failed := TRUE;
                RetryCount := Attempts;
                State := 0;
            ELSE
                RetryCount := Attempts;
                RetryTimer(IN := TRUE, PT := RetryDelay);
                State := 3;
            END_IF;
        END_IF;
    
    3:  // 延时重试
        IF RetryTimer.Q THEN
            RetryTimer(IN := FALSE);
            State := 1;
        END_IF;
END_CASE;

END_FUNCTION_BLOCK

文档版本:1.0 | 更新日期:2026-04-28 | 作者:JianLin Studio

← 返回博文列表