DesignSpark Electrical Logolinkedin
菜单 搜寻
提问问题

通过结构式文本 (ST) 和 RevPi Core 3 控制交通灯

一个简单的结构式文本 (PLC) 程序,可在 RevPi Core 3 上运行以控制交通灯。

将 RevPi Core 3 和 DIO 安装在 DIN 导轨上并成功运行后(详见上一个帖子,我准备用它们来做一些有意义的事情。作为“概念验证”,我想试着模拟一个简单的交通灯装置。

结构式文本 (ST)

创建 PLC 控制程序的主要标准语言分为 3 种 - 结构式文本语言 Structured Text Language (ST)、梯形逻辑和功能块图 (FBD)。顾名思义,后两者是更为图形化的界面,然而它们的灵活性不如结构式文本语言,加上 RevPi 随附的免费版 logi.CAD 3 仅支持结构式文本语言,因此我选择使用它。

尽管结构式文本是一种行业标准 IEC 61131-3 管理范围内的标准化语言,且语言核心保持不变,但是每个 PLC 供应商都做出特定的修改和增加。我在网上找到了一篇实用的入门教程,在它的指导下我开始着手搭建。对于熟悉计算机语言的人来说,结构式文本由 PASCAL 发展而来,它让我想起许多年前,我在 ZX80 上用来进行乒乓球游戏编程的 BASIC 语言。

logi.CAD 3

除了使用新的语言以外,我还使用了以前从未用过的软件。我发现,通过浏览  logi.CAD 3 术语表了解一些使用的术语,然后在必要时再次查阅,对我的工作有很大的帮助。我特别记录了以下几点:

  • 对象 - logi.CAD 3 项目资源管理器中的对象位于文件夹内,是该文件夹的子文件夹。对象相当于文件系统中的文件。
  • 项目 - 项目是 logi.CAD 3 项目资源管理器中的一种特殊类型的文件夹。默认情况下,项目是项目资源管理器中的根目录。


完整的内容总称为应用程序,它不仅有包含已编写代码的 STL 文件,还包括配置文件、全局变量和专用于 PLC 的库。

这时,我发现了一个有效的办法,那就是通过单击“Project Menu(项目菜单)”下的“Clean(清理)”选项来“清理”项目,然后等待 Logi.CAD 3 运行完毕,之后应用程序创建并加载成功。

闪烁的灯光

我已经创建了一个简单的应用程序,可用于控制一盏灯闪烁。这基于我在上一篇博客中使用的 RevPi 快速入门指南 示例。

PROGRAM RevolutionPiCounterProgram
	VAR
		value 	: BOOL;  
	END_VAR
		
	VAR_EXTERNAL	
		Red_1 : BOOL;
		Amber_2 : BOOL;
		Green_3 : BOOL;
	END_VAR
		
	IF value THEN
		Red_1 := False;
		value := False;
	ELSE
		Red_1 := True; 
		value := True;
	END_IF;
	
END_PROGRAM

本例中,LED 持续闪烁。这是因为 PLC 应用程序会自动重复。“End_Program”实际上表示返回到起始行然后重新开始。

教程中解释如下“当 PLC 运行到 END_PROGRAM 时,PLC 扫描周期将重新开始,程序将重新运行”:

交通信号灯

现在,我需要研究出如何使 LED 以标准交通灯亮顺序闪烁 - 红、红和黄、绿、黄,然后再回到红。

更改信号灯的闪烁速度时,只需在配置文件中编辑一个数值即可,但是这会改变整个扫描循环的速度,因此这种方法较为粗糙,只会使应用程序整体减慢。此外,我还想要能单独改变不同灯的闪烁速度。事实证明,这比最初预期的难度更大。

TON 函数(计时器延迟)提供了所需的延迟,但我无法通过代码获得所需的效果。我能够使 LED 亮起一定时间后熄灭,但是却无法再次亮起,或者能够使 LED 闪烁并熄灭,但是却无法指定熄灭时间。我反复碰壁,一度觉得这项任务可能超出了我的处理能力。就在这时,我在网络上寻求帮助,在 Codesys 论坛上找到了一篇实用的博客文章,其中提到了 CASE 语句。Codesys 的功能与 logi.CAD 类似,而我发现它们所用的结构化文本语法存在一些差异,但是我成功地根据我的需要对示例进行了调整。

我曾经在网络教程中学习过 CASE 语句,但是直到我看到这个示例时,才突然认识到如何能够将它用于实际应用中。

最终代码如下:

PROGRAM RevolutionPiProgram

	VAR  
	wait : TON; 
	count : INT;
	END_VAR
		
	VAR_EXTERNAL	
		Red_1 : BOOL;
		Amber_2 : BOOL;
		Green_3 : BOOL;
	END_VAR
		
CASE count OF
	0: //init
		count := count + 1;

	1: // Red
   
		Red_1 := True;
		Amber_2 := False;
     	Green_3 := False;
     
		wait(IN:=TRUE, PT:=T#5s);
		
		IF wait.Q THEN
			wait(IN:=FALSE);
			count := count + 1;
		END_IF;

  	 2: // Red and Amber
   		
   		Red_1 := True;
    	Amber_2 := True;
    	Green_3 := False;
     
     	wait(IN:=TRUE, PT:=T#5s);
	
		IF wait.Q THEN
			wait(IN:=FALSE);
			count := count + 1;
		END_IF;

   	3:  // Green

		Red_1 := False;
		Amber_2 := False;
		Green_3 := True;
     
     	wait(IN:=TRUE, PT:=T#5s);
     		
     	IF wait.Q THEN
     		wait(IN:=FALSE);
     		count := count + 1;
     	END_IF;
      
  	 4: // Amber
   
   		Red_1 	:= False;
   		Amber_2 := True;
   		Green_3 := False;
   		
   		wait(IN:=TRUE, PT:=T#5s);
   		
   		IF wait.Q THEN
   			wait(IN:=FALSE);
   			count := count + 1;
   		END_IF;
   		
		ELSE
		count := 0;

END_CASE;

END_PROGRAM


CASE 用于在出现特定整数值时执行语句。本例中创建了一个名为“count”的整数变量,此变量在每次 PLC 扫描时增加 1,直到最终条件运行以及 ELSE 将它重新设置为零。而 TON 将每个语句运行 5 秒。更改该数值时,只需编辑以下行中的 5s 值即可:

wait(IN:=TRUE, PT:=T#5s);

如有需要,可以为每次灯亮指定不同的时间(在以下视频中,我将它们全部更改为了 2 秒)。如需增加灯的数量,也可通过扩展代码轻松实现。

结论

在学习使用新的(就我而言)计算机语言和不熟悉的软件时,总会面临各种挑战,但是我对最终得到的优秀解决方案感到非常满意。虽然我最终搭建出的交通灯可能不完全“适合道路应用”,但是可以看到,只需适当的调整,它们可在农业展览等类似的一次性活动中用于简单的交通控制。

I currently look after production at AB Open. I have a background in the arts, environmental conservation and IT support. In my spare time I do a bit of DJing and I like making things.

3 Sep 2019, 6:55