Standard function blocks
The bistables, edge detectors, counters and timers of Ed.3 Tables 43 to 46, with what the standard leaves to the implementer.
Inputs and outputs that are arrays, structures or strings
A FUNCTION_BLOCK’s VAR_INPUT or VAR_OUTPUT may be an array, a structure
or a STRING. A call copies an input in, f(xs := a), and an output
out, f(hist => b); each source is found or computed before any input
is set, so a call whose arguments fault changes nothing. A STRING too
long for the input or the variable it is taken into is cut and flagged
STRING_LENGTH, as any string store. From outside, an output reads as
the instance’s member, f.hist[0], f.text.
An in-out given, an output taken into, any variable
count(v := totals[i], twice => report.double);
count(v := ptr^, NOT neg => ok);
A function block’s VAR_IN_OUT is given any variable of its type, and an
output is taken into any variable that holds it: an element, a field,
one at an address, one through a reference. Where each is, is found
before the block runs, so an index out of bounds or a NULL reference
stops the statement first and the block does not run. A variable at an
address, of a subrange or through a reference is given to an in-out as
a copy, stored back as the block returns
(Arrays); an output is widened, and clamped into
a subrange, as any store (the harness cases fbargs, inoutcopy).
R_EDGE and F_EDGE inputs
VAR_INPUT clk : BOOL R_EDGE; (or F_EDGE) in a FUNCTION_BLOCK or a
PROGRAM declares, implicitly, an R_TRIG (an F_TRIG) in the instance
(Ed.3 6.6.3.2 rule 13): called with the input as the body starts, its Q
is what the body reads as clk - TRUE in the call that sees the edge
only. The trigger is the standard one, so an F_EDGE input first given
FALSE is TRUE once (Table 44: M starts FALSE). From outside, e.clk
is what was given. A method cannot read such an input (6.6.5.4 rule 3),
and a FUNCTION or a method cannot declare one: it keeps nothing from
one call to the next (E0016). The harness case edgeinputs runs a
block’s and a program’s.
An input set from outside
An instance’s input may be set apart from a call, tm.PT := T#2s
(Ed.3 6.6.7.2.2, Figure 20 a): its field, which the next call reads,
of a standard block as of the program’s own, named directly, as an
element, or through a reference. An output is the block’s alone
(E0015).
Instances: initial values, arrays, structures, globals
TYPE Cooler : STRUCT
temp : INT;
cooling : TOF := (PT := T#100ms); (* Ed.3 Table 11 7a *)
END_STRUCT; END_TYPE
VAR
t : TON := (PT := T#500ms);
c : Count := (inc := 2, limit := 100); (* an input, a PUBLIC variable *)
tons : ARRAY[1..50] OF TON := [50(PT := T#100ms)]; (* Table 11 5b *)
line : ARRAY[1..4] OF Cooler;
END_VAR
tons[i](IN := start);
line[2].cooling(IN := hot);
- An instance’s initial value names its inputs, outputs and PUBLIC
variables (Ed.3 6.6.3.3, and 6.6.5.3 for a class); the others keep
their type’s own.
[50(PT := T#100ms)]repeats one, as Table 11 writes it; the grammar’s50((PT := T#100ms))is the same. - An instance is an array’s element or a structure’s field as any
value is, and is called, read and given there:
tons[i](...),tons[i].Q,line[2].cooling(...), a methodaccs[i].Add(...), an in-out or an interface giventons[i](Figure 8 d, e). Its index is checked first: out of bounds is an INDEX fault, and the statement stops before anything runs. An element is an instance of exactly its type, so a call on it is bound statically. - A global instance, in the CONFIGURATION’s or a resource’s VAR_GLOBAL, is reached by VAR_EXTERNAL from a program or a block.
- A restart keeps them as it keeps their instances.
An instance as a value: copied, and given as an input
VAR a, b : Count; line2 : ARRAY[1..4] OF Cooler; END_VAR
b := a; (* every variable of a copied into b *)
line2 := line; (* an array or structure that holds instances, too *)
total := Peek(a); (* FUNCTION Peek : INT VAR_INPUT c : Count; END_VAR *)
watch(c := a); (* FUNCTION_BLOCK Watch VAR_INPUT c : Count; END_VAR *)
b := acopies the whole instance (Ed.3 Table 72, 1d): its inputs, outputs and internal variables, and the instances it contains, as CODESYS and TwinCAT copy one.bthen runs on from whereawas, and the two are separate. The two are of one type (E0013 otherwise). A reference, an interface or an in-out in it is copied as it is: both then name the same variable.- An instance given as an input is a copy (Ed.3 Table 42, 9a), to
a FUNCTION, a method or a FUNCTION_BLOCK. In the POU that takes it
its variables are read,
c.n,c.Q; it is not written (E0015) and not called (E0016), which Ed.3 6.6.3.4 rules 6 and 7 keep for an instance given as a VAR_IN_OUT. A call made to the copy would be lost with it. An input not given is an instance with its initial values. A function block keeps its copy from call to call, as any input, andwatch.c := a;sets it apart from a call. - An instance given as a VAR_IN_OUT is the caller’s own (Ed.3
6.6.3.4 rules 6 and 7), of a standard block as of the program’s: a
FUNCTION, a method or a FUNCTION_BLOCK calls it,
tm(IN := go, PT := T#1s), reads its outputs and passes it on, and it is the caller’s timer that ran. It is given a variable, an array’s element or what a reference refers to, of the in-out’s type exactly (E0013 otherwise). The harness casestdinoutruns a counter and a timer through each. - A FUNCTION_BLOCK’s output may be an instance, called by the block
that owns it:
watch.own.nreads it,watch(own => d)copies it out. - A FUNCTION’s or method’s output, result or own variable may be an
instance. It is set up at each call and keeps nothing from one call
to the next, as every variable of a FUNCTION (Ed.3 6.6.2.2 rule 10):
a timer there never runs on. The function calls it,
Make.inc := 2; Make();for its result, and the caller gets a copy:e := Make(2);,Work(o => f);, or reads one variable of it,Make(2).n. - A structure or an array that holds instances is a value in all
the same places: an input, an output, an in-out and a result of a
FUNCTION, a method or a FUNCTION_BLOCK, an
ARRAY[*]of instances, and a PROGRAM’s input or output connected to a global of its type. In an input, the instances it holds are read only, as above; its other parts are written as any input’s (the harness caseholders). - Two instances are not compared (E0014): compare their variables.
- An instance of a class, or of a block with methods, a base or an interface, is not copied nor an input or output at all (E0031), nor is an array or structure that holds one: see objects.
The harness case instvalues runs these.
Bistables and edges
SR is set-dominant, RS reset-dominant (Table 43). R_TRIG and F_TRIG see
an edge between one call and the next: a rising edge at the first call
counts when CLK is already TRUE, as the standard’s ST body has it
(M starts FALSE).
Counters count over their type’s range
CTU and CTUD count up while CV is below PVmax, CTD and CTUD down while CV is above PVmin, and the standard leaves both to the implementer (Table 45). In iecf they are the limits of CV’s own type: a CTU (CV an INT) stops at 32767, a CTD at -32768, a CTD_UDINT at 0. A counter never wraps. Q compares CV with PV as the table says, whatever PV is.
Siemens counts the same way, to the range limit of the type. CODESYS and TwinCAT give CV the type WORD, so their CTD stops at 0; Rockwell’s CTUD wraps. matiec stops CTU at PV and CTD at 0, which the standard does not say.
| Counter | Type of CV | Counts up to | Counts down to |
|---|---|---|---|
| CTU, CTD, CTUD | INT | 32767 | -32768 |
| CTU_DINT, CTD_DINT, CTUD_DINT | DINT | 2147483647 | -2147483648 |
| CTU_LINT, CTD_LINT, CTUD_LINT | LINT | 2⁶³-1 | -2⁶³ |
| CTU_UDINT, CTD_UDINT, CTUD_UDINT | UDINT | 4294967295 | 0 |
| CTU_ULINT, CTD_ULINT, CTUD_ULINT | ULINT | 2⁶⁴-1 | 0 |
Timers
TP, TON and TOF (Table 46) time against the task’s clock,
ctx->now_ns, which the platform sets for each run of a task: a timer
sees time pass between scans, not during one. ET counts from 0 to PT
and stops there. A negative PT counts as 0: the timer’s output follows
its input at once. The LTIME forms (TP_LTIME, TON_LTIME, TOF_LTIME) time
in nanoseconds.