跳转至

CatST:语言规范、STM32 编译生成与扩展路线

CatST = Company Automation Text,是公司内部专用的类 ST 文本逻辑语言。CatST 不是 PLC 平台,而是公司内部设备的安全逻辑配置语言。CatST 面向现场维护和设备调试人员,语法尽量接近 PLC ST,但运行方式不是 IEC 61131-3 解释 Runtime,而是由上位机 PLC Studio 检查、仿真、生成 UserLogic.c,再通过 ARM GCC 编译为 STM32 固件。


1. 设计目标

CatST 的目标不是做一台通用 PLC,而是为公司内部设备开发一套高度定制化的安全逻辑配置能力:

  1. 现场人员使用接近 PLC ST 的文本语言完成绝大部分控制逻辑。
  2. 上位机负责语法检查、语义检查、仿真、C 代码生成、ARM GCC 编译和下载。
  3. STM32 端只运行编译后的 C 代码,不解析 CatST,不解释脚本。
  4. 固件保留固定 Runtime、安全层、通信栈、驱动层和下载协议。
  5. CatST 允许剪裁 IEC ST,但应最大化保留可安全落地、可静态验证、可生成确定性 C 的 ST 语句和表达能力。
  6. 后续 EtherCAT、CANopen、以太网等能力通过 Runtime 通信任务和过程映像接入,CatST 不直接阻塞等待通信。
  7. 现场维护不依赖 J-Link;固定 Bootloader 固化后,通过串口完成调试、下载、监控和快速迭代。

CatST 在 ST 与 STM32 C 之间的平衡原则:

原则 说明
语法靠近 ST 使用 IFCASE:=TONCTUTIME 等现场人员熟悉的形式
语义靠近 PLC 扫描 用户逻辑按扫描周期执行,输入先采样,输出后刷新
生成结果靠近 C 所有 CatST 最终生成普通 C 函数,由固定 Runtime 调用
资源必须有界 禁止动态内存、递归、无界循环、阻塞通信和直接硬件访问
安全高于逻辑 CatST 写输出只写输出映像,固件安全层可以最终关闭物理输出
可测量可回归 AST 仿真、生成 C 仿真和实机运行应保持语义一致

2. 非目标与边界

CatST 明确不是:

不是完整 IEC 61131-3 ST
不是完整 IEC 61131-3 Runtime
不是设备端解释语言
不是 C 语言替代品
不是现场自由访问硬件的脚本环境
不是通用 PLC 产品线

CatST 禁止用户逻辑直接访问:

GPIO / UART / SPI / I2C / CAN / Ethernet MAC
Flash / RTC / Watchdog / NVIC / DMA / HAL Handle
Bootloader / 下载标志 / App CRC 标志
文件系统 / 动态内存 / 任意指针
ISR / 中断回调 / HAL Callback

这些能力只能由固件 Runtime、驱动层、通信层或受控系统函数实现,并以变量区或专用 API 的形式暴露给 CatST。

中断、DMA、定时器捕获和通信接收属于 Runtime 能力。CatST 不允许用户编写中断子函数,只能通过 InterruptModel.md 定义的事件映像、高速计数器、捕获值和过程映像读取中断结果。


3. 总体架构

logic.catst
PLC Studio
 ├── Lexer 词法分析
 ├── Parser 语法分析
 ├── AST 语法树
 ├── Semantic 语义检查
 ├── Safety 安全检查
 ├── Resource 资源预算检查
 ├── Simulator AST 仿真
 ├── C CodeGen 生成 UserLogic.c
 └── ARM GCC 编译 app.bin
Bootloader 下载到 STM32
STM32 Application
 ├── 固定 PLC Runtime
 ├── 固定通信任务
 ├── 固定安全层
 └── UserLogic_Init / UserLogic_Scan

STM32 扫描模型以 Firmware.md 为准:

