话不多说,准备好提问的问题,我们直接看结果;这次准备对比文心一言,星火大模型,通义前问这三个国产模式。以下是提问主题:
问题一:你会PLC的ST编程吗?
问题二:路口有三盏灯,分别是红灯,绿灯,黄灯,请用ST语言写一段这样的逻辑程序,红灯亮10秒,黄灯亮2秒,然后绿灯亮8秒,依次循环。
首先看通义千问的结果:
代码如下:
VAR
2 timer_red : TON; // 定时器用于红灯
3 timer_yellow : TON; // 定时器用于黄灯
4 timer_green : TON; // 定时器用于绿灯
5 state : INT; // 当前状态变量:1 - 红灯,2 - 黄灯,3 - 绿灯
6 cycle_start : BOOL; // 循环开始标志
7
8PROGRAM MAIN
9BEGIN
10 (* 初始化 *)
11 state := 1; // 初始状态为红灯
12 timer_red.IN := TRUE; // 启动红灯定时器
13 timer_yellow.IN := FALSE;
14 timer_green.IN := FALSE;
15 cycle_start := TRUE;
16
17 (* 主循环 *)
18 WHILE TRUE DO
19 CASE state OF
20 1: // 红灯阶段
21 IF timer_red.Q THEN // 红灯定时时间到
22 timer_red.IN := FALSE; // 停止红灯定时器
23 timer_yellow.IN := TRUE; // 启动黄灯定时器
24 state := 2;
25 END_IF;
26
27 2: // 黄灯阶段
28 IF timer_yellow.Q THEN // 黄灯定时时间到
29 timer_yellow.IN := FALSE; // 停止黄灯定时器
30 timer_green.IN := TRUE; // 启动绿灯定时器
31 state := 3;
32 END_IF;
33
34 3: // 绿灯阶段
35 IF timer_green.Q THEN // 绿灯定时时间到
36 timer_green.IN := FALSE; // 停止绿灯定时器
37 cycle_start := TRUE; // 准备重新开始下一个周期
38 state := 1; // 回到红灯阶段
39 END_IF;
40 END_CASE;
41
42 (* 当一个完整周期结束时重新启动计时器 *)
43 IF (timer_red.Q AND timer_yellow.Q AND timer_green.Q) AND cycle_start THEN
44 timer_red.IN := TRUE;
45 timer_yellow.PT := T#10S; // 设置红灯持续时间
46 timer_yellow.IN := FALSE;
47 timer_green.PT := T#2S; // 设置黄灯持续时间
48 timer_green.IN := FALSE;
49 cycle_start := FALSE;
50 END_IF;
51 END_WHILE;
52END_PROGRAM
从上述代码来看,不需要死循环且TON没有实例化;
第2次对通义提问:
代码如下:
VAR
2 timer_red : TON; // 定时器用于红灯
3 timer_yellow : TON; // 定时器用于黄灯
4 timer_green : TON; // 定时器用于绿灯
5 state : INT; // 当前状态变量:1 - 红灯,2 - 黄灯,3 - 绿灯
6
7PROGRAM MAIN
8BEGIN
9 (* 初始化 *)
10 state := 1;
11
12 (* 状态机循环 *)
13 WHILE TRUE DO
14 CASE state OF
15 1: // 红灯阶段
16 timer_red.PT := T#10S; // 设置红灯时间为10秒
17 timer_red.IN := TRUE;
18 IF timer_red.Q THEN // 红灯定时时间到
19 timer_red.IN := FALSE;
20 state := 2;
21 END_IF;
22
23 2: // 黄灯阶段
24 timer_yellow.PT := T#2S; // 设置黄灯时间为2秒
25 timer_yellow.IN := TRUE;
26 IF timer_yellow.Q THEN // 黄灯定时时间到
27 timer_yellow.IN := FALSE;
28 state := 3;
29 END_IF;
30
31 3: // 绿灯阶段
32 timer_green.PT := T#8S; // 设置绿灯时间为8秒
33 timer_green.IN := TRUE;
34 IF timer_green.Q THEN // 绿灯定时时间到
35 timer_green.IN := FALSE;
36 state := 1; // 回到红灯阶段
37 END_IF;
38 END_CASE;
39 END_WHILE;
40END_PROGRAM
从上述代码来看,不需要死循环且TON没有实例化,几乎没有什么变化。
第3次提问:
代码如下:
VAR
2 timer_red : TON; // 定时器用于红灯
3 timer_yellow : TON; // 定时器用于黄灯
4 timer_green : TON; // 定时器用于绿灯
5 state : INT; // 当前状态变量:1 - 红灯,2 - 黄灯,3 - 绿灯
6
7(* 初始化部分 *)
8initialization
9BEGIN
10 state := 1;
11 timer_red.PT := T#10S; // 设置红灯初始时间为10秒
12 timer_yellow.PT := T#2S; // 设置黄灯初始时间为2秒
13 timer_green.PT := T#8S; // 设置绿灯初始时间为8秒
14END_INITIALIZATION;
15
16(* 主程序部分 *)
17program main
18BEGIN
19 (* 在每次扫描时检查当前状态并更新定时器设置 *)
20 CASE state OF
21 1: // 红灯阶段
22 timer_red.IN := TRUE;
23 IF timer_red.Q THEN // 红灯定时时间到
24 timer_red.IN := FALSE;
25 state := 2;
26 timer_yellow.IN := TRUE;
27 END_IF;
28
29 2: // 黄灯阶段
30 IF timer_yellow.Q THEN // 黄灯定时时间到
31 timer_yellow.IN := FALSE;
32 state := 3;
33 timer_green.IN := TRUE;
34 END_IF;
35
36 3: // 绿灯阶段
37 IF timer_green.Q THEN // 绿灯定时时间到
38 timer_green.IN := FALSE;
39 state := 1; // 回到红灯阶段
40 timer_red.IN := TRUE;
41 END_IF;
42 END_CASE;
43END_PROGRAM
第三次提示后,还是和之前差不多,也许判断的语法相差比较大,逻辑基本上还是看的下去,只是不能直接运行,肯定也不符合IEC61131的规范;
通义千问实测失败。进行下一项。
接下来我们看星火大模型的表现:
首次提问:
代码如下:
PROGRAM TrafficLightControl
VAR
RedLight: BOOL; // 红灯
YellowLight: BOOL; // 黄灯
GreenLight: BOOL; // 绿灯
Timer: TON; // 定时器
END_VAR
METHOD ControlTrafficLights
CASE Timer.Q OF
0: // 红灯亮10秒
RedLight := TRUE;
YellowLight := FALSE;
GreenLight := FALSE;
Timer(IN:= NOT Timer.Q, PT:= T#10S);
1: // 黄灯亮2秒
RedLight := FALSE;
YellowLight := TRUE;
GreenLight := FALSE;
Timer(IN:= NOT Timer.Q, PT:= T#2S);
2: // 绿灯亮8秒
RedLight := FALSE;
YellowLight := FALSE;
GreenLight := TRUE;
Timer(IN:= NOT Timer.Q, PT:= T#8S);
END_CASE;
END_METHOD
代码分析来看,这个存在TON使用同一个实例的问题,而且也没有看到状态切换;我们需要再次提示;
第二次提问:
第二次的代码如下:
PROGRAM TrafficLightControl
VAR
RedLight: BOOL; // 红灯
YellowLight: BOOL; // 黄灯
GreenLight: BOOL; // 绿灯
Timer: TON; // 定时器
END_VAR
METHOD ControlTrafficLights
CASE Timer.Q OF
0: // 红灯亮10秒
RedLight := TRUE;
YellowLight := FALSE;
GreenLight := FALSE;
Timer(IN:= NOT Timer.Q, PT:= T#10S);
1: // 黄灯亮2秒
RedLight := FALSE;
YellowLight := TRUE;
GreenLight := FALSE;
Timer(IN:= NOT Timer.Q, PT:= T#2S);
2: // 绿灯亮8秒
RedLight := FALSE;
YellowLight := FALSE;
GreenLight := TRUE;
Timer(IN:= NOT Timer.Q, PT:= T#8S);
END_CASE;
END_METHOD
如上所示,代码和上次一模一样,没有任何改善;测试失败,进入一个模型的测试。
接下来看下文心一言的表现,进行第一次提问:
代码如下:
PROGRAM TrafficLightControl
VAR
RedLightTimer : TON; // 红灯计时器
YellowLightTimer : TON; // 黄灯计时器
GreenLightTimer : TON; // 绿灯计时器
LightState : INT; // 灯的状态(0=红灯,1=黄灯,2=绿灯)
END_VAR
// 初始化部分
BEGIN
// 初始化计时器和灯的状态
RedLightTimer(IN:=FALSE, PT:=T#10s); // 红灯计时器设置为10秒
YellowLightTimer(IN:=FALSE, PT:=T#2s); // 黄灯计时器设置为2秒
GreenLightTimer(IN:=FALSE, PT:=T#8s); // 绿灯计时器设置为8秒
LightState := 0; // 初始状态为红灯
END_BEGIN
// 主逻辑部分
WHILE TRUE DO
CASE LightState OF
0: // 红灯状态
// 红灯亮
IF RedLightTimer.Q THEN
// 红灯计时完成,切换到黄灯
RedLightTimer(IN:=FALSE); // 重置红灯计时器
YellowLightTimer(IN:=TRUE); // 启动黄灯计时器
LightState := 1; // 切换到黄灯状态
END_IF;
1: // 黄灯状态
// 黄灯亮
IF YellowLightTimer.Q THEN
// 黄灯计时完成,切换到绿灯
YellowLightTimer(IN:=FALSE); // 重置黄灯计时器
GreenLightTimer(IN:=TRUE); // 启动绿灯计时器
LightState := 2; // 切换到绿灯状态
END_IF;
2: // 绿灯状态
// 绿灯亮
IF GreenLightTimer.Q THEN
// 绿灯计时完成,切换到红灯
GreenLightTimer(IN:=FALSE); // 重置绿灯计时器
RedLightTimer(IN:=TRUE); // 启动红灯计时器
LightState := 0; // 切换到红灯状态
END_IF;
END_CASE;
// 这里可以添加控制灯的输出逻辑
// 例如:
// IF LightState = 0 THEN
// // 控制红灯输出为ON
// ELSEIF LightState = 1 THEN
// // 控制黄灯输出为ON
// ELSEIF LightState = 2 THEN
// // 控制绿灯输出为ON
// END_IF;
// 延时或者等待以确保逻辑循环不会过快执行
// 这通常是通过PLC的扫描周期或者特定的延时指令来实现
// 在这里我们假设PLC的扫描周期足够慢以支持这个逻辑
END_WHILE;
点评代码:仍然是无法执行的,状态切走后,TON的实例没有扫描,会导致无法继续执行。
第2次提问:
代码如下:
PROGRAM TrafficLightControl
VAR
// 定时器
RedLightTimer : TON; // 红灯定时器
YellowLightTimer: TON; // 黄灯定时器
GreenLightTimer : TON; // 绿灯定时器
// 灯光状态
LightState : INT; // 1=红灯,2=黄灯,3=绿灯
// 灯光输出(假设连接到PLC的物理输出)
RedLightOutput : BOOL; // 红灯输出
YellowLightOutput: BOOL; // 黄灯输出
GreenLightOutput: BOOL; // 绿灯输出
// 定时器是否在运行标志
RedTimerRunning : BOOL;
YellowTimerRunning: BOOL;
GreenTimerRunning : BOOL;
END_VAR
// 初始化
IF NOT RedTimerRunning THEN
// 只在红灯定时器未运行时设置
LightState := 1; // 初始状态为红灯
RedLightTimer(IN:=TRUE, PT:=T#10s); // 红灯定时器设为10秒
RedTimerRunning := TRUE; // 标记红灯定时器正在运行
YellowLightTimer(IN:=FALSE); // 黄灯定时器关闭
GreenLightTimer(IN:=FALSE); // 绿灯定时器关闭
// 设置输出
RedLightOutput := TRUE;
YellowLightOutput := FALSE;
GreenLightOutput := FALSE;
END_IF
// 红灯逻辑
IF LightState = 1 AND RedLightTimer.Q THEN
// 红灯时间到,切换到黄灯
LightState := 2;
RedLightTimer(IN:=FALSE); // 停止红灯定时器
RedTimerRunning := FALSE; // 标记红灯定时器已停止
YellowLightTimer(IN:=TRUE, PT:=T#2s); // 启动黄灯定时器
YellowTimerRunning := TRUE; // 标记黄灯定时器正在运行
RedLightOutput := FALSE; // 红灯灭
END_IF
// 黄灯逻辑
IF LightState = 2 AND YellowLightTimer.Q THEN
// 黄灯时间到,切换到绿灯
LightState := 3;
YellowLightTimer(IN:=FALSE); // 停止黄灯定时器
YellowTimerRunning := FALSE; // 标记黄灯定时器已停止
GreenLightTimer(IN:=TRUE, PT:=T#8s); // 启动绿灯定时器
GreenTimerRunning := TRUE; // 标记绿灯定时器正在运行
YellowLightOutput := FALSE; // 黄灯灭
END_IF
// 绿灯逻辑
IF LightState = 3 AND GreenLightTimer.Q THEN
// 绿灯时间到,切换到红灯
LightState := 1;
GreenLightTimer(IN:=FALSE); // 停止绿灯定时器
GreenTimerRunning := FALSE; // 标记绿灯定时器已停止
RedLightTimer(IN:=TRUE, PT:=T#10s); // 启动红灯定时器
RedTimerRunning := TRUE; // 标记红灯定时器正在运行
GreenLightOutput := FALSE; // 绿灯灭
END_IF
// 设置当前灯光输出
RedLightOutput := (LightState = 1);
YellowLightOutput := (LightState = 2);
GreenLightOutput := (LightState = 3);
// 注意:在实际应用中,您可能还需要考虑其他事件和条件,如交通流量、行人按钮等。
// 此外,如果PLC复位或重启,您可能需要一种机制来重新初始化LightState和定时器状态。
END_PROGRAM
检测结果还是一样,TON的用法有问题;仿真如下:
从上述论述可以看出,国产大模型在逻辑编程的推理方面,目前还不近人意,提示词的理解很多时候理解不了。目前看PLC工程师短期内还是可以继续发展的;后续PLC工程师可以利用AI工具加快代码的编辑。毕竟AI工具生成的注释和变量名还是比较规范的。生成后自行修改一部分逻辑可以得到自己想要的答案。
大家有兴趣研发AI生成代码技术的,欢迎加群一起交流。 |