3

I have made a function block using CODESYS to perform energy metering. The inputs of the function block is current and voltage and the output is energy. Now, we need to have 1000 instances of this function block to run the code for 1000 meter we have. Writing (and possibly copy and pasting) of these instances doesn't seem to be the most interesting work. Wondering if anybody has a smarter way of doing this numerous instantiation.

For example, here is how the code (in CODESYS) looks like for 2 instances:

meter_instance1(CURRENT:=I1, VOTAGE:=V2);
Energy1:= meter_instance1.ENERGY;

meter_instance2(CURRENT:=I2, VOTAGE:=V2);
Energy2:= meter_instance2.ENERGY;

And we like to have 1000 instances of it. Any idea is highly appreciated.

aghd
  • 685
  • 2
  • 9
  • 20

2 Answers2

5

Just make an array of the function block:

aEnergyMeter : array [0..999] of FB_EnergyMeter;

Also make arrays of the voltage and the current:

aVoltage : array [0..999] of INT; //if you use INT as type

aCurrent : array [0..999] of INT;

Then you can use it like that:

aEnergyMeter[0](CURRENT:= aCurrent[0], VOLTAGE := aVoltage[0]);

As you use different arrays with the same size, I would prefer to define some global constant:

VAR GLOBAL CONSTANT
firstDevice : UINT := 0;

lastDevice : UINT := 999;

END_VAR

Then you can define the array like that:

aEnergyMeter : array [firstDevice..lastDevice] of FB_EnergyMeter;
aghd
  • 685
  • 2
  • 9
  • 20
Arndt
  • 98
  • 5
2

I agree with Arndt that you should use an array of function blocks and an array for voltage and current. Depending on your scan rate of your task you should be able to use a for loop to scan through all of your function blocks in a couple lines of code

var
  meterInstance : array[1..1000] of FB_EnergyMeter;
  voltage : array[1..1000] of int;
  current : array[1..1000] of int;
  energy  : array[1..1000] of int;
end_var


for i:=1 to 1000 by 1 do
  meterInstance[i](Voltage := voltage[i],Current:= current[i]);
  energy[i] := meterInstance.Energy;
end_for;

in that for loop you could also combine some error checks while you're at it

for i:=1 to 1000 by 1 do
  meterInstance[i](Voltage := voltage[i],Current:= current[i]);
  if meterInstance.Energy > MaxEnergy then
    //sound alarm
  end_if;
end_for;

The only caveat with this approach is if the scan time is too fast for your task. You could possibly get a watch dog error as the task would overrrun. However since you are only doing 1000 elements and I am assuming your function block is not extremely complex you should be ok with this approach. If you have problems try extending scan time or watch error time.

mrsargent
  • 2,267
  • 3
  • 19
  • 36
  • I implemented the technique, it runs without error. However, I am getting a peculiar response. I am using a loop of two meters as a test. Starting of the code is " FOR K:=0 TO 1 DO". After running the code as simulation, I see that the value of K stuck at "2" and the instance value are not updated. I checked the function block instances and they are running fine and updating values. However, the values are not being transferred to the program. – aghd Aug 07 '17 at 15:20
  • if you set a breakpoint in your program and step through the for loop line by line do you see the values getting transferred to the instance? As long as the function block is public (accessible for anywhere in the program) they should be updating. – mrsargent Aug 07 '17 at 20:25
  • It is now working. I had to re-initiate the LOOP COUNTER at the end of the cyclic interval. – aghd Aug 08 '17 at 18:57