读取物理输入
输入滤波
更新 X 输入映像区
RUN 模式下执行 UserLogic_Scan()
执行安全策略
刷新 Y/R 物理输出
处理通信、参数、诊断、看门狗

CatST 只生成 UserLogic_Init()UserLogic_Scan() 的受控代码,不生成 main(),不改变固件任务调度。


4. 语言等级与目标板 Profile

CatST 使用“语言等级 + 目标板 Profile”控制功能范围。

4.1 语言等级

等级 定位 必须满足
CatST-Core 第一版核心语言 支持赋值、表达式、IFCASE、定时器、计数器、边沿检测,无动态内存、无循环、无直接硬件访问,适合 F103/F407
CatST-Safe 安全扩展语言 增加 VAR_TEMP、索引访问、更多安全纯函数、可静态计数的 FOR 等确定性能力
CatST-Comm 通信映像扩展 支持 EtherCAT/CANopen/Ethernet 过程映像变量,不在扫描中阻塞协议解析
CatST-Fast 快速扫描子集 限定为纯布尔/整数表达式、固定功能块和极小资源预算,用于微秒级快任务

第一版实现应优先完成 CatST-Core,并为 CatST-Safe 的语法和诊断预留扩展点。

4.2 目标板 Profile

Profile 目标 说明
F103_LITE 低成本版 更严格的代码大小、变量数量、诊断深度和下载分区限制
F407_STANDARD 标准版 第一版主开发平台,完整支持当前变量区和在线监控
EXT_COMM 扩展通信版 在 F407 或更高资源平台上启用 EtherCAT/CANopen/Ethernet 过程映像

不同 Profile 不应改变 CatST 的核心语义。差异只体现在资源上限、可用扩展库、通信映像范围和编译预算。


5. 源文件形式

CatST 源文件推荐扩展名:

.catst

编码:

UTF-8

大小写规则:

  1. 关键字大小写不敏感,IFifIf 等价。
  2. 内置变量区名大小写不敏感,X0x0 等价。
  3. 用户别名建议使用大小写敏感显示,但编译器应禁止仅大小写不同的重复命名,避免现场误读。

注释:

// 单行注释

(* 多行注释
   可跨行
*)

语句使用分号结尾:

Y0 := X0;

5.1 简写程序形式

现场默认推荐使用无包装的简写形式:

IF X0 AND NOT X1 THEN
    Y0 := TRUE;
ELSE
    Y0 := FALSE;
END_IF;

简写形式等价于单一 PLC_PRG 程序体。

5.2 标准程序包装形式

为了接近 ST,也允许可选包装:

PROGRAM PLC_PRG
VAR_ALIAS
    StartButton AT X0 : BOOL;
    StopButton  AT X1 : BOOL;
    MotorRun    AT Y0 : BOOL;
END_VAR

IF StartButton AND NOT StopButton THEN
    MotorRun := TRUE;
ELSE
    MotorRun := FALSE;
END_IF;
END_PROGRAM

第一版只允许一个 PROGRAM。不支持多 POU、多任务、自定义函数和自定义功能块。


6. 变量区与符号

变量区范围以 MemoryMap.md 为最终规范。CatST 可访问的基础变量区:

区域 范围 权限 类型 说明
X X0~X15 只读 BOOL 数字输入映像
Y Y0~Y7 可写 BOOL 晶体管输出映像
R R0~R3 可写 BOOL 继电器输出映像
M M0~M127 可读写 BOOL 内部辅助位
D D0~D127 可读写 DINT 数据寄存器
T T0~T31 功能块访问 Timer 定时器
C C0~C31 功能块访问 Counter 计数器
S S0~S63 只读 BOOL/WORD 系统状态
E E0~E63 只读 BOOL/WORD 故障码

6.1 直接变量访问

Y0 := X0;
M0 := X0 AND NOT X1;
D0 := D1 + 10;

直接变量必须满足:

  1. 区域存在。
  2. 索引在范围内。
  3. 写入权限允许。
  4. 表达式类型与目标变量兼容。

