Przejdź do głównej zawartości

MC252 program language

Ta treść nie jest jeszcze dostępna w Twoim języku.

An MC252 edge program is a taskfile: a text file the controller compiles and runs again and again. MC252 firmware 48 to 50 compile language version 12; this page describes firmware 50. HMI checks the source as you type, following the same rules; the device’s own compile result stays authoritative. How HMI stores and deploys programs is in MC252 edge programs.

In the program editor, hovering a word shows how it is written, a one-line description, and a Docs link to its section here.

Headings show how each item is written. Operand names in them say what goes there: variable is a variable name; value a variable or an integer; condition a condition name; label, string and parameter the name of one; target the variable or condition that receives a result.

A program is a sequence of lines. Each line is empty, an option, a definition or an action.

  • ; or # starts a comment that runs to the end of the line, except inside a string.
  • A line can start with a label, a name followed by :. GO, CALL and TRYCALL jump to labels. A label can stand on its own line, before the action it marks.
  • Words are separated by spaces or tabs.
  • Everything is case-insensitive except string text: CALL, Call and cAlL are the same word, and pump and PUMP the same name.
  • A line holds at most 198 bytes before its comment; a longer one fails to compile. Comments do not count.
  • An @ anywhere in a line, outside its comment, makes it an option line, so strings cannot contain @.
  • Integers are 64-bit signed, written in decimal (-150) or hexadecimal (0x1F).

A name (of a definition or label) has 1 to 39 bytes of printable ASCII, does not start with a digit or a sign followed by a digit, and contains none of :@=+-/*%><[]. It is not a reserved word: an option, statement, command, function, type, memory source, table letter, error name, VAR, VARS, COND, CONDS, TRUE, FALSE, LASTERROR or EMPTYSTRING. RUN and ONERROR name only labels. A name can be defined once.

An item is defined before it is used, with these exceptions: labels and strings can be used before their definition, and variables and conditions are defined where an action first uses them (see Variables). Each kind of item (devices, parameters, strings, variables, conditions, labels) and the actions of a file are limited to 49151 each; an array counts as its size, so no array has more than 49151 items.

@PROTOCOLVERSION 12
@UPDATE 10 ; run every 10 seconds
DEF sensor MBWRSINGLE 3 16 ; Modbus unit 3
DEF temperature INT16 sensor H 100 ; tenths of a degree
DEF relay BIT sensor C 0
DEF setpoint INT16 MEMBAT H 5000 ; kept on battery, also the controller's register 5000
DEF failure "Sensor failed: *ERR(lasterror)*"
run:
PUT t READ temperature
PUT limit READ setpoint
IF ISNOTKNOWN limit
PUT limit 250 ; default while the setpoint was never written
PUT hot GR t limit
IF hot
WRITE relay 1
IF NOT hot
WRITE relay 0
EXIT OK
onerror:
SYSLOG failure
EXIT LASTERROR

An option line is @, the option and an integer value. A value that is not an integer or is out of range fails to compile. An option sets compilation for the whole file or how its task runs.

The language version the file is written for. Only 12 is accepted; any other value, including 11 of older examples, fails to compile. Put it first.

The interval between two runs of the task, 1 to 2000000 seconds; default 60. The actual interval depends on the controller’s load: parameter reads and writes and SMS make a run longer. A run that comes due while the previous one still runs starts as soon as that one ends; when more than one run is late, the extra runs are skipped, which can break counters that count runs.

Divides the interval for sub-second runs: with a non-zero divisor, the interval is UPDATE / UPDATEDIVISOR seconds. 0 (the default) keeps whole seconds. With a non-zero divisor, the integer quotients UPDATE / UPDATEDIVISOR must not exceed 60 and UPDATEDIVISOR / UPDATE must not exceed 500. Each option is checked against the value the other has at that line (@UPDATE is 60 until set), so put @UPDATE first: @UPDATE 2 then @UPDATEDIVISOR 3 runs about every 667 ms.

The share of time, 1 to 100 percent, that reads and writes of device parameters may take; the default is 25. After each device operation the task waits so that the operation took this share: 100 adds no wait, 50 waits as long as the operation took, 25 three times as long. The wait leaves the bus to other clients. Memory parameters are not affected.

How long a read or write of a device parameter waits for the answer, 0 to 5000 ms; default 5000. An operation that times out raises EXC_PARAM_TARGET_FAILED. Memory parameters are not affected.

The size of variables. Only 64 is accepted: variables are 64-bit signed integers.

The size of item indexes. Only 16 is accepted.

Whether variables and conditions are reset before each run: 0 (default) keeps their values in RAM from run to run until the controller restarts or loses power; 1 makes every run start with unknown values.

Which keywords may be left out: 0 none, so commands take the prefix RE (RE RETURN) and copies VAL; 1 (default) the command prefix and VAL; 2 also DEF and PUT. IF is always written. Write commands without DO, which does not compile.

Defines name as the kind of item that follows: a string, a variable or condition, a Modbus device or a parameter. Items a definition refers to are defined earlier in the file. With @SYNTAX 2, DEF may be left out.

A variable holds a 64-bit signed integer or is unknown (see Unknown values). VARS defines an array of count variables, from 1 up to the limit of a file; an array of one is a plain variable.

DEF is optional for single variables: PUT, a function operand or a string reference defines a variable where it first appears. Define a variable first when its first use cannot tell its kind: a plain copy (PUT a b where neither is known yet) or ISKNOWN fails to compile otherwise. Arrays are always defined first.

LASTERROR is a predefined variable; see LASTERROR.

A condition holds TRUE, FALSE, or is unknown. CONDS defines an array of count conditions, with the same limit. As with variables, a single condition is defined where it first appears, except where the first use cannot tell its kind.

The two condition values. They can be copied into a condition (PUT ready TRUE) or checked (IF TRUE); functions that take conditions, such as AND and NOT, take condition names, not these literals.

An array item is name[index], counted from 0.

  • An integer index (levels[2]) works wherever a single item does. It is checked at compile time.
  • A variable index (levels[i]) compiles in fewer places: on one side of a plain copy (PUT levels[i] t or PUT t levels[i], not both), as the target of READ, SQRT, BITSNOT and ERR, and on one side of NOT. Elsewhere it fails to compile. The index is a single variable. At run time an index outside the array raises EXC_OUT_OF_BOUNDS; an unknown index, EXC_UNKNOWN.
  • On firmware 49, copying from an item by a variable index above 0 (PUT t levels[i] with i of 1 or more) stops the run, although it compiles. Read items with an integer index, or keep one variable per item.
  • MAX, MIN, SUM, MAXIDX, MINIDX and SELECTBY take whole arrays.

A string: text in double quotes, kept as written (case-sensitive). ** stands for one *; other * pairs enclose string references filled in at run time. The text can hold ; and #, but not @. SYSLOG, SENDSMS, PARAMLOG, SMSRCVD and NOSMSRCVD take strings and may name one defined later in the file.

A string produces at most 127 bytes of output, after references are filled in; UTF-8 letters outside ASCII take two or more bytes. The compiler accepts longer strings, but their output does not fit the device’s buffer.

EMPTYSTRING is a predefined string of zero length, for example the sender of SMSRCVD that matches any number.

*VAR(variable)*, *ERR(variable)*, *PHONE(index)*

Section titled “*VAR(variable)*, *ERR(variable)*, *PHONE(index)*”

References in a string, replaced when the string is used:

  • *VAR(variable)*: the variable’s value in decimal. *variable* is short for it.
  • *ERR(variable)*: the name of the error code the variable holds, such as EXC_IO.
  • *PHONE(index)*: the GSM phone number at index, 0 to 3, in the device settings.

LASTERROR works in VAR and ERR.

DEF report "Level *VAR(level)* of *VAR(limit)*, last error *ERR(lasterror)*"
DEF formula "5 ** 2 = *VAR(product)*" ; prints 5 * 2 = …
DEF operator "*PHONE(0)*"

A device definition names a Modbus unit that parameters read and write. unit is a fixed unit ID 1 to 255, * for the controller’s own unit ID, or a variable plus an offset 1 to 255 (base+1), read at run time. read and write limit the registers or coils per Modbus request, 1 to 125 each.

A device that is only read. WRITE to its parameters fails to compile.

A device written with the single-coil and single-register write functions.

A device written with the multiple-coil and multiple-register write functions, at most write per request.

A device written with either the single or the multiple write functions.

The controller’s own virtual Modbus device: the same as MBWRANY * 100 100. Use it to read and write the MC252’s own registers, and to log its registers.

A parameter: a value of a given type at a source, which READ reads into a variable and WRITE writes. The source is a Modbus device defined earlier or a memory source. A device parameter takes a table and an address; for a memory parameter they are optional and map it to the controller’s own registers (see Tables and addresses).

DEF flow F32EP2R meter H 20 ; float register pair, as hundredths
DEF counter UINT32 MEMBAT ; battery-backed, not visible over Modbus
DEF mode UINT16 MEMTEMP H 5000 ; RAM, readable as the controller's register 5000

Values are converted between the type and the 64-bit variable on each read and write. A value that does not convert raises EXC_TYPE_UNKNOWN. A memory parameter that was never written reads as unknown; a device parameter reads the device’s register.

Byte orders: big-endian (BE, or no suffix) puts the most significant byte first; BLE reverses all bytes; WLE puts the least significant 16-bit word first and keeps each word big-endian. For example, 66051 (0x00010203) as INT32 is 00 01 02 03, as INT32BLE 03 02 01 00, as INT32WLE 02 03 00 01.

One bit, 0 or 1: a coil (C) or a discrete input (D). BIT takes only these tables, and the other types only H and I. One byte in a memory source.

Written like DEF name INT16 source table address.

TypeBytesRegistersRangeByte order
UINT8110 to 255—
INT811−128 to 127—
UINT16210 to 65535BE
UINT16BLE210 to 65535BLE
INT1621−32768 to 32767BE
INT16BLE21−32768 to 32767BLE
UINT32, UINT32BLE, UINT32WLE420 to 4294967295BE, BLE, WLE
INT32 (INT32BE), INT32BLE, INT32WLE42−2147483648 to 2147483647BE, BLE, WLE
INT64, INT64BLE, INT64WLE8464-bit signedBE, BLE, WLE

INT32BE is the same as INT32.

Written like DEF name F32EP1R source table address. IEEE 754 single precision, 4 bytes, two registers: F32EPnR big-endian, F32BLEEPnR with all bytes reversed, F32WLEEPnR with the words swapped. n is 0 to 3: the variable holds the value multiplied by 10ⁿ, so F32EP2R reads 12.34 as 1234 and writes 1234 as 12.34. See Fixed-point values.

Written like DEF name F64EP1R source table address. IEEE 754 double precision, 8 bytes, four registers: F64EPnR, F64BLEEPnR and F64WLEEPnR, with n from 0 to 6, the multiplier as for single precision.

Memory parameters keep values in the controller between runs, or share them between programs. The limits apply to all programs on the device together; a parameter that does not fit fails to compile. A parameter takes the bytes of its type: 1, 2, 4 or 8. Reads and writes of memory parameters do not wait for @PARAMTIMEOUT or @PARAMLOADRATIO.

RAM: 2048 bytes, fast, lost when the controller restarts or loses power.

Memory powered by the clock battery: 64 bytes, kept through power loss.

A file on the memory card: up to 65535 bytes, slower, needs the memory card with the programs. A write that fails raises EXC_IO. MEMFILE parameters do not share storage between programs.

The controller’s settings area: 800 bytes, kept through restarts, read-only for programs. WRITE to a MEMFLASH parameter fails to compile.

TableModbus dataTypesWRITE to a device
CcoilsBITyes
Ddiscrete inputsBITno
Hholding registersall but BITyes
Iinput registersall but BITno

address is the zero-based address of the first coil or register: a fixed number from 0 that leaves room for all the type’s registers within 65535, or a variable plus an offset 0 to 65535 (base+4), read at run time. WRITE needs table C or H on a device that allows writes, or a memory source other than MEMFLASH.

A memory parameter with a table and address is also the controller’s own register or coil at that address, readable by HMI and other Modbus clients. Memory parameters of the same source, table, address and size share storage, also across programs: one program writes the value and the others read it. A second program that writes it fails to compile, and the device skips that file. Mapped memory parameters that overlap without matching exactly fail to compile.

Each run starts at the run label, or at the first action without one, and performs actions in order until EXIT. Assignments (PUT) store a result, checks (IF) skip the next action, and commands do the rest.

Stores a result in target, a variable or condition, or an array item: PUT target, a function and its operands. The function’s result has the target’s kind. Without a function, the item after the target is copied into it (VAL): PUT copy original, PUT limit 250, PUT flag TRUE. A target not defined yet is defined as the function’s kind. With @SYNTAX 2, PUT may be left out.

Performs the next action only when the condition is TRUE; FALSE and unknown skip it. condition is a condition name or array item, TRUE, FALSE, or a function with a condition result (IF GR t limit). A function with a variable result fails to compile. An IF covers one action: use GO to skip more.

Two IFs in a row do not mean “and”. When the first condition is not TRUE, it skips the second IF, and the action after the second one runs. HMI warns about an IF whose next action is another IF. To require both conditions, use IF AND, with each condition stored in a condition name first if needed (PUT warm GR t limit).

Two labels with a fixed meaning. run marks the first action of each run; without it, runs start at the file’s first action. onerror marks the program’s error handler: an error that no TRYCALL handler catches jumps there, with the error code in LASTERROR. These names cannot name other items.

An error interrupts the function it happens in and jumps to that function’s handler. With no handler, or when the handler itself fails, the error goes to the caller’s handler, and at the top to onerror. An error with no handler is unhandled: the device writes Unhandled error #<code> at line <line>: <name> to its log (while device-side logging is on) and ends the run with that error. The line is the program line of the action that failed. See Debug programs on an MC252.

Ends the run. error is OK for a normal end, an error name, an integer error code, or LASTERROR; another variable fails to compile. The task reports a code other than OK as its last error.

Runs the actions from label until RETURN, then continues after the CALL. Calls can nest; the depth is limited by the number of RETURN actions in the file, and a deeper call raises EXC_STACK_OVERFLOW.

Ends the function started by the last CALL or TRYCALL and continues after it. Without one it raises EXC_STACK_UNDERFLOW.

Writes a variable or an integer to the parameter, converted to its type. The parameter is in table C or H of a device that allows writes, or in a memory source other than MEMFLASH. An unknown value raises EXC_UNKNOWN; a device that fails raises its error.

Continues at label. With IF, it makes branches and loops; bound every loop so that a run ends within @UPDATE.

Writes the string to the device log (/LOGS/SYS.LOG on the memory card). It writes only while the device’s task logging is on, in HMI the endpoint’s device-side logging (Device log); otherwise it does nothing.

Sends text as an SMS to the number addressee produces, both strings (*PHONE(0)* gives a number from the settings). An addressee with nothing but 0 digits sends nothing. A failed send raises EXC_IO.

Like CALL, with its own error handler: an error in the function jumps to the label handler, with the error code in LASTERROR.

Writes the parameter’s value to the device’s data log, from which HMI records readings (Record readings on an MC252). The log identifies the value by its Modbus address, so the parameter needs a table and address. Log a device parameter, using an MBSELF device for the controller’s own registers: logging a mapped memory parameter compiles, but the write fails and stops all program logging until the device restarts or reloads its programs. Nothing is written while the device’s task log format setting is off.

Like PARAMLOGNOCOMMENT, with the string comment stored with the value.

Raises an error: an error name, an integer error code, or LASTERROR to pass a handled error on to the caller’s handler. RAISE OK and RAISE 0 fail to compile.

Functions compute the result of a PUT, and those with a condition result also the check of an IF. A function with an unknown operand usually gives an unknown result (see Unknown values). Where a function takes variable and value, the first is a variable (not an integer) and the second a variable or an integer.

The sum, variable + value.

The difference, variable - value.

The product, variable * value.

The integer quotient, variable / value, with the fractional part dropped. Division by zero raises EXC_RESULT_INFINITY.

The remainder, variable - (variable / value * value); it has the sign of variable. A zero value raises EXC_RESULT_INFINITY.

The integer square root, rounded down. A negative value raises EXC_RESULT_COMPLEX; a negative integer fails to compile.

Bitwise AND of the two values.

Bitwise OR of the two values.

The value with every bit inverted.

variable shifted right by value bits, keeping the sign (arithmetic shift).

variable shifted left by value bits.

Bit number bit of variable, 0 or 1, counted from 0 for the least significant bit: the same as SHR by bit followed by BITSAND with 1.

Each also works as PUT target and the same operands, storing the result in a condition.

TRUE when variable = value.

TRUE when variable ≠ value.

TRUE when variable ≥ value.

TRUE when variable < value.

TRUE when variable > value.

TRUE when variable ≤ value.

These take condition names or array items with an integer index, not TRUE or FALSE, and also work as PUT target.

TRUE when both are TRUE. FALSE when either is FALSE, even if the other is unknown.

The inverse of AND: FALSE when both are TRUE.

TRUE when either is TRUE, even if the other is unknown.

The inverse of OR: TRUE when both are FALSE.

The inverse of the condition; unknown stays unknown. It takes a condition name or array item, including one with a variable index, but not TRUE or FALSE. Also works as PUT target.

A copy of item: a variable, an integer, a condition, TRUE or FALSE, or an array item. A variable index works on one side of the copy. The kinds of target and item match. VAL may be left out (PUT copy original) unless @SYNTAX 0. In an IF, the item is a condition.

Reads the parameter and converts its value to a variable. A device parameter is read with a Modbus request, subject to @PARAMTIMEOUT and @PARAMLOADRATIO; a failed read raises the device’s error. A memory parameter that was never written reads as unknown.

These take an array of variables defined with VARS and at least two items.

The largest item.

The index of the largest item, from 0 to the array size minus 1.

The smallest item.

The index of the smallest item, from 0 to the array size minus 1.

The sum of the items.

The item of array at the position of the first TRUE in selectors, an array of conditions of the same size. Items after the first TRUE do not matter, even unknown ones.

error is an error name or an integer code.

The numeric code of the error, for example PUT code ERR EXC_IO.

TRUE when the variable holds the error’s code: IF ERREQ LASTERROR EXC_PARAM_TARGET_FAILED. Also works as PUT target.

TRUE when the variable does not hold the error’s code. Also works as PUT target.

TRUE when the variable or condition item has a value, never unknown. The item is defined or used earlier in the file. Also works as PUT target.

TRUE when item is unknown. Use it to give a default to a memory parameter that was never written. Also works as PUT target.

TRUE when a new SMS came from a number starting with the string sender and its text starts with the string text. EMPTYSTRING as sender matches any number. Also works as PUT target.

The inverse of SMSRCVD. Also works as PUT target.

These take no operands and cannot be used in an IF.

The run interval in seconds.

The run interval in milliseconds.

The first integer in the program’s file name: 3 for PUMP3.TXT. Use it as a base for addresses so that copies of one program under different names use different registers. A file name without a digit fails to compile.

The controller’s real-time clock, local time with daylight saving time. No operands; not in an IF.

The clock in seconds since the start of the base year, usually 2000.

The year.

The month, 1 to 12.

The day of the month, 1 to 31.

The hour, 0 to 23.

The minutes, 0 to 59.

The seconds, 0 to 59.

The day of the week, 1 (Monday) to 7 (Sunday).

Seconds since midnight, 0 to 86399.

Today’s sunrise in seconds since midnight; -1 during polar day, 86400 during polar night.

Today’s sunset in seconds since midnight; -1 during polar day, 86400 during polar night.

No operands; not in an IF.

The supply voltage in millivolts.

The controller’s temperature in degrees.

Variables are integers. Fractions are kept as integers with a fixed multiplier, such as tenths: the EPnR floating-point types apply one when they read and write, and many devices report scaled integers. Addition and subtraction keep the multiplier; multiplication multiplies the multipliers, division divides them, and a square root needs a multiplier with an even number of zeros.

A variable or condition is unknown before it is first assigned, after a read of a memory parameter that was never written, after a failed assignment, and at the start of each run with @RESETDATA 1. Most functions with an unknown operand give an unknown result; AND, OR and SELECTBY give a result when the known operands decide it. IF treats unknown as FALSE: choose IF GR or its inverse IF LE so that the skipped branch is the safe one, and guard with ISKNOWN.

Where an action needs a number, unknown is an error: WRITE and EXIT of an unknown variable and an array item with an unknown index raise EXC_UNKNOWN.

A predefined variable holding the code of the last error. Handlers check it with IF ERREQ LASTERROR EXC_IO, strings print it with *ERR(lasterror)*, and EXIT LASTERROR or RAISE LASTERROR pass it on. RAISE sets it; programs do not assign it with PUT. EXIT and RAISE take it, but no other variable.

LASTERROR, ERR, the codes EXIT and RAISE take, a task’s last error and the Unhandled error #<code> log line use these codes. Names can be written wherever an error is expected. These are run-time errors; compile errors have their own codes, which the program editor explains on each problem.

CodeNameRaised when
0OKNo error
1EXC_MB_ILLEGAL_FUNCTIONThe Modbus device answered with exception 1
2EXC_MB_ILLEGAL_DATA_ADDRESSThe Modbus device answered with exception 2
3EXC_MB_ILLEGAL_DATA_VALUEThe Modbus device answered with exception 3
4EXC_MB_SLAVE_DEVICE_FAILUREThe Modbus device answered with exception 4
5EXC_MB_ACKNOWLEDGEThe Modbus device answered with exception 5
6EXC_MB_SLAVE_BUSYThe Modbus device answered with exception 6
8EXC_MB_MEMORY_PARITY_ERRORThe Modbus device answered with exception 8
10EXC_PARAM_PATH_UNAVAILABLEThe controller has no path to the device (gateway exception 10)
11EXC_PARAM_TARGET_FAILEDThe device did not answer within @PARAMTIMEOUT (gateway exception 11)
60EXC_TYPE_UNKNOWNA parameter value could not be converted to or from its type
61EXC_ACTION_UNKNOWNThe action is unknown to the firmware
62EXC_IOSending an SMS, writing a MEMFILE parameter, or reading the task’s compiled file failed
63EXC_OUT_OF_MEMORYThe controller ran out of memory
64EXC_STACK_OVERFLOWCALL or TRYCALL nested too deep
65EXC_STACK_UNDERFLOWRETURN without a CALL
66EXC_RESULT_INFINITYDivision by zero
67EXC_RESULT_COMPLEXSquare root of a negative value
68EXC_OUT_OF_BOUNDSAn array index outside the array
69, 70, 79EXC_UNKNOWNThe task or a parameter was lost while running, or a value was unknown where a number is needed

Any other code also shows as EXC_UNKNOWN. A device that does not answer raises EXC_PARAM_TARGET_FAILED, not EXC_IO.