I am coming from an era of Factory Floor and Pac, where the speed has always been a consideration if you are controlling machines or producing higher speed controls. Therefore, with this in mind, I have the following issue to bring to the floor.
From the first platform, cycle times have often required logic time saving techniques. The basic one has always been read the rack with one command (such as MoveIoUnitToNumTableEx(Mkt_Rack1, Mkt_Rack1_fTable, 0, 24);), then handle the logic, either with tables or individual vars OR do I read ech IO point as I come to it?
My preference has always been to load all the vars from the read table at the top of your main logic looping chart. I think most would agree that reading each var is bad practice, however, there are exceptions to this on a case by case basis in the interest of the current realtime state of an input.
What I think newcomers to Opto22 may or may not realize is the shear magnitudes of speed in processing internal variables (as apart from IO of any kind). Even the Pac controllers processed internal vars so fast that loading and unloading large tables in a script is not even worth thinking about. So even if you have 512 IO on a controller, unloading the read table to 512 variables is not an issue.
Next the other issue has been do I load all the vars into the read table at the bottom of the chart and write them all at once with the MoveNumTableToIoUnitEx(Mkt_Rack1_fTable, 0, Mkt_Rack1, 24); command? OR do I write each variable out in the logic everywhere that logic occurs in the strategy? And do I write it every time or only when it needs to be written?
Keeping that in mind, unloading the read table to each variable provides 2 possible sources of state for each variable, in the variable itself, and in the table from where that value came. This provides the possibility of creating an exception write, by comparing the read table value to the internal variable state. Keep in mind, I always use an internal variable as a reflection of the IO point, such as:
//digital output module 0
Servo_Reset_dout = Mkt_Rack1_fTable;
Servo_Run_dout = Mkt_Rack1_fTable;
Servo_Select_dout = Mkt_Rack1_fTable;
This means that for each IO point, I have an integer (or float) that is used internally in the controller as shown in the script above. So these points would actually be Servo_Reset_do, Servo_Run_do, Servo_Select0_do.
By using these two states, I can create a write script in the last block, of the loop chart that writes any variable out directly (individual writes) to the rack if the value in the table is not equal (<>) to the value in the varibale. Therefore, anywhere in the strategy, I can change the internal var and know that it will be written out on that cycle, and also know that it will not be written if I do not change the var.
In addition to creating an exception write system, I can therefore use digital output features such as StartOnPulse without having it overwritten by an output table that writes all of the IO on each cycle. Remember, when the command MoveNumTableToIoUnitEx, it only writes to outputs and it writes to all outputs, regardles. So even if you do not change the value of an output table element, it still writes whatever value exists, which will over write any output feature command you may have issued.
In the exception write example I described, the value does not get written in a table, but gets written directly, and it does not get written unless I have changed the internal var. This means that if anywhere in the chart (between these two input and output blocks) I can do a direct write or a feature write to an ouput point directly, and not cause an output write in the output block to occur and therefore the feature or direct change I made to the point gets preserved. It does so not only is it not over written, but it is also read into the read table on the next cycle, and now the output block will not see a value change.
Let’s take the StartOnPulse, I write the command, the output block doesn’t yet see a change, it doesn’t write, in the meantime the pulse is ON and continues in that state, the next read table will have whatever that state is, and it gets maintained until it sees a change in that state. So in theory, the ON value is read, the ON value if not changed in the logic is not written on the next cycle maintaining the current state of the feature. Once the current state of the feature turns the point off, the value is read and now the new state is maintained.
Lets also consider if the ON state turns off after the read, and during the logic phase of your chart. This still works because the current value read into the table is same as value in the internal variable, therefore, not write will occur even after the On pulse turns off.
Here is an example of the output writes:
if(Mkt_Rack1_fTable <> Servo_Reset_dout) then Servo_Reset_do = Servo_Reset_dout; endif
if(Mkt_Rack1_fTable <> Servo_Run_dout) then Servo_Run_dout = Servo_Run_dout; endif
if(Mkt_Rack1_fTable <> Servo_Select_dout) then Servo_Select_dout = Servo_Select_dout; endif