禁止示例:

X0 := TRUE;      // 禁止,X 是只读输入
S0 := TRUE;      // 禁止,S 是只读系统状态
T0.Q := TRUE;    // 禁止,定时器状态只读
C0.CV := 0;      // 禁止,计数器当前值不可直接写
Y12 := TRUE;     // 禁止,越界

6.2 变量别名

为了降低现场维护成本,CatST 支持 VAR_ALIAS 为固定变量区创建业务名称。

VAR_ALIAS
    StartButton AT X0 : BOOL;
    StopButton  AT X1 : BOOL;
    MotorRun    AT Y0 : BOOL;
    AlarmRelay  AT R0 : BOOL;
    TargetCount AT D0 : DINT;
END_VAR

别名规则:

  1. 别名不分配新内存,只映射到既有变量区。
  2. 别名继承原变量权限。
  3. 别名类型必须与映射对象兼容。
  4. 一个别名只能映射一个对象。
  5. 多个别名可以映射同一对象,但编译器应给出 Warning,避免现场误解。
  6. 别名不得与关键字、内置函数、变量区名冲突。

6.3 临时变量

CatST-Safe 可支持 VAR_TEMP,用于单次扫描内的中间计算。

VAR_TEMP
    InterlockOk : BOOL;
    NextValue   : DINT;
END_VAR

InterlockOk := X0 AND NOT X1;
NextValue := D0 + 1;

VAR_TEMP 规则:

  1. 编译为 UserLogic_Scan() 内的局部 C 变量。
  2. 每次扫描重新初始化,不能保持状态。
  3. 不能被在线监控直接读取。
  4. 不能使用 AT 映射。
  5. F103_LITE 下默认最多 16 个,F407_STANDARD 下默认最多 64 个。

需要保持状态的逻辑应使用 M/D/T/C 等固定变量区。


7. 数据类型

7.1 核心类型

CatST 类型 含义 C 映射 说明
BOOL 布尔量 bool 仅允许 TRUE / FALSE
INT 16 位有符号整数 int16_t 主要用于临时变量或参数
DINT 32 位有符号整数 int32_t D 区默认类型
TIME 时间常量 uint32_t 毫秒 用于定时器预置值

第一版 D 区按 DINT 处理。如果通过 Modbus 16 位寄存器访问,一个 D 占两个连续 Holding Register,映射以 MemoryMap.md 为准。

7.2 扩展类型

CatST-Comm 可增加以下类型,用于通信状态字和协议映像:

类型 C 映射 用途
UINT uint16_t CANopen 状态字、寄存器值
UDINT uint32_t 计数、时间戳、以太网状态
WORD uint16_t 位域状态
DWORD uint32_t 位域状态

扩展类型只有在目标 Runtime 和 MemoryMap 扩展文档声明支持时才能使用。

7.3 TIME 常量

支持格式:

T#1ms
T#100ms
T#1s
T#2m
T#1h

转换规则:

写法 毫秒
T#1ms 1
T#1s 1000
T#2m 120000
T#1h 3600000

第一版 TIME 内部统一转换为毫秒。超出 uint32_t 毫秒范围必须编译报错。

7.4 类型转换

默认不允许 BOOL 与整数隐式混用:

D0 := X0;        // 禁止
Y0 := D0;        // 禁止

允许显式转换函数:

D0 := BOOL_TO_DINT(X0);
Y0 := DINT_TO_BOOL(D0);

转换规则:

  1. BOOL_TO_DINT(FALSE) 为 0,BOOL_TO_DINT(TRUE) 为 1。
  2. DINT_TO_BOOL(0) 为 FALSE,非 0 为 TRUE。
  3. DINT_TO_INT() 超出 INT 范围时按饱和规则处理,并产生 Warning 或运行诊断。

8. 表达式与运算符

8.1 字面量

TRUE
FALSE
0
123
-10
T#100ms

第一版不支持字符串字面量、浮点字面量和数组字面量。

