我想知道我是否可以用状态机/图对PLC进行编程。
在Sparx EA的帮助下,我们可以组成状态机。有没有可能将这个状态机转换成SCL(结构化控制语言,用于PLC编程)?或者,我们可以从Sparx EA中获取什么类型的数据,作为PLC编程的输入?
也许你有一个更好的想法来实现这个想法。
发布于 2017-01-19 17:53:40
好的。您需要一个代码生成器工具,它可以读取状态机图表,并生成等效的结构化文本。
代码的形状非常简单。您可以为每个位定义一个ST布尔值(如果您可以像在StateCharts中那样拥有活动的并行状态)或一个包含状态号的ST整数。
然后,每个州的ST代码为:
if (StateXXX) then
<action in this state>
if (somecondition)
StateXXX=false;
StateYYY=true;
endif
endif您需要为每个州生成此代码。
这就留下了一个问题,你使用什么工具来完成这一任务?可以说是任何可以读取UML图的工具,UML图通常可以作为XML文档从UML编辑器中导出;使用解析后的XML,您可以编写代码来爬过它并输出上面的代码片段。
如果您编写的片段是定义良好的模板,这可能会更容易。您可以使用即席模板(简单的文本字符串,其中包含必须填充某些内容的标记),也可以使用强制生成代码的结构和组合的工具,如Program Transformation System (PTS)。
PTS接受一种语言的语法,将解析该语言的实例,并允许您转换该语言,最后生成修改后的语言实例。一个有用的特例是将琐碎的程序转换为复杂的、真实的程序。此外,一个好的PTS将允许您编写正式代码模板方面的模式和转换规则,至少强制模板的语法有效。这确保了您使用的片段始终具有一定的最小意义。(相反,您可以在文本模板中编写任何您喜欢的垃圾代码)。当您编写大量这样的模式时,这对避免产生垃圾非常有帮助。
对于这个特定的示例(我公司的名为DMS的PTS,请参阅bio),您可以为上面的片段编写模式:
pattern StateInstance(statenumber: natural, action: statements, exit_condition: expression, exit_state: natural): statement =
" if (StateNumber=\statenumber) then
\action
if (\exit_condition) then
StateNumber=\exit_state
endif
endif
";DMS提供了API来实例化这个模式(以及其他模式,通常会编写很多),并组合它们的结果(使用实例化的模式作为实例化的其他模式的参数),以生成最终的程序。您还可以添加转换规则来优化生成的代码。(DMS是由语法定义驱动的;它已经知道XML语言,特别是对ST和40+有健壮的定义)。
发布于 2017-01-19 17:37:45
我从来没有真正编写过S7,但基本上知道你在找什么。EA没有用于SCL的生成器,看到它来自Sparx的机会很低。所以有两种可能性。
首先(但我不喜欢)是深入研究在代码生成过程中使用的Sparx宏语言的内部。如果你只需要对现有的模板做一些小的调整,那也没什么,但是写一个全新的模板(对我来说)一点也不好玩。
第二种方法是使用API生成代码。这相当简单(对我来说,因为我在大学里学的是编译器构造)。您要做的就是获取状态机,遍历它并生成相应的语言结构。这在很大程度上取决于你的技能,但我会在几天内创建一个粗略的原型。
Perl这里是一个示例脚本(我知道如果您一周左右不使用它,它就是一个,但是您可以破解它),它使用EA的API来解析状态机:
package Compiler;
use strict;
use Win32::OLE qw (in);
sub new {
my ($self, $rep) = @_;
$self = {};
$self->{nodes} = {};
$self->{rep} = $rep;
bless $self;
}
sub traverse {
my ($self, $node) = @_;
my $guid = $node->ElementGUID;
return if defined($self->{nodes}->{$guid});
my $nodeInfo = { 'name' => $node->Name, 'type'=> $node->Type, 'out' => ()};
$self->{nodes}->{$guid} = $nodeInfo;
for my $trans (in $node->Connectors) {
my $target = $self->{rep}->GetElementByID($trans->SupplierID);
next if $target->ElementGUID eq $guid;
my @targetInfo = ($trans->TransitionGuard, $target->ElementGUID);
push(@{$nodeInfo->{out}}, \@targetInfo);
$self->traverse($target);
}
}
1;下面是一个简单的主程序:
use strict;
no strict 'refs';
use compiler;
my $rep = $ENV{'REP'}; # get repository pointer "by magic"
my $node = $rep->GetElementByGUID('{574C5E0C-E032-44c6-A6B0-783D35B9958B}'); # fixed addressing of InitialNode
my $compiler = Compiler->new($rep);
$compiler->traverse($node); # read in all possible transitions/states
my %states = %{$compiler->{nodes}}; # this hash holds all states and their transitions
for my $key (keys %states) {
my $state = $states{$key}; # loop through all found states
print "$state->{type} $state->{name}\n"; # state name
for my $out (@{$state->{out}}) {
my ($guard, $guid) = @{$out};
my $target = $compiler->{nodes}->{$guid};
print "__$guard -> $target->{name}\n";
}
}现在假设你有一个状态机,像这样:

当你运行上面的程序时,它会打印出来
StateNode StateNode __no condition -> State1 (StateNode StateNode__no condition->State1)
状态State1
__condition -> State2
__exit ->状态State2
other condition -> State1 (其他条件)
第一个是未命名的出口,第二个是InitialNode (您也可以从StateNode获取该信息并使用它)。State1有两种可能的转换(到exit和State2)。而State2只会转换到State1。
现在,有了命名状态列表,您可以为不同的状态创建一些枚举。此外,您还为所有转换提供了保护,您可以将其转换为if-cascades或switch-语句。
当然,这不是一个完整的代码生成器,但您可以从这个脚手架中了解如何制作一个。
发布于 2017-01-22 23:40:16
如果你使用的是西门子PLC-s,那么图形有一个可选的软件包,叫做S7 -S7:http://w3.siemens.com/mcms/simatic-controller-software/en/step7/simatic-s7-graph/Pages/Default.aspx。您可以在那里实现状态机。但不知道它的任何导入选项。
我将它用于一些作为状态机进行控制的设备。那个软件包不是免费的,我不记得它的价格了。我也不知道是否所有的S7家族都支持它。我使用了400系列,它在那里工作。
在任何项目中使用它之前,请询问您当地的西门子分销商,允许您使用它。
https://stackoverflow.com/questions/41737351
复制相似问题