我使用msterSCADA4D,我创建了一个屏幕,该怎么往屏幕里添加饼状图,并与每扇绑定标签并实现动...
创建于:2026年4月9日
使用 GPT-5.4 Thinking 回答 Chat01
创建于:2026年4月9日
使用 GPT-5.4 Thinking 回答 Chat01
我使用msterSCADA4D,我创建了一个屏幕,该怎么往屏幕里添加饼状图,并与每扇绑定标签并实现动态显示?
如果你说的是 MasterSCADA 4D,最稳妥的做法是:** 用 SVG 画饼图,再用 XML 把每个扇区和文字暴露成可绑定参数,最后把这些参数和标签连起来**。官方在线帮助明确支持把外部 SVG+XML 导入到窗口里,并把 SVG 的属性、文字内容等做成可动态绑定的参数。窗口本身是在“图形界面/窗口”里创建的,创建后会自动打开图形编辑器。(support.mps-soft.ru)
你可以按这个顺序做:
先准备标签
比如你有 4 个扇区,就准备 4 个数值标签:Tag_A、Tag_B、Tag_C、Tag_D。如果还要显示百分比/名称,再准备对应文本或中间变量。MasterSCADA 4D 支持在图形客户端层做这类逻辑和辅助脚本,因此“先算比例,再喂给画面”这条路是可行的。(support.mps-soft.ru)
用 SVG 画一个饼图底图
建议在 Figma / Inkscape / Illustrator 里画。官方要求 SVG 用外部编辑器制作;所有元素放在根组 g 下,根组要有 id="root";每个需要动态改动的元素都要有有意义的唯一 id。所以你的饼图最好这样命名:
slice_1、slice_2、slice_3、slice_4,文字则用 label_1、label_2…… 这样导入时更稳定。(support.mps-soft.ru)
给 SVG 写同名 XML 描述文件
官方要求 XML 文件和 SVG 同名、同目录。XML 的作用就是告诉 MasterSCADA:哪个 SVG 元素可以被外部控制、控制的是哪个属性、类型是什么。官方给出的结构是 <SvgDef><ParameterDefs><ParameterDef ... /></ParameterDefs></SvgDef>,其中:
ItemId 对应 SVG 元素 idPath 对应要改的属性,比如 fill、width、class,如果改文字内容就写 contentParamType="attribute" 表示改元素属性,ParamType="style" 表示改样式Type 常见有 STRING 和 HMI.SolidColorType。(support.mps-soft.ru)可以先从这个 XML 模板起步:
xml<?xml version="1.0"?> <SvgDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ParameterDefs> <!-- 扇区1 --> <ParameterDef DisplayName="扇区1颜色" ParamType="attribute" ItemId="slice_1" Path="fill" Type="HMI.SolidColorType" /> <ParameterDef DisplayName="扇区1文字" ParamType="attribute" ItemId="label_1" Path="content" Type="STRING" /> <!-- 扇区2 --> <ParameterDef DisplayName="扇区2颜色" ParamType="attribute" ItemId="slice_2" Path="fill" Type="HMI.SolidColorType" /> <ParameterDef DisplayName="扇区2文字" ParamType="attribute" ItemId="label_2" Path="content" Type="STRING" /> <!-- 如果你还想显隐 --> <ParameterDef DisplayName="扇区1透明度" ParamType="attribute" ItemId="slice_1" Path="opacity" Type="STRING" /> </ParameterDefs> </SvgDef>
上面这种“颜色 + 文字 + 透明度”的绑定方式,和官方文档描述的参数化机制是完全一致的。(support.mps-soft.ru)
把 SVG 导入你已经建好的窗口
在库里新建窗口后,右键窗口执行 Import SVG。官方说明里写得很清楚:选择 SVG 后,如果同目录下有对应 XML,会一起导入;导入完成后,这些参数会出现在属性里,并且可以和项目参数建立连接。(support.mps-soft.ru)
把导入好的 SVG 放进你的屏幕,并绑定标签
导入后,SVG 会变成一个可配置的图形元素。官方示例里是把滑块的“当前值”拖到 SVG 的属性上进行绑定;同理,你可以把项目里的标签值绑定到 扇区1颜色、扇区1文字、扇区1透明度 这些属性上。官方也说明,导入后的 SVG 属性可以“与项目参数关联,以便在运行时变化”。(support.mps-soft.ru)
这是最简单、最稳的。
比如 4 个扇区先在 SVG 里画成固定 25% + 25% + 25% + 25%,运行时只改:
fill:颜色随标签变化content:显示实时值或百分比opacity:某扇区无数据时设为 0,有数据时设为 1这个方案完全不需要你去动态改几何形状,落地最快。它完全符合官方的 SVG/XML 动态属性机制。(support.mps-soft.ru)
这个方案也能做,但需要你先在程序里算出每个扇区的角度,再把结果映射到 SVG。官方文档明确支持通过 XML 去改 SVG 元素属性;因此,按这个机制推断,你可以把每个扇区的 path d 当成字符串属性去更新,或者像官方“圆形进度条”示例那样,去动态改 stroke-dashoffset 之类的属性。官方示例已经证明:SVG 属性和值可以动态绑定,并且必要时可通过“线性分段转换”把源值映射成图形值。这里把 d 作为可绑定属性是基于官方属性参数化机制的推断,不是我在文档里看到的现成饼图案例。(support.mps-soft.ru)
你可以在 ST/FBD 里先这样算:
pascalTotal := Tag_A + Tag_B + Tag_C + Tag_D; IF Total > 0 THEN P1 := Tag_A / Total * 360.0; P2 := Tag_B / Total * 360.0; P3 := Tag_C / Total * 360.0; P4 := Tag_D / Total * 360.0; ELSE P1 := 0; P2 := 0; P3 := 0; P4 := 0; END_IF;
然后再算累计角度:
pascalA1_Start := 0.0; A1_End := P1; A2_Start := A1_End; A2_End := A2_Start + P2; A3_Start := A2_End; A3_End := A3_Start + P3; A4_Start := A3_End; A4_End := 360.0;
最后把每个扇区转成 SVG path 字符串,输出到中间变量,比如:
pascalSlice1_Path := SectorPath(50.0, 50.0, 40.0, A1_Start, A1_End); Slice2_Path := SectorPath(50.0, 50.0, 40.0, A2_Start, A2_End); ... Label1_Text := CONCAT('A ', REAL_TO_STRING(Tag_A));
然后在 XML 里把 slice_1 的 d、label_1 的 content 暴露出来绑定。这里 content 是官方明确支持的,d 属于按“属性可参数化”机制做的工程实现。(support.mps-soft.ru)
如果你现在是第一次做,先别直接上“真动态饼图”。建议你先做这个版本:
opacity等这个版本跑通,再升级成动态角度版本。这样排错最少。官方示例里“圆形进度条 + 文本”也是先把 SVG 元素 id、属性、文字内容暴露出来,再做绑定和转换,思路和这里完全一致。(support.mps-soft.ru)
如果你愿意,我下一条可以直接给你一份 “4 扇区饼图的完整 SVG + XML 示例”,你复制到 MasterSCADA 4D 里就能开始绑标签。
<svg width="500" height="400" viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg">
<!-- 背景 --> <rect x="0" y="0" width="500" height="400" fill="#dcdcdc"/> <!-- 标题 --><text x="250" y="40"
font-size="24"
font-weight="bold"
text-anchor="middle"
fill="#333">
Сравнение годных и чёрных фишек
</text>
</g> <!-- 图例 --> <g transform="translate(320, 60)">text<!-- 良品(动态) --> <path id="sliceGood" d="M 0,0 L 0,-150 A 150,150 0 1,1 -150,0 Z" fill="#6ec35a" stroke="white" stroke-width="2"/> <!-- 不良品(动态) --> <path id="sliceBad" d="M 0,0 L -150,0 A 150,150 0 0,1 0,-150 Z" fill="#e04b36" stroke="white" stroke-width="2"/>
</g> </svg> 这是我的svg代码,为我写出对应的xml,要符合要求,而且我需要扇区角度跟数值一起变化,做“真正的动态饼图”,变更其余步骤详细的一步步的说明以及我应该怎么做?text<rect x="0" y="0" width="16" height="16" fill="#6ec35a" rx="2" /> <text x="24" y="12" font-size="16" fill="#333"> Годные </text> <rect x="0" y="30" width="16" height="16" fill="#e04b36" rx="2" /> <text x="24" y="42" font-size="16" fill="#333"> Чёрные </text>
可以,这个能做成真正的动态饼图。关键点有 4 个:
<g id="root">。<path> 的 d 属性暴露出来,因为 MasterSCADA 4D 官方就支持把 path 的 d 作为可绑定参数。d 字符串,再直接绑定到 SVG 属性。<text> 元素加 id,XML 里用 Path="content"。MasterSCADA 4D 官方文档就是这么做的。 (MPS Soft Support)先说一个必须改的地方:你现在这份 SVG 没有根组 g id="root",而官方对可动态 SVG 的通用要求里明确写了,所有图元应放在根组里,根组要有 Id="root";同一控件里需要外部访问的元素也要有清晰的 id。(MPS Soft Support)
下面是尽量少改动、但已经符合导入要求的版本。
我只做了 3 件事:
<g id="root">svg<svg width="500" height="400" viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg"> <g id="root"> <!-- 背景 --> <rect id="bgRect" x="0" y="0" width="500" height="400" fill="#dcdcdc"/> <!-- 标题 --> <text id="titleText" x="250" y="40" font-size="24" font-weight="bold" text-anchor="middle" fill="#333"> Сравнение годных и чёрных фишек </text> <!-- 饼图 --> <g id="pieGroup" transform="translate(180,220)"> <!-- 良品(动态) --> <path id="sliceGood" d="M 0,0 L 0,-150 A 150,150 0 1,1 -150,0 Z" fill="#6ec35a" stroke="white" stroke-width="2"/> <!-- 不良品(动态) --> <path id="sliceBad" d="M 0,0 L -150,0 A 150,150 0 0,1 0,-150 Z" fill="#e04b36" stroke="white" stroke-width="2"/> </g> <!-- 图例 --> <g id="legendGroup" transform="translate(320, 60)"> <rect id="legendGoodColor" x="0" y="0" width="16" height="16" fill="#6ec35a" rx="2" /> <text id="legendGoodText" x="24" y="12" font-size="16" fill="#333"> Годные </text> <rect id="legendBadColor" x="0" y="30" width="16" height="16" fill="#e04b36" rx="2" /> <text id="legendBadText" x="24" y="42" font-size="16" fill="#333"> Чёрные </text> </g> </g> </svg>
把下面内容保存成和 SVG 同名的 XML 文件,并且和 SVG 放在同一文件夹。
例如:
chips_pie.svgchips_pie.xmlMasterSCADA 4D 官方要求 XML 与 SVG 同名、同目录;XML 根结构就是 <SvgDef><ParameterDefs>...</ParameterDefs></SvgDef>,每个参数用 ParameterDef 描述。(MPS Soft Support)
xml<?xml version="1.0"?> <SvgDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ParameterDefs> <!-- 两个扇区的几何形状:真正动态饼图的核心 --> <ParameterDef DisplayName="GoodPath" ParamType="attribute" ItemId="sliceGood" Path="d" Type="STRING" /> <ParameterDef DisplayName="BadPath" ParamType="attribute" ItemId="sliceBad" Path="d" Type="STRING" /> <!-- 两个扇区的颜色 --> <ParameterDef DisplayName="GoodFill" ParamType="attribute" ItemId="sliceGood" Path="fill" Type="HMI.SolidColorType" /> <ParameterDef DisplayName="BadFill" ParamType="attribute" ItemId="sliceBad" Path="fill" Type="HMI.SolidColorType" /> <!-- 可选:0 或 1,用来在 0% / 100% 时隐藏某个扇区 --> <ParameterDef DisplayName="GoodOpacity" ParamType="attribute" ItemId="sliceGood" Path="opacity" Type="STRING" /> <ParameterDef DisplayName="BadOpacity" ParamType="attribute" ItemId="sliceBad" Path="opacity" Type="STRING" /> <!-- 可选:如果你想让图例颜色也跟着变 --> <ParameterDef DisplayName="LegendGoodFill" ParamType="attribute" ItemId="legendGoodColor" Path="fill" Type="HMI.SolidColorType" /> <ParameterDef DisplayName="LegendBadFill" ParamType="attribute" ItemId="legendBadColor" Path="fill" Type="HMI.SolidColorType" /> <!-- 可选:如果你想让图例文字也动态 --> <ParameterDef DisplayName="LegendGoodContent" ParamType="attribute" ItemId="legendGoodText" Path="content" Type="STRING" /> <ParameterDef DisplayName="LegendBadContent" ParamType="attribute" ItemId="legendBadText" Path="content" Type="STRING" /> </ParameterDefs> </SvgDef>
这里最关键的就是:
ItemId="sliceGood" Path="d"ItemId="sliceBad" Path="d"因为官方示例已经明确给过:path 元素的 d 可以在导入时作为参数暴露出来;同样,content 是用来动态改 <text>...</text> 里面文本内容的特殊路径。(MPS Soft Support)
你的图只有两扇,所以实现其实很直接:
GoodValueBadValueTotal = GoodValue + BadValueGoodDeg = 360 * GoodValue / TotalBadDeg = 360 - GoodDeg然后把这两个角度换成 SVG 的 path d 字符串。
你当前饼图的圆心在 translate(180,220) 后的局部坐标 (0,0),半径是 150,起点是正上方 (0,-150)。
所以两扇区的路径都可以按这个逻辑生成:
GoodDegSVG 标准里,d 就是 path 的路径字符串;里面用 M / L / A / Z 这些命令描述几何。(W3C)
建议你建这些标签:
GoodValueBadValueGoodPath —— STRINGBadPath —— STRINGGoodOpacity —— STRINGBadOpacity —— STRINGGoodFill —— 颜色BadFill —— 颜色LegendGoodText —— STRINGLegendBadText —— STRINGMasterSCADA 4D 支持在对象、节点、通道、标签、窗口等元素上挂程序,并在图形客户端层做逻辑和辅助脚本,所以这种“先计算,再绑定到 SVG 属性”的方法是对路的。(MPS Soft Support)
下面给你的是两扇区专用算法,比通用多扇区更简单。
半径固定:
textR = 150
良品扇区终点角度:
textEndDeg = -90 + GoodDeg
终点坐标:
textEndX = R * COS(EndDeg * PI / 180) EndY = R * SIN(EndDeg * PI / 180)
大弧标志:
textLargeGood = 1, 当 GoodDeg > 180 LargeGood = 0, 当 GoodDeg <= 180 LargeBad = 1, 当 BadDeg > 180 LargeBad = 0, 当 BadDeg <= 180
良品扇区:
textM 0,0 L 0,-150 A 150,150 0 LargeGood,1 EndX,EndY Z
不良扇区:
textM 0,0 L EndX,EndY A 150,150 0 LargeBad,1 0,-150 Z
下面我写成接近可直接抄的 ST 伪代码。
不同版本里字符串拼接、字符串替换函数名可能略有差别,所以你只需要把 CONCAT / REAL_TO_STRING / “逗号替换点号”的函数名按你工程里现成函数改一下就行。
pascal(* 输入 *) (* GoodValue : REAL *) (* BadValue : REAL *) (* 输出 *) (* GoodPath : STRING *) (* BadPath : STRING *) (* GoodOpacity : STRING *) (* BadOpacity : STRING *) (* LegendGoodText: STRING *) (* LegendBadText : STRING *) VAR Total : REAL; GoodDeg : REAL; BadDeg : REAL; EndDeg : REAL; EndRad : REAL; EndX : REAL; EndY : REAL; LargeGood : STRING; LargeBad : STRING; END_VAR Total := GoodValue + BadValue; IF Total <= 0.0 THEN GoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '0'; BadOpacity := '0'; ELSE GoodDeg := 360.0 * GoodValue / Total; BadDeg := 360.0 - GoodDeg; LegendGoodText := CONCAT('Годные: ', REAL_TO_STRING(GoodValue)); LegendBadText := CONCAT('Чёрные: ', REAL_TO_STRING(BadValue)); (* 0% / 100% 特殊处理 *) IF GoodDeg <= 0.001 THEN GoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; GoodOpacity := '0'; BadOpacity := '1'; ELSIF GoodDeg >= 359.999 THEN GoodPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '1'; BadOpacity := '0'; ELSE GoodOpacity := '1'; BadOpacity := '1'; EndDeg := -90.0 + GoodDeg; EndRad := EndDeg * 3.1415926 / 180.0; EndX := 150.0 * COS(EndRad); EndY := 150.0 * SIN(EndRad); IF GoodDeg > 180.0 THEN LargeGood := '1'; ELSE LargeGood := '0'; END_IF; IF BadDeg > 180.0 THEN LargeBad := '1'; ELSE LargeBad := '0'; END_IF; GoodPath := CONCAT( CONCAT( CONCAT( CONCAT( CONCAT( CONCAT( 'M 0,0 L 0,-150 A 150,150 0 ', LargeGood ), ',1 ' ), SvgNum(EndX) ), ',' ), SvgNum(EndY) ), ' Z' ); BadPath := CONCAT( CONCAT( CONCAT( CONCAT( CONCAT( CONCAT( CONCAT( 'M 0,0 L ', SvgNum(EndX) ), ',' ), SvgNum(EndY) ), ' A 150,150 0 ' ), LargeBad ), ',1 0,-150' ), ' Z' ); END_IF; END_IF;
SVG 的路径数字一定要用点号小数点,不能用区域设置里的逗号。W3C 的 SVG Paths 规范明确写了,路径数据里允许的 decimal point 是 .,并举例说明像 13,000.56 这样的写法是无效的。(W3C)
所以你还要做一个辅助函数,把 REAL_TO_STRING() 结果中的逗号换成点:
pascalFUNCTION SvgNum : STRING VAR_INPUT Value : REAL; END_VAR VAR s : STRING; END_VAR s := REAL_TO_STRING(Value); (* 这里把逗号替换成点号。 具体替换函数名按你的版本来写。 *) (* 例如:s := ReplaceCommaToDot(s); *) SvgNum := s; END_FUNCTION
这里我故意没把“替换函数名”写死,因为不同版本、不同库里字符串替换函数名可能不一样;但逻辑就是这一句:把 , 换成 .。
把改好的 SVG 和 XML 放在同一目录,同名。
例如:
chips_pie.svgchips_pie.xml官方导入说明就是这么要求的。(MPS Soft Support)
在 库 / 窗口 里新建一个窗口,然后右键这个窗口,执行 “导入 SVG”。官方示例和导入文档都是这条路径。(MPS Soft Support)
导入成功后,在属性面板里你应该能看到:
GoodPathBadPathGoodFillBadFillGoodOpacityBadOpacity官方示例里,导入后会在属性面板里出现对应的 SVG 属性。(MPS Soft Support)
官方 Path 示例的做法也是:先做成一个 SVG 窗口,再把它拖到另一个窗口/画面里使用。(MPS Soft Support)
至少先建:
GoodValueBadValueGoodPathBadPath如果你要颜色和显隐,再建:
GoodFillBadFillGoodOpacityBadOpacity如果要动态图例,再建:
LegendGoodTextLegendBadTextMasterSCADA 4D 支持在窗口等图形层元素上挂 IEC 61131-3 程序。把上面的逻辑写进去,让它持续根据 GoodValue / BadValue 计算路径字符串。(MPS Soft Support)
直接绑定:
GoodPath → SVG 的 GoodPathBadPath → SVG 的 BadPathGoodFill → SVG 的 GoodFillBadFill → SVG 的 BadFillGoodOpacity → SVG 的 GoodOpacityBadOpacity → SVG 的 BadOpacity如果你还做了图例文字:
LegendGoodText → LegendGoodContentLegendBadText → LegendBadContent这里我建议你直接绑定字符串结果,不要走“点式转换”去枚举角度,因为真实饼图是连续变化的,点式转换只适合有限离散状态。官方的 Path 示例里是把路径字符串作为目标值来驱动 d 的。(MPS Soft Support)
先用一组你能手算的值做验证,比如:
GoodValue = 75BadValue = 25这时:
GoodDeg = 270(-150,0)所以你会得到:
textGoodPath = M 0,0 L 0,-150 A 150,150 0 1,1 -150,0 Z BadPath = M 0,0 L -150,0 A 150,150 0 0,1 0,-150 Z
这和你现在 SVG 里那组静态形状正好是一致的。
如果这一步对上了,说明你的公式、弧标志和顺时针方向都没错。
g id="root"这会让 SVG 不符合官方动态化要求。(MPS Soft Support)
REAL_TO_STRING 输出逗号小数如果字符串里出现 -106,07 这种形式,SVG 的 d 解析很容易出错;路径数字要用 .。(W3C)
完整圆不能只靠一条普通 A 弧线从起点绕一圈回自己,所以我在上面的逻辑里给了“两个半圆弧拼成整圆”的特殊写法。
W3C 对 d 的说明是:只有当两次路径字符串的命令结构完全一致时,才能平滑插值;如果命令结构不同,就会离散跳变。也就是说,普通扇区之间可以尝试做平滑,但从“空扇区/整圆”切到普通扇区时,很可能是跳变。(W3C)
按这个顺序做,成功率最高:
GoodPath / BadPath,别急着做文字。LegendGoodContent / LegendBadContent。如果你愿意,我下一条可以直接继续给你一份 “可直接粘贴的完整 ST 程序版本”,我把字符串拼接也按更接近 MasterSCADA 风格给你展开。
我导入后,这是属性,以及我创建了st,我应该在st上面写什么,将完整代码给我,并详细告知我绑定标签的步骤,以及各种细节
你现在这一步已经对了:导入后能看到 GoodPath / BadPath,说明 XML 已经把两个 <path> 的 d 属性成功暴露成可绑定参数了;MasterSCADA 4D 官方的 Path 示例也是通过给 <path> 加 id,再把属性 d 作为 SVG 参数导入来做动态图形。你把 ST 程序建在对象下面也没问题,MasterSCADA 4D 支持在对象、窗口等层级添加 IEC 61131-3 程序。(MPS Soft Support)
先注意一条很关键的规则:需要外部绑定的量,不要只在 ST 代码里声明。官方说明里写了,程序里有“参数”组用于和外部元素建立连接,而只在 ST 文本里声明的变量不能建立连接。所以 GoodValue / BadValue / GoodPath / BadPath ... 这些要在程序的输入输出端子里建成“参数”;代码里的 TotalR / EndDeg / EndXi 之类才放在 VAR ... END_VAR 里当局部变量。(MPS Soft Support)
在 ST_program_1 里,用左右两侧的输入/输出端子创建参数,不要只写在代码里。ST 编辑器本身就有输入/输出端子,程序参数会出现在程序的“参数”组里,方便外部绑定。(MPS Soft Support)
GoodValue : DINTBadValue : DINTGoodPath : STRINGBadPath : STRINGGoodOpacity : STRINGBadOpacity : STRINGLegendGoodContent : STRINGLegendBadContent : STRING先别绑 GoodFill / BadFill / LegendGoodFill / LegendBadFill。
第一轮先把“扇区角度动态变化”跑通,颜色先用 SVG 里原本的绿色和红色。
注意:只粘贴程序体,不要自己再写 PROGRAM ... END_PROGRAM。官方说明里说,ST 编辑器里写的是程序体,输入输出参数靠端子定义。(MPS Soft Support)
pascalVAR GoodR : REAL; BadR : REAL; TotalR : REAL; GoodDeg : REAL; BadDeg : REAL; EndDeg : REAL; EndRad : REAL; EndXr : REAL; EndYr : REAL; EndXi : INT; EndYi : INT; GoodPct : INT; BadPct : INT; LargeGood : STRING; LargeBad : STRING; SX : STRING; SY : STRING; T1 : STRING; T2 : STRING; END_VAR (* 1. 输入值转 REAL,便于后续三角函数计算 *) GoodR := DINT_TO_REAL(GoodValue); BadR := DINT_TO_REAL(BadValue); TotalR := GoodR + BadR; (* 2. 无数据时隐藏整个饼图 *) IF TotalR <= 0.0 THEN GoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '0'; BadOpacity := '0'; LegendGoodContent := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); LegendBadContent := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue)); ELSE (* 3. 计算角度 *) GoodDeg := GoodR * 360.0 / TotalR; IF GoodDeg < 0.0 THEN GoodDeg := 0.0; END_IF; IF GoodDeg > 360.0 THEN GoodDeg := 360.0; END_IF; BadDeg := 360.0 - GoodDeg; (* 4. 计算百分比文字 *) GoodPct := REAL_TO_INT(GoodR * 100.0 / TotalR); IF GoodPct < 0 THEN GoodPct := 0; END_IF; IF GoodPct > 100 THEN GoodPct := 100; END_IF; BadPct := 100 - GoodPct; T1 := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); T1 := CONCAT(T1, ' ('); T1 := CONCAT(T1, INT_TO_STRING(GoodPct)); T1 := CONCAT(T1, '%)'); LegendGoodContent := T1; T2 := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue)); T2 := CONCAT(T2, ' ('); T2 := CONCAT(T2, INT_TO_STRING(BadPct)); T2 := CONCAT(T2, '%)'); LegendBadContent := T2; (* 5. 特殊情况:0% *) IF GoodDeg <= 0.001 THEN GoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; GoodOpacity := '0'; BadOpacity := '1'; (* 6. 特殊情况:100% *) ELSIF GoodDeg >= 359.999 THEN GoodPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '1'; BadOpacity := '0'; (* 7. 正常情况:0% ~ 100% 之间 *) ELSE GoodOpacity := '1'; BadOpacity := '1'; (* 起点固定在圆顶点 (0,-150),终点按角度计算 *) EndDeg := -90.0 + GoodDeg; EndRad := EndDeg * 3.1415926 / 180.0; EndXr := 150.0 * COS(EndRad); EndYr := 150.0 * SIN(EndRad); (* 转整数,避免 SVG 路径里出现小数格式问题 *) EndXi := REAL_TO_INT(EndXr); EndYi := REAL_TO_INT(EndYr); SX := INT_TO_STRING(EndXi); SY := INT_TO_STRING(EndYi); (* 大弧标志 *) IF GoodDeg > 180.0 THEN LargeGood := '1'; ELSE LargeGood := '0'; END_IF; IF BadDeg > 180.0 THEN LargeBad := '1'; ELSE LargeBad := '0'; END_IF; (* 良品扇区路径 *) GoodPath := 'M 0,0 L 0,-150 A 150,150 0 '; GoodPath := CONCAT(GoodPath, LargeGood); GoodPath := CONCAT(GoodPath, ',1 '); GoodPath := CONCAT(GoodPath, SX); GoodPath := CONCAT(GoodPath, ','); GoodPath := CONCAT(GoodPath, SY); GoodPath := CONCAT(GoodPath, ' Z'); (* 不良品扇区路径 *) BadPath := 'M 0,0 L '; BadPath := CONCAT(BadPath, SX); BadPath := CONCAT(BadPath, ','); BadPath := CONCAT(BadPath, SY); BadPath := CONCAT(BadPath, ' A 150,150 0 '); BadPath := CONCAT(BadPath, LargeBad); BadPath := CONCAT(BadPath, ',1 0,-150 Z'); END_IF; END_IF;
这段代码的核心就是动态生成 SVG 的 d 字符串。W3C 对 SVG 路径弧线命令 A 的定义里说明了:large-arc-flag 决定走大弧还是小弧,sweep-flag=1 代表按正角方向扫过去;所以代码里 GoodDeg > 180 时把大弧标志设成 1。(W3C)
你的 ST_program_1 在对象下,最省事的设置是:
官方文档里这两个就是程序“任务”类别里的关键属性;程序可以运行在父对象任务里,也可以跑在屏幕任务里,但你现在这个场景先用“父对象任务 + 周期性”最稳。官方也说明了,不同任务之间的参数连接是支持双向同步的。(MPS Soft Support)
你现在的逻辑链应该是:
PLC/内部标签 -> ST程序输入 -> ST程序输出 -> pie_chart控件参数
不要反过来。
假设你的真实标签叫:
Tag_GoodTag_Bad那么把:
Tag_Good 绑定到 ST_program_1.GoodValueTag_Bad 绑定到 ST_program_1.BadValue这里用直接连接,不要加转换器。
因为程序自己已经负责算比例和生成路径字符串了。
再把:
ST_program_1.GoodPath → pie_chart.GoodPathST_program_1.BadPath → pie_chart.BadPathST_program_1.GoodOpacity → pie_chart.GoodOpacityST_program_1.BadOpacity → pie_chart.BadOpacityST_program_1.LegendGoodContent → pie_chart.LegendGoodContentST_program_1.LegendBadContent → pie_chart.LegendBadContent这里也用直接连接,不要开“点式转换”。
官方 Path 示例里,d 参数本来就是给路径字符串用的;只是官方示例用下拉框 + 转换器去切换离散图标,而你这里已经在 ST 里直接算好了最终字符串,所以不需要再做一次转换。(MPS Soft Support)
这里分两种情况:
pie_chart 直接当成一个独立窗口用那就直接在这个窗口本体上绑。
pie_chart 拖进了另一个画面 123那就应该在 123 这个画面里,选中 pie_chart 实例 后再绑。
也就是说,绑的是实例参数,不是资源定义本身。
你截图里 Resources -> Windows -> pie_chart 说明它现在是一个资源窗口。真正运行时若它被拖进 123,建议在 123 里选中该实例后再做连接,这样最不容易搞混。
先别一上来接 PLC。
先手工给输入值,测这 4 组:
GoodValue = 75, BadValue = 25GoodValue = 50, BadValue = 50GoodValue = 0, BadValue = 100GoodValue = 100, BadValue = 0其中第一组最关键。
75 / 25 时良品应占 270°,终点正好接近 (-150, 0),这时路径应接近你现在静态示例里的那组字符串。
如果这组对了,说明你的角度、终点坐标和弧方向都对了。弧线的四种组合以及 large-arc-flag / sweep-flag 的含义,W3C 路径规范里有明确定义。(W3C)
这样外部没法绑。官方明确说,代码里声明的变量不能建立连接。(MPS Soft Support)
GoodPath/BadPath 加了转换器不要加。ST 已经输出最终 d 字符串了。
如果 pie_chart 是被拖进 123 的,就在 123 里选实例再绑。
检查 ST_program_1 的任务设置是不是“周期性”。
这通常是 legendGoodText / legendBadText 的 id 或 XML 里的 Path="content" 不一致。XML 必须严格对应 SVG 里的元素 id 和属性。(MPS Soft Support)
官方导入说明里写了:如果 SVG 已经加过,再选对应 XML 可以更新描述。也就是说你改过 SVG 或 XML 后,通常要重新导入或更新 XML 描述。(MPS Soft Support)
先只接 6 个输出:
先把饼图“转起来”。
等这个跑通了,再决定要不要第二步加:
你要的话,我下一条直接给你画一张 “从标签到 ST,再到 pie_chart 的绑定示意图”,按你的对象树名字一一标出来。
我已将代码写入,可我又如何将标签与st定义的输入绑定,又如何将把 ST 输出绑到 pie_chart 的 SVG 参数,详细说明每个步骤
从你这张图看,现在 ST 程序还没有真正创建输入/输出参数,因为右侧属性里只有 En0,没有 GoodValue / BadValue / GoodPath / BadPath ...。在 MasterSCADA 4D 里,只有建在程序“输入/输出端子(клеммник)”上的参数,才能方便地和外部标签/窗口属性建立连接;仅在 ST 文本里声明的变量,官方明确说明“不能为其设置连接”。ST 编辑器左侧是输入端子,右侧是输出端子;创建后的参数会出现在图例的“参数”页签和树里的对应分组中。(support.mps-soft.ru)
你现在要做的,不是先去绑 pie_chart,而是先把 ST_program_1 的端子建完整。另外,导入 SVG 后,XML 暴露出来的 GoodPath / BadPath / Legend... 这些就是 SVG 的可绑定参数,XML 的作用正是告诉 MasterSCADA 哪些 SVG 属性会受 SCADA 变量驱动;XML 还必须严格对应 SVG 元素的 id 和属性名。(support.mps-soft.ru)
打开 ST_program_1 编辑器后,左边是输入端子,右边是输出端子。如果你现在没看到完整端子栏,点左右两边的小切换按钮,把端子栏展开。官方文档里写了,输入端子在编辑区左边,输出端子在右边。(support.mps-soft.ru)
你需要在左侧输入端子创建这两个参数:
GoodValue,类型建议 DINTBadValue,类型建议 DINT创建方式有两种,推荐你用第 1 种:
你左边树里已经有两个实际标签,名字看起来就是:
годныеЧёрные你可以直接把这两个标签从树里拖到 ST_program_1 的左侧输入端子区。官方说明写得很明确:** 把项目参数拖到程序里(端子、树、程序区域)时,程序会自动添加同名参数并与其建立连接**。(support.mps-soft.ru)
拖进去后,很可能自动生成两个输入参数,名称会跟原标签名一致,比如:
годныеЧёрные如果你想继续用代码里的 GoodValue / BadValue 这两个名字,那就把新生成的两个输入参数重命名成:
GoodValueBadValueST 编辑器官方说明:如果你在端子里重命名参数,而旧名字已经出现在代码中,会弹窗询问是否同步替换代码里的名字。(support.mps-soft.ru)
如果你不想拖拽,也可以在输入端子里手工“添加参数”,然后命名为:
GoodValue : DINTBadValue : DINT再把左侧树中的 годные 绑到 GoodValue,Чёрные 绑到 BadValue。程序参数本来就建议加在端子上,这是官方推荐的经典用法。(support.mps-soft.ru)
在右侧输出端子创建这些参数:
GoodPath : STRINGBadPath : STRINGGoodOpacity : STRINGBadOpacity : STRINGLegendGoodContent : STRINGLegendBadContent : STRING建好以后,这些输出会出现在程序右侧端子、图例参数页签,以及树中的程序参数组里。(support.mps-soft.ru)
你代码里这些应该继续留在 VAR ... END_VAR 里,作为局部变量:
GoodRBadRTotalRGoodDegBadDegEndDegEndRadEndXrEndYrEndXiEndYiGoodPctBadPctLargeGoodLargeBadSXSYT1T2而下面这些不要写进 VAR 里,它们必须是端子参数:
GoodValueBadValueGoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent因为官方明确说,ST 文本里声明的变量可以用,但不能设置连接。(support.mps-soft.ru)
这一步做完,数据流应当是:
годные / Чёрные -> ST_program_1 输入 -> ST 计算
那这一步其实已经自动完成了。官方文档写明,把项目参数拖到程序端子里时,程序参数会被创建并与之建立连接。(support.mps-soft.ru)
你可以这样检查:
ST_program_1GoodValue、BadValue 是否随真实标签变化那你要手工把树中的真实标签绑到它们:
годныеST_program_1 左侧输入端子中的 GoodValueЧёрные 拖到 BadValue如果你的小版本里不能直接拖到参数名上,通常也可以先选中 GoodValue 这个输入参数,再在属性/连接界面里指定来源变量。这里不同小版本的按钮名字可能略有不同,但本质就是建立“标签 → 程序输入参数”的关系。官方确认程序参数就是用来和项目树参数建立这类关系的。(support.mps-soft.ru)
完成后,ST_program_1 的属性面板里就不该只有 En0 了,而应该能看到你新增的输入/输出参数。创建在端子里的参数还会出现在图例的“参数”页签,以及树中的程序参数分组里。(support.mps-soft.ru)
pie_chart 的 SVG 参数这一步做完,数据流应当是:
ST_program_1 输出 -> pie_chart 实例参数 -> SVG 的 d/content 属性
你左边树里看到的 pie_chart 在 Resources > Windows 下,它是资源窗口。真正显示在画面上的,应该是你把它拖进 123 这个窗口后的实例。
你要绑定的,优先应该是 123 画面里那个 pie_chart 实例 的参数,而不是只绑定资源定义本身。否则经常会出现“资源里改了,运行画面没反应”。这点不是官方一句话写死的规则,而是 HMI 资源/实例的常见实际用法;你现在这个结构下,按实例绑最稳。
123切到窗口 123,确认里面已经放了一个 pie_chart。如果没放,就把资源窗口 pie_chart 从资源树拖进 123。导入 SVG 的官方流程就是先在库里建窗口,再把 SVG 加进去作为窗口内容。(support.mps-soft.ru)
123 里选中 pie_chart 实例选中以后,看右侧属性面板。
在它的 Parameters 分组里,你应该能看到这些 SVG 参数:
GoodPathBadPathGoodFillBadFillGoodOpacityBadOpacityLegendGoodContentLegendBadContent这些参数之所以会出现,是因为 XML 已经把它们定义成了可动态绑定的 SVG 属性。(support.mps-soft.ru)
pie_chart 对应属性现在再打开 ST_program_1,从它的输出端子或者图例-参数页签里,把输出参数拖到 pie_chart 实例的对应属性行上。
一一对应绑定成这样:
ST_program_1.GoodPath → pie_chart.GoodPathST_program_1.BadPath → pie_chart.BadPathST_program_1.GoodOpacity → pie_chart.GoodOpacityST_program_1.BadOpacity → pie_chart.BadOpacityST_program_1.LegendGoodContent → pie_chart.LegendGoodContentST_program_1.LegendBadContent → pie_chart.LegendBadContent如果你的小版本允许直接拖到属性值单元格,这样最快。
如果不能直接拖到属性格里,就选中对应属性后,用该属性的“绑定/连接”按钮去指定来源参数为 ST_program_1 的对应输出。这里具体按钮图标在不同小版本可能略有差别,但本质上是让 SVG 参数的值来源于 ST 输出参数。官方关于 SVG/XML 的说明就是:XML 定义哪些 SVG 属性能动态变化,以及哪些 SCADA 数据会驱动它们。(support.mps-soft.ru)
你先只绑这 6 个:
GoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent把“扇区几何”和“图例文字”跑通以后,再决定是否要让颜色也动态。这样排错最少。
要,改一处就行:确保代码里用到的输入/输出名字,和你端子里创建的参数名字完全一致。
也就是说:
GoodValue / BadValue,代码就保持不变。годные / Чёрные,那你就要么把端子重命名成 GoodValue / BadValue,要么把代码中的 GoodValue / BadValue 改成俄文名。官方说明里,端子改名时可以联动替换 ST 代码中的旧名字。(support.mps-soft.ru)
你照这个顺序做,最不容易乱:
在 ST_program_1 左边输入端子创建:
GoodValueBadValue在 ST_program_1 右边输出端子创建:
GoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent检查代码里没有把这些名字写进 VAR 局部变量区。
把左边树里的真实标签绑定到:
годные → GoodValueЧёрные → BadValue打开 123 画面,选中里面的 pie_chart 实例。
把 ST_program_1 的 6 个输出参数绑定到 pie_chart 的 6 个同名 SVG 参数。
编译/检查程序。
在线测试 4 组值:
En0说明你还没在端子里真正创建程序参数。只写代码不够。官方明确说,ST 文本中声明的变量不能设置连接。(support.mps-soft.ru)
GoodValue、GoodPath 未定义说明这些名字还没有在输入/输出端子里建出来。
pie_chart 不动通常是你绑到了资源窗口 pie_chart,而不是绑到 123 画面里的实例。
说明 LegendGoodContent / LegendBadContent 没有绑定到实例参数,或者 XML 里的 content 对应的 id 不一致。XML 必须严格对应 SVG 的结构和元素 id。(support.mps-soft.ru)
官方说明:SVG 已经导入过后,再选对应 XML 可以更新描述。也就是说改完 XML 后,通常要重新导入或更新该 SVG 的 XML 描述。(support.mps-soft.ru)
你其实可以直接这么做:
годные 拖到 ST 左侧输入端子Чёрные 拖到 ST 左侧输入端子GoodValue、BadValue123 中选中 pie_chart 实例这样最快。
如果你愿意,我下一条直接按你这棵树的名字,给你画一份**“从左侧标签到 ST,再到 123 里的 pie_chart 实例”的文字接线图**,你可以对着一个个连。
我的左侧没有输入,这是为什么,而且我的标签也无法拖入没有输入的地方,这该如何解决?
你这个不是“不能有输入”,而是左侧输入端子被折叠/没建参数了。
从你截图看:
EnO另外,官方也明确说了:只在 ST 文本里写声明的变量,不能设置外部连接;要做你这种“标签绑定到 ST,再绑定到 SVG”的结构,推荐用程序端子参数。把项目里的参数拖到程序的端子、树或程序区,系统会自动创建程序参数并建立连接。(support.mps-soft.ru)
你现在 ST 编辑器最左边那条灰色栏,中间靠左有一个白色小箭头。
点它一次,左侧输入端子就会展开。
这是官方定义的“输入端子可见性开关”:输入端子在左边,小按钮控制“只显示开关”还是“显示整个端子栏”。(support.mps-soft.ru)
输入端子只是个容器。
你没创建输入参数时,它展开后也会是空的。
你照这个顺序做。
官方说明:把项目参数拖到程序里(端子、树、程序区)时,程序会自动新增同名参数并和它建立连接。(support.mps-soft.ru)
你这样做:
годныеЧёрныегодные 拖到 ST 左侧输入端子空白区Чёрные 拖进去拖进去以后,程序会自动生成两个输入参数,并且已经连上原标签。官方就是这么定义的。(support.mps-soft.ru)
官方同样写了:项目参数拖到程序区也会创建程序参数并建立连接。(support.mps-soft.ru)
所以如果你对着端子不好放,可以直接把:
годныеЧёрные拖到中间白色代码编辑区里。
拖完后,程序里也会新增参数。
输出参数不能从项目树直接拖出来,因为它们是程序算出来的。
所以你需要在右侧输出端子自己加。
你现在右边能看到 EnO,说明右侧端子是打开的。
你需要再新增这 6 个输出参数:
GoodPath : STRINGBadPath : STRINGGoodOpacity : STRINGBadOpacity : STRINGLegendGoodContent : STRINGLegendBadContent : STRING不同小版本按钮样式可能不一样,但通常有这几种方式之一:
STRING官方定义里,右侧端子就是“访问方式为 Output 的程序参数”。(support.mps-soft.ru)
如果右键菜单里没有“添加参数”,就去:
Parameters但新增时一定保证它们是 Output。
要看你刚才拖进去后生成的输入参数名字是什么。
例如变成:
годныеЧёрные那你有两个选择:
改成:
GoodValueBadValue官方说明:在端子里重命名参数时,如果旧名字已经在 ST 代码里出现,系统会提示是否同步替换代码中的名称。(support.mps-soft.ru)
这是最推荐的。
把代码里的:
pascalGoodR := DINT_TO_REAL(GoodValue); BadR := DINT_TO_REAL(BadValue);
改成:
pascalGoodR := DINT_TO_REAL(годные); BadR := DINT_TO_REAL(Чёрные);
但这个不太推荐,因为后面维护不方便。
pie_chart 的 SVG 参数这一步你要去 123 画面里选中 pie_chart 实例,不是只盯着资源树里的 pie_chart。
123点击上方 123 标签页。
pie_chart让右侧属性栏显示这个图元的属性。
这时你应该能看到:
GoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent这些是 XML 暴露出来的 SVG 参数,本来就是给动态绑定用的。(support.mps-soft.ru)
把 ST_program_1 的输出参数,绑定到 pie_chart 的同名参数:
ST_program_1.GoodPath → pie_chart.GoodPathST_program_1.BadPath → pie_chart.BadPathST_program_1.GoodOpacity → pie_chart.GoodOpacityST_program_1.BadOpacity → pie_chart.BadOpacityST_program_1.LegendGoodContent → pie_chart.LegendGoodContentST_program_1.LegendBadContent → pie_chart.LegendBadContent常见有两种方式:
从 ST_program_1 的输出端子,把参数拖到 pie_chart 属性值单元格上。
点 pie_chart 某个属性值格,再用“绑定/连接”按钮指定来源为 ST_program_1 的对应输出。
先不要一次全做完。先按这个最小闭环测试:
先让它跑最核心的几何:
输入:
GoodValueBadValue输出:
GoodPathBadPath然后在 pie_chart 里只先绑:
GoodPathBadPath如果饼图角度已经会变化,再继续加:
GoodOpacityBadOpacityLegendGoodContentLegendBadContent这样排错最容易。
解决:点最左边小箭头展开。
官方明确说左侧按钮控制输入端子显示。(support.mps-soft.ru)
解决:你还没创建输入参数。
把 годные、Чёрные 拖进去即可。官方说明拖入程序会自动建参数并连上。(support.mps-soft.ru)
解决:必须通过端子/程序参数创建可连接的输入输出。
官方明确写了,ST 文本里声明的变量不能设置连接。(support.mps-soft.ru)
годные 拖进去Чёрные 拖进去GoodValue、BadValueGoodPath / BadPath / GoodOpacity / BadOpacity / LegendGoodContent / LegendBadContent123pie_chartpie_chart 同名参数把你点开左侧端子后的截图再发我一张,我可以直接按你当前界面告诉你“下一步点哪里”。
我现在没有实际的plc设备,我也只是在object1上面自己创建的标签,我该怎么测试图形的正确与否?我希望标签能够随时间变化,图形也跟变化,我该怎么测试?
可以,不用 PLC 也能完整测试。最实用的办法是把 Object1 里你自己建的标签当成“模拟 PLC 标签”,再加一个 “信号发生器”ST 程序,让这两个标签随时间自动变化;你的饼图程序继续像读取真实设备标签一样去读它们。MasterSCADA 4D 里对象参数可以直接建在对象里,程序参数建议放在程序端子上,并且把项目参数拖进程序时会自动创建并建立连接;另外,ST 里自己 VAR 出来的变量不能直接和外部项目元素建立连接。(support.mps-soft.ru)
最稳的测试分两步:
先别急着做动画。
先验证几何对不对。
你可以临时用一个很简单的 ST 程序输出固定值:
pascalGoodValue := 75; BadValue := 25;
这时饼图应该明显是 3/4 绿色,1/4 红色。
然后再改成下面几组去看是否正确:
pascalGoodValue := 50; BadValue := 50; GoodValue := 0; BadValue := 100; GoodValue := 100; BadValue := 0; GoodValue := 25; BadValue := 75;
如果这 4 组都对,你的 GoodPath / BadPath 算法基本就通了。
这里我建议你单独建一个程序,名字比如:
ST_simulator放在 Object1 下面,专门负责给测试标签喂数据。
你的饼图程序继续放在 Object2 或现在的位置,不用改思路。
建两个整数标签,直接用你现在已有的也行,比如:
годныеЧёрные再建一个程序:
ST_simulator保留你现在的饼图程序:
ST_program_1它的输入仍然是:
GoodValueBadValue它的输出仍然是:
GoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent这个版本不依赖 PLC,也不依赖系统时钟函数,只依赖程序周期执行。
它利用 Phase 这个局部变量在每个周期累加,再用 SIN() 生成平滑变化。MasterSCADA 4D 的普通本地变量 Local 会在调用之间保留值,而 Temp 才会每次重新初始化;SIN 的输入是弧度。(support.mps-soft.ru)
ST_simulator 建两个输出参数在程序右侧输出端子创建:
GoodValue : DINTBadValue : DINT然后把下面代码粘进去:
pascalVAR Phase : REAL; GoodR : REAL; END_VAR (* 每个周期推进一点相位,数值越大变化越快 *) Phase := Phase + 0.08; IF Phase > 6.283185 THEN Phase := Phase - 6.283185; (* 2*pi *) END_IF; (* 生成 5~95 之间变化的良品数 *) GoodR := 50.0 + 45.0 * SIN(Phase); GoodValue := REAL_TO_DINT(GoodR); BadValue := 100 - GoodValue;
这里 REAL_TO_DINT 会做四舍五入式转换。(support.mps-soft.ru)
GoodValue 会在大约 5 到 95 之间来回变化BadValue 会自动变成 100 - GoodValue100这对验证饼图最直观。
ST_simulator 直接输出到 Object1 的两个标签这是最像“PLC 采集值”的测试方式。
在 Object1 下确认你有两个标签:
годныеЧёрные它们用整数标签就行。MasterSCADA 4D 标准标签里有整数、实数、逻辑等类型。(support.mps-soft.ru)
打开 ST_simulator。
在右侧输出端子创建:
GoodValueBadValue把这两个输出分别和 Object1 里的标签建立连接:
ST_simulator.GoodValue → Object1.годныеST_simulator.BadValue → Object1.Чёрные如果你习惯拖拽,直接把对象参数拖进程序/端子可以自动建立程序参数和连接;官方推荐经典做法还是通过程序端子来做。(support.mps-soft.ru)
保持 ST_simulator 为周期执行。
你截图里 Execution method = Periodic 已经是对的,继续保持就行。
现在你的 ST_program_1 就相当于“图形计算程序”。
它不要直接接 PLC,而是接刚才那两个测试标签。
ST_program_1 的输入端确保有两个输入参数:
GoodValueBadValue把 Object1 的两个标签绑到这里:
Object1.годные → ST_program_1.GoodValueObject1.Чёрные → ST_program_1.BadValue这样数据链路就是:
ST_simulator -> Object1 标签 -> ST_program_1 -> pie_chart
这和以后换成 PLC 的时候几乎一样,只是把数据源从 PLC 改成了你自己的模拟程序。
在 123 画面里选中 pie_chart 实例,确认这几个参数已经绑定到 ST_program_1 输出:
GoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent然后运行项目,看 3 件事:
如果这三件事同时成立,你的整条链路就是通的。
如果你想先最小化排错,建议你这样连:
годныеЧёрныеST_simulatorST_program_1pie_chartST_simulator.GoodValue → Object1.годныеST_simulator.BadValue → Object1.ЧёрныеObject1.годные → ST_program_1.GoodValueObject1.Чёрные → ST_program_1.BadValueST_program_1.GoodPath → pie_chart.GoodPathST_program_1.BadPath → pie_chart.BadPathST_program_1.GoodOpacity → pie_chart.GoodOpacityST_program_1.BadOpacity → pie_chart.BadOpacityST_program_1.LegendGoodContent → pie_chart.LegendGoodContentST_program_1.LegendBadContent → pie_chart.LegendBadContent也可以更简单:
ST_simulatorST_program_1 里直接写死输入值做校验例如临时改成:
pascalGoodValue := 75; BadValue := 25;
或者做一个很简单的动态版本:
pascalVAR Phase : REAL; GoodR : REAL; END_VAR Phase := Phase + 0.08; IF Phase > 6.283185 THEN Phase := Phase - 6.283185; END_IF; GoodR := 50.0 + 45.0 * SIN(Phase); GoodValue := REAL_TO_DINT(GoodR); BadValue := 100 - GoodValue;
但这只是“自测几何”。
真正贴近以后接 PLC 的方式,还是前面那个“Object1 测试标签 + ST_simulator”的方案。
用下面这几个观察点最容易:
50 / 50 时,图应该正好半圆对半75 / 25 时,绿色应该大约占 3/495 / 5 时,绿色应该接近整圆,只剩一点红0 / 100 时,只剩红色整圆100 / 0 时,只剩绿色整圆如果这些状态都对,说明:
sweep-flag 方向对了改这一行:
pascalPhase := Phase + 0.08;
0.02:更慢0.15:更快0.30:很快不用 SIN,直接做加减计数也行。
比如每周期加 1,到 95 后再减回 5。这样更容易肉眼检查每一级变化。
pascalVAR GoodValueInt : DINT; DirUp : BOOL := TRUE; END_VAR IF DirUp THEN GoodValueInt := GoodValueInt + 1; IF GoodValueInt >= 95 THEN GoodValueInt := 95; DirUp := FALSE; END_IF; ELSE GoodValueInt := GoodValueInt - 1; IF GoodValueInt <= 5 THEN GoodValueInt := 5; DirUp := TRUE; END_IF; END_IF; GoodValue := GoodValueInt; BadValue := 100 - GoodValue;
这个版本的优点是:
你可以很容易看出是不是每一步都正确。
你现在最值得做的是:先加一个 ST_simulator,把上面的动态代码跑起来。等你把连接做好后,把你的对象树和 ST_simulator 端子截图发我,我可以直接按你的界面把“哪一根连哪一根”给你标出来。