8.2 运算符优先级

从高到低:

优先级 运算符 说明
1 ( ) 括号
2 NOT、一元 - 逻辑非、负号
3 */MOD 乘、除、取模
4 +- 加、减
5 =<>>>=<<= 比较
6 AND 逻辑与
7 XOR 逻辑异或
8 OR 逻辑或

示例:

M0 := (X0 AND X1) OR NOT X2;
M1 := D0 > 10 AND D1 <= 100;
D2 := D0 + D1 * 2;

8.3 整数运算安全规则

生成 C 代码时不得引入 C 语言未定义行为。整数运算必须遵守:

  1. 常量表达式在编译期求值。
  2. 常量溢出必须报错。
  3. 运行期 DINT/INT 运算使用受控 helper 或更宽中间类型实现。
  4. 赋值到较小整数类型时按目标类型范围饱和,编译器给出 Warning。
  5. 常量除以 0 必须报错。
  6. 运行期除以 0 不得导致 MCU 异常,生成代码必须调用受控除法 helper,并设置运行诊断或返回 0。

示例:

D0 := D1 / D2;

生成 C 不应直接生成可能异常或未定义的裸表达式,而应生成类似:

PLC_D[0] = PLC_DINT_Div(PLC_D[1], PLC_D[2]);

9. 语句

9.1 赋值

Y0 := TRUE;
M0 := X0;
D0 := D1 + 10;

规则:

  1. 左侧必须是可写变量、可写别名或 VAR_TEMP
  2. 左侧不能是表达式。
  3. = 只用于比较,不能用于赋值。

9.2 IF 语句

IF X0 AND NOT X1 THEN
    Y0 := TRUE;
ELSIF X2 THEN
    Y0 := FALSE;
ELSE
    Y0 := M0;
END_IF;

规则:

  1. 条件表达式必须是 BOOL。
  2. ELSIF 可出现多次。
  3. ELSE 可省略。
  4. 必须以 END_IF; 结束。

9.3 CASE 语句

CatST-Core 支持 CASE,用于状态机和模式选择。

CASE D0 OF
    0:
        Y0 := FALSE;
        Y1 := FALSE;
    1:
        Y0 := TRUE;
        Y1 := FALSE;
    2, 3:
        Y0 := TRUE;
        Y1 := TRUE;
ELSE
    Y0 := FALSE;
    Y1 := FALSE;
END_CASE;

规则:

  1. CASE 表达式必须是整数或枚举式常量别名。
  2. 分支标签必须是常量。
  3. 分支标签不得重复。
  4. ELSE 建议保留,用于异常状态回退。
  5. 生成 C 可使用 switch 或等价 if 链。

9.4 FOR 语句

CatST-Core 默认不启用循环。CatST-Safe 可启用受限 FOR

FOR i := 0 TO 7 DO
    // 仅允许访问可静态验证的表达式
END_FOR;

受限 FOR 属于第二阶段 Safe 能力,必须满足:

  1. 起始值、结束值、步长必须是编译期常量。
  2. 最大迭代次数必须可静态计算。
  3. 默认单个 FOR 最大 64 次迭代。
  4. 默认整个程序所有 FOR 展开后最大 256 次迭代。
  5. 循环变量必须是 VAR_TEMP 整数变量。
  6. 不支持 EXITCONTINUE
  7. 不能在循环中调用可能改变通信状态或阻塞的函数。
  8. 配合 X[i]Y[i]M[i]D[i] 等索引访问时,编译器必须静态证明索引不越界。

编译器可选择展开 FOR,也可生成有固定边界的 C for。两者都必须通过资源预算检查。

9.5 禁止语句

第一版禁止:

WHILE
REPEAT
EXIT
CONTINUE
RETURN
GOTO
动态数组
指针
自定义 FUNCTION
自定义 FUNCTION_BLOCK
多 PROGRAM
多 TASK

禁止原因不是 STM32 无法执行,而是这些能力会显著提高扫描周期分析、现场诊断和安全验证成本。


10. 内置函数与功能块

10.1 纯函数

纯函数不保存状态,不访问硬件,不阻塞。

函数 说明
BOOL_TO_DINT(x) BOOL 转 DINT
DINT_TO_BOOL(x) DINT 转 BOOL
INT_TO_DINT(x) INT 转 DINT
DINT_TO_INT(x) DINT 转 INT,按饱和规则
ABS(x) 绝对值
MIN(a, b) 较小值
MAX(a, b) 较大值
LIMIT(min, x, max) 限幅
SEL(g, a, b) g=FALSE 返回 a,否则返回 b

纯函数可出现在表达式中:

D0 := LIMIT(0, D1 + D2, 1000);
Y0 := DINT_TO_BOOL(D0);

10.2 定时器

支持:

TON:通电延时
TOF:断电延时
TP:脉冲定时

推荐使用命名参数:

TON(T0, IN := X0, PT := T#1000ms);

IF T0.Q THEN
    Y0 := TRUE;
END_IF;

兼容简写:

TON(T0, X0, T#1000ms);

可读字段:

字段 类型 说明
Tn.Q BOOL 定时器输出
Tn.ET DINT 已经过时间,毫秒

禁止直接写定时器字段:

T0.Q := TRUE;    // 禁止
T0.ET := 0;      // 禁止

同一个定时器实例每个扫描周期最多允许一次更新调用,多次读取允许。

10.3 计数器

支持:

CTU:上数计数器
CTD:下数计数器

示例:

CTU(C0, CU := X0, PV := 10, R := X1);

IF C0.Q THEN
    R0 := TRUE;
END_IF;

兼容简写:

CTU(C0, X0, 10, X1);
CTD(C1, X2, 0, X3);

可读字段:

字段 类型 说明
Cn.Q BOOL 到达预置状态
Cn.CV DINT 当前计数值

禁止直接写计数器字段。复位必须通过功能块参数完成。

10.4 边沿检测

支持:

M0 := R_TRIG(X0);
M1 := F_TRIG(X1);

规则:

  1. R_TRIG 返回上升沿单扫描脉冲。
  2. F_TRIG 返回下降沿单扫描脉冲。
  3. 编译器为每个调用点分配私有 Edge_t 状态。
  4. 边沿函数只能作为简单赋值右侧使用,不允许嵌套在复杂表达式中。
  5. 边沿调用点在程序结构变化后允许状态重新初始化,因为下载新 App 后用户逻辑状态本来需要重新确认。

推荐写法:

M10 := R_TRIG(X0);

IF M10 THEN
    D0 := D0 + 1;
END_IF;

11. CatST 到 C 的生成规则

生成文件由上位机创建:

UserLogic.c
UserLogic.h
UserConfig.h

固定入口:

void UserLogic_Init(void);
void UserLogic_Scan(void);

生成模板:

#include "plc_runtime.h"
#include "UserLogic.h"

void UserLogic_Init(void)
{
    /* Auto generated init code. */
}

void UserLogic_Scan(void)
{
    /* ===== Auto generated from CatST ===== */

    /* generated logic here */

    /* ===== End generated code ===== */
}

11.1 变量映射

示例 CatST:

Y0 := X0 AND NOT X1;
D0 := D1 + 10;

可生成类似 C:

PLC_Y[0] = PLC_X[0] && !PLC_X[1];
PLC_D[0] = PLC_DINT_Add(PLC_D[1], 10);

Runtime 可以选择受控数组或受控 API,但生成代码不得访问底层 GPIO:

PLC_SetY(0, PLC_GetX(0));

以下生成结果禁止:

HAL_GPIO_WritePin(...);
GPIOA->ODR = ...;
malloc(...);
while (...);

11.2 控制流映射

IF 映射为 C if

IF X0 THEN
    Y0 := TRUE;
ELSE
    Y0 := FALSE;
END_IF;
if (PLC_X[0])
{
    PLC_Y[0] = true;
}
else
{
    PLC_Y[0] = false;
}

CASE 映射为 C switch 或静态 if 链:

switch (PLC_D[0])
{
case 0:
    PLC_Y[0] = false;
    break;
case 1:
    PLC_Y[0] = true;
    break;
default:
    PLC_Y[0] = false;
    break;
}

11.3 生成器硬限制

生成器不得生成:

  1. 任意用户 include。
  2. 任意用户 C 片段。
  3. 动态内存。
  4. 递归。
  5. 无界循环。
  6. 文件操作。
  7. 阻塞通信调用。
  8. 直接硬件寄存器访问。
  9. 直接 HAL/LL 驱动调用。
  10. 可能导致 C 未定义行为的裸整数运算。

12. 扫描周期、资源预算与性能

CatST 必须在编译期生成资源报告:

语句数量
AST 节点数量
表达式最大深度
IF 嵌套深度
CASE 分支数量
定时器实例数量
计数器实例数量
边沿状态数量
VAR_TEMP 数量
受限 FOR 最大展开次数
估算生成 C 行数
估算 UserLogic 代码大小

默认建议阈值:

指标 F103_LITE F407_STANDARD
语句数量 512 2048
表达式最大深度 12 24
IF 嵌套深度 8 16
CASE 单语句分支 32 128
边沿状态数量 64 256
VAR_TEMP 数量 16 64
受限 FOR 总展开次数 128 1024

超过阈值时,编译器应给出明确错误或需要目标 Profile 显式放宽。

性能要求:

  1. 普通扫描周期目标仍以 Firmware.md 为准,默认 1ms~10ms 可配置。
  2. CatST 编译器应估算用户逻辑复杂度,避免现场程序把扫描周期拖到不可控。
  3. 对于需要微秒级响应的场景,应使用 CatST-Fast 子集或固件专用快任务。
  4. EtherCAT/CANopen/Ethernet 协议解析不应放入普通 CatST 扫描逻辑中。
  5. 通信栈可在中断、DMA、RTOS 任务或主循环通信阶段运行,并通过过程映像与 CatST 交互。

微秒级目标必须以实测为准。CatST 可以支持极小逻辑块达到 1 us 量级执行时间,但不能承诺任意现场程序都满足该目标。


13. 安全模型

CatST 安全模型分三层:

层级 执行位置 职责
编译期安全 PLC Studio 禁止危险语法、越界变量、只读写入、资源超限
Runtime 安全 STM32 App 运行模式、输入滤波、输出映像、定时器、计数器、诊断
输出安全层 STM32 App/硬件 STOP/ERROR/DOWNLOAD/急停/CRC 错误时关闭物理输出

即使 CatST 写入:

Y0 := TRUE;

固件安全层仍可在输出刷新前关闭物理输出。CatST 不能绕过安全层。

下载安全要求:

  1. 下载前必须 STOP。
  2. 下载前必须关闭输出。
  3. 下载中禁止输出动作。
  4. 下载完成后默认 STOP。
  5. RUN 必须由人工确认或受控命令确认。

14. 通信与扩展控制模型

后续 EtherCAT、CANopen、以太网扩展不建议做成 CatST 中的阻塞函数,例如:

// 禁止方向:扫描中等待网络响应
ReadSocket(...);
CanOpenUpload(...);

推荐模型是“通信任务 + 过程映像 + CatST 读写映像”:

通信中断/DMA/协议任务
协议解析和对象字典/PDO/报文状态
输入过程映像缓冲
 ↓ 扫描边界复制
CatST UserLogic_Scan 读取稳定映像
输出过程映像缓冲
 ↓ 扫描后刷新
通信任务发送 PDO/SDO/以太网报文

未来扩展可使用别名映射外部对象:

VAR_ALIAS
    DriveReady  AT CANOPEN.Node1.StatusWord.Bit0 : BOOL;
    DriveFault  AT CANOPEN.Node1.StatusWord.Bit3 : BOOL;
    TargetSpeed AT CANOPEN.Node1.TargetVelocity  : DINT;
END_VAR

该语法属于 CatST-Comm,必须满足:

  1. 对象映射由工程配置和通信配置生成,不由现场代码任意拼接地址。
  2. 读写访问的是 Runtime 过程映像,不是阻塞协议调用。
  3. 通信超时、掉线、状态字异常由 Runtime 设置 S/E 或扩展状态变量。
  4. CatST 写出的控制字必须经过安全层和通信层状态机过滤。
  5. 快速通信场景可绕过普通扫描周期做协议解析,但 CatST 只能在受控任务边界读写一致性快照。

这样可以同时保留 PLC ST 的现场可编辑优势和 STM32 在通信、协议解析、DMA、中断、快速任务上的性能优势。


15. 中断与快速事件模型

CatST 不开放用户 ISR。以下形式禁止:

INTERRUPT EXTI0 DO
    Y0 := TRUE;
END_INTERRUPT;

正确模型是:

硬件中断 / DMA / 定时器捕获
固定 Runtime ISR
事件锁存 / 高速计数 / 捕获值 / 通信过程映像
扫描边界复制为稳定快照
CatST UserLogic_Scan() 读取快照

CatST 可使用 Runtime 暴露的只读事件资源,例如:

IF HSC0.CV >= D0 THEN
    Y0 := TRUE;
END_IF;

IF L0 THEN
    M0 := TRUE;
END_IF;

详细规则见 InterruptModel.md


16. 诊断与错误码

诊断信息必须包含:

错误级别:Error / Warning / Info
错误编号
文件名
行号
列号
源码片段
错误说明
修复建议

建议错误码范围:

范围 类型
E1000~E1999 词法错误
E2000~E2999 语法错误
E3000~E3999 语义错误
E4000~E4999 安全规则错误
E5000~E5999 资源预算错误
W1000~W1999 可编译但建议修复的风险

示例:

Y0 = TRUE;
E2004 第 1 行第 4 列:赋值应使用 :=,不能使用 =
Y12 := TRUE;
E3002 第 1 行第 1 列:Y12 不存在,当前目标板仅支持 Y0~Y7
WHILE X0 DO
    Y0 := TRUE;
END_WHILE;
E4001 第 1 行第 1 列:CatST 不支持 WHILE,无界循环会导致扫描周期不可控

17. 仿真与一致性

同一段 CatST 程序必须能在三种路径中保持一致:

CatST AST 仿真
 ↓ 对比
生成 C 的 PC 版 Runtime 仿真
 ↓ 对比
STM32 实机运行

一致性范围:

  1. X 输入相同。
  2. 扫描次数相同。
  3. 模拟时间步进相同。
  4. Y/R/M/D/T/C 输出和状态相同。
  5. 定时器、计数器、边沿检测语义相同。
  6. 错误和诊断规则一致。

仿真器应支持:

设置 X 输入
设置 M/D 初值
单步扫描
连续扫描
设置模拟扫描周期
查看 Y/R/M/D/T/C/S/E
导出扫描轨迹
对比生成 C 仿真结果

18. 示例

17.1 启停联锁

VAR_ALIAS
    StartButton AT X0 : BOOL;
    StopButton  AT X1 : BOOL;
    MotorRun    AT Y0 : BOOL;
END_VAR

IF StartButton AND NOT StopButton THEN
    MotorRun := TRUE;
ELSE
    MotorRun := FALSE;
END_IF;

17.2 延时启动

TON(T0, IN := X0, PT := T#1000ms);

IF T0.Q THEN
    Y0 := TRUE;
ELSE
    Y0 := FALSE;
END_IF;

17.3 计数到达

CTU(C0, CU := X0, PV := 10, R := X1);

IF C0.Q THEN
    R0 := TRUE;
ELSE
    R0 := FALSE;
END_IF;

17.4 简单状态机

CASE D0 OF
    0:
        Y0 := FALSE;
        IF X0 THEN
            D0 := 1;
        END_IF;

    1:
        Y0 := TRUE;
        IF X1 THEN
            D0 := 2;
        END_IF;

    2:
        Y0 := FALSE;
        R0 := TRUE;
ELSE
    D0 := 0;
    Y0 := FALSE;
    R0 := FALSE;
END_CASE;

17.5 安全限幅

D2 := LIMIT(0, D0 + D1, 1000);

IF D2 >= 800 THEN
    Y0 := TRUE;
ELSE
    Y0 := FALSE;
END_IF;

19. 第一版实现范围

第一版建议支持:

PROGRAM / END_PROGRAM 可选包装
VAR_ALIAS
IF / THEN / ELSIF / ELSE / END_IF
CASE / OF / ELSE / END_CASE
:= 赋值
AND / OR / XOR / NOT
= <> > < >= <= 比较
+ - * / MOD 整数运算
BOOL / INT / DINT / TIME
TON / TOF / TP
CTU / CTD
R_TRIG / F_TRIG
ABS / MIN / MAX / LIMIT / SEL
BOOL_TO_DINT / DINT_TO_BOOL / INT_TO_DINT / DINT_TO_INT
语法检查
语义检查
安全检查
资源预算检查
AST 仿真
UserLogic.c 生成
生成 C 快照测试

第一版默认不启用:

WHILE
REPEAT
RETURN
EXIT
CONTINUE
数组
结构体
指针
字符串
浮点
自定义函数
自定义功能块
多任务
多 POU
递归
动态内存
现场任意 C 代码片段
扫描内阻塞通信
直接硬件访问
用户中断函数

第二阶段 Safe 建议实现:

VAR_TEMP
受限 FOR
索引访问 X[i] / Y[i] / M[i] / D[i]
UINT / UDINT / WORD / DWORD
通信过程映像别名
更丰富的纯函数库
CatST-Fast 快任务子集
L/HSC/CAP 事件映像

20. 测试要求

CatST 编译器必须建立测试用例:

  1. 合法赋值。
  2. 合法 IF/ELSIF/ELSE。
  3. 嵌套 IF。
  4. CASE 状态机。
  5. 逻辑表达式优先级。
  6. 比较运算。
  7. 整数运算和溢出保护。
  8. 除以 0 保护。
  9. TIME 常量转换。
  10. TON/TOF/TP。
  11. CTU/CTD。
  12. R_TRIG/F_TRIG。
  13. VAR_ALIAS 权限继承。
  14. 只读变量写入错误。
  15. 越界变量错误。
  16. 禁止 WHILE/FOR 默认错误。
  17. 函数参数数量错误。
  18. 函数参数类型错误。
  19. 同一 T/C 实例多次更新错误。
  20. 生成 C 快照测试。
  21. AST 仿真与生成 C 仿真一致性测试。
  22. 生成 C 仿真与 STM32 实机运行一致性测试。
  23. F103_LITE 资源预算超限错误。
  24. F407_STANDARD 资源预算边界测试。
  25. 用户中断语法禁止测试。
  26. L/HSC/CAP 事件映像仿真与 Runtime 一致性测试。

测试总要求以 TestPlan.md 为准。


21. 与其他文档的一致性要求

  1. CatST 变量范围必须与 MemoryMap.md 一致。
  2. 生成的 C 必须符合 Firmware.md 中的 Runtime API 和安全策略。
  3. 上位机编辑、补全、诊断、仿真、编译和下载必须符合 Software.md
  4. 维护协议、在线变量、下载流程必须符合 Protocol.md
  5. CatST 测试必须纳入 TestPlan.md
  6. 中断、DMA、捕获和快任务边界必须符合 InterruptModel.md
  7. 若后续扩展 EtherCAT、CANopen 或以太网,应新增通信映像规范,并保持 CatST 不阻塞扫描周期的原则。