Word тип данных codesys
Разработка под ПЛК: Beckhoff CX series, SE Modicon M221, WAGO 750 series.
Среды разработки: TwinCAT 3, EcoStruxure Machine Expert-Basic, CODESYS V2.3.
Основная часть опыта приходится на ST+TwinCAT 3, который базируется на CODESYS и IEC 61131.
Статью решил написать так как покидаю OT и перехожу в мир IT. Хочется поделится опытом, чтобы эти 3 года не прошли даром.
Среда разработки
Если часто приходиться комментировать части кода - то узнайте какое сочетание клавиш позволит вам это сделать, это сэкономит много времени. В TwinCAT XAE Shell для комментирования выделенного кода: Ctrl+K+C и Ctrl+K+U для расскомментирования.
Structured Text
STRING vs WSTRING
В TwinCAT 3 есть возможность использовать Unicode строки. Они могут пригодиться, если необходимо передовать специфические символы, но без необходимости лучше не использовать WSTRING.
Size of character
Date and time
Почти в любом проекте необходимо знать точное время, вычислять временные интервалы. Часто работа с временем и датами доставляет много проблем и боли. Для себя я нашёл решение, уверен, оно упростит многим жизнь.
Эта функция может быть использована для считывания метки времени операционной системы. Временная метка представляет собой 64-разрядное целое значение с точностью до 100 нс. Помимо прочего, его можно использовать для синхронизации задач или измерения времени. Одна единица соответствует 100 нс. Время представляет собой количество интервалов в 100 нс с 1 января 1601 года.
Хранятся отметки в переменных типа ULINT. Зная всё это мы можем без труда рассчитывать интервалы времени с точностью до 100нс! Нужно просто найти разность между отметками.
К сожалению, стандартных функций для преобразования отметки в тип DATETYPE я не нашёл, поэтому пришлось реализовать такую функцию самостоятельно:
Как видно из кода, сложность заключалась в расчёте интервала между начальным отсчётом системного времени ПЛК и типа DATETIME.
Функция для получения текущей даты/времени в формате DATETIME
Числовые константы
Большинство документаций по обмену по промышленным протоколам содержит шестнадцатиричные адреса регистров, номера функций, обозначения комманд и т.д. Для битовых операций необходимо представлять числа в двоичном виде. Чтобы эффективно решать задачи, где приходиться отходить от десятичной системы счисления необходимо знать о возможности задания константных чисел заданного типа в заданной системе счисления.
В общем виде задание числовой константы выглядит так:
Типом этих числовых значений может быть BYTE, WORD, DWORD, SINT, USINT, INT, UINT, DINT, UDINT, REAL или LREAL.
ANY type
В языках программирования со статической типизацией довольно сложно делать универсальные функции/функциональные блоки. Когда мне поставили задачу собирать и анализировать различные данные, я решил, что копировать функциональные блоки и изменять в них только тип входного значения - не лучший вариант. Тогда появилась идея приводить все типы к одному и по объективным причинам это тип LREAL.
При реализации функции или метода вы можете объявлять входные данные (VAR_INPUT) как переменные с типом данных ANY. Далее вы можете получить указатель на значение, тип данных и размер переданной на этот вход переменной.
Структура типа данных ANY
Кроме типа ANY существуют также дочерние типы:
Дерево наследования типов
Хочу обратить внимание что на вход типа ANY не может быть подана константа, поэтому в некоторых случаях придётся создавать дополнительную переменную.
Зная про этот тип мне удалось реализовать функцию, которая приводила данные разных типов к LREAL.
Функция по преобразованию числовых типов в LREAL
REFERENCE
Все знают про указатели (POINTER) и связанные с ними проблемы, так вот многие из них можно избежать, если использовать ссылки(REFERENCE):
Ссылки проще в использовании: ссылку не нужно разыменовывать (с помощью ^), чтобы получить доступ к содержимому объекта, на который ссылается ссылка.
Более чистый синтаксис для передачи значений: Если вход является ссылкой, то нет необходимости писать ADDR(value).
В отличие от указателей, для ссылок компилятор проверяет типы данных при передаче значений.
Стоит отметить, что не всегда ссылкой можно заменить указатель, но когда это возможно, то сделайте это.
Pragmas
Инструкции pragma влияют на свойства переменных, относящихся к процессу компиляции или предкомпиляции. Не поленитесь просмотреть возможности каждого типа pragmas - обязательно найдёте что-то полезное для своего проекта.
Union
Union - тип структуры, который позволяет представлять значение в разных типах данных. Данная структура полезна при отладке кода а также при обработке входных значений.
В случае, если нужно обращаться к битам, то это можно сделать через точку. Но у этого способа я вижу огромный недостаток: нет возможности итерироваться по битам. Если нужно разобрать переменную на байты или по 16-бит или другим сложным образом, то вместо написания сложных функций попробуйте сначала сделать это с помощью Union.
SEL, MIN, MAX, LIMIT
Многим программистам ПЛК часто не хватает синтаксического сахара, которого много в других языках программирования. На примере функции SEL хочется показать, что возможно этот "сахар" в виде тернарного оператора не особо нужен.
Если вам нужно выбрать значение в зависимости от условия, выможете сделать это в одну строку:
Если вам нужно ограничить значение сверху и/или снизу, это также можно сделать в одну строку:
Многие функции и операторы, которых нам не хватает уже написаны - нужно только поискать.
Заключение
В статье описано,то на что лично мне захотелось обратить внимание (ООП решил не трогать). Буду рад если мой опыт принесёт кому-то пользу. Попрошу при использовании предоставленных функций оставлять продолжать version history.
Делитесь своим опытом в комментариях. Чтобы быть в курсе событий и общаться с коллегами предлагаю перейти по ссылкам: тг-канал proPLC, тг-чат proPLC.
Тип данных WORD
Здравствуйте.
Хотелось бы использовать тип данных WORD для управления множеством выходов, поскольку для массового изменения очень подходит битовые операции. Но не могу понять как грамотно привязвыать выходы к такой переменной. Получаются совсем уж нелепые конструкции.
Для чего этот тип данных используется на практике, в реальной работе?
Тип данных WORD
egjar писал(а): ↑ 22 мар 2021, 22:39 Для чего этот тип данных используется на практике, в реальной работе?
Тип Word - это целочисленный беззнаковый тип данных, в два байта. Диапазон 0-65535. Используется везде, где оказывается нужным.
Где конкретно, в какой среде, с каким ПЛК, по какому протоколу Вы работете с выходами?
Тип данных WORD
egjar писал(а): ↑ 22 мар 2021, 22:39 Для чего этот тип данных используется на практике, в реальной работе?
Вот для упаковки-распаковки битовых переменных и используется в основном.
И, например, в Step7 тип Word интерпретируется как массив бит.
А как использовать. по разному в различных системах например Var_Bool0:=Var_Word.0, где-то операторы есть Pack- UnPack, а в софте для программирования есть кнопка "HELP", если что не понятно жмем и ищем-читаем там.
Тип данных WORD
stesl писал(а): ↑ 23 мар 2021, 10:37 Тип Word - это целочисленный беззнаковый тип данных, в два байта. Диапазон 0-65535. Используется везде, где оказывается нужным.
Не путайте Word с UInt (unsigned integer16), он не относится к целочисленным, так как не кодирует числовые значения и не совместим с математическими операциями.
Потому что:
Sergy6661 писал(а): ↑ 23 мар 2021, 12:54 Вот для упаковки-распаковки битовых переменных и используется в основном.
Но не в основном, а только для этого. Если конечно в конкретном ПЛК не срабатывает неявное преобразование, из-за которого кажется, что Word - это целое число.
Это разные типы данных, хотя все они 16 бит.
Тип данных WORD
Михайло писал(а): ↑ 23 мар 2021, 21:52 Не путайте Word с UInt (unsigned integer16), он не относится к целочисленным, так как не кодирует числовые значения и не совместим с математическими операциями.
Ну, допустим, в CoDeSys WORD по большему счету как UINT16, но в CoDeSys можно по биту к любому целочисленному обращаться.
В общем все от системы разработки зависит и опять же кнопка "HELP" рулит.
Тип данных WORD
Михайло писал(а): ↑ 23 мар 2021, 21:52 Не путайте Word с UInt (unsigned integer16), он не относится к целочисленным, так как не кодирует числовые значения и не совместим с математическими операциями.
Тип данных WORD
Почему именно беззнаковое? Значения в диапазоне -32767. 32767 в какие-то другие типы укладывается?
[+] В начале было слово.
И слово было - два байта.
CODESYS V3 supports all IEC-61131-3 operators. These operators are recognized implicitly throughout the project. In addition to these IEC operators, CODESYS also supports some non-IEC 61131-3 operators.
Operators are used in blocks, such as functions.
For information about the processing order (binding strength) of the ST operators, please refer to the section on ST expressions.
For operations with floating-point data types, the computational result depends on the applied target system hardware.
For operations with overflow or underflow in the data type, the computational result depends on the applied target system hardware.
Overflow/underflow in the data type¶
The CODESYS compiler generates code for the target device and computes temporary results always with the native size that is defined by the target device. For example, computation is performed at least with 32-bit temporary values on x86 and ARM systems and always with 64-bit temporary values on x64 systems. This provides considerable advantages in the computation speed and often also produces the desired result. But this also means that an overflow or underflow in the data type is not truncated in some cases.
Example 1
The result of this addition is not truncated and the result in dwVar is 65536 .
Example 2
The overflow and underflow in the data type is not truncated and the results ( bVar1, bVar2 ) of both comparisons are FALSE on 32-bit and 64-bit hardware.
Example 3
By the assignment to wVar3 , the value is truncated to the target data type WORD and the result bvar1 is TRUE .
Example 4
In order to force the compiler to truncate the temporary results, a conversion can be inserted.
The type conversion makes sure that both comparisons are 16-bit only and the results ( bVar1, bVar2 ) of both comparisons are each TRUE .
Arithmetic operators¶
Bitstring operators¶
Bitshift operators¶
Selection operators¶
Comparison operators¶
A comparison operator is a Boolean that compares two inputs (first and second operand).
Address operators¶
Call operators¶
Type conversion operators¶
You can explicitly call type conversion operators. The type conversion operators described below are available for typed conversions from one elementary type to another elementary type, as well as for overloading. Conversions from a larger type to a smaller type are also implicitly possible (for example, from INT to BYTE or from DINT to WORD ).
Overloaded conversion: TO_
Elementary data types:
The keywords T , TIME_OF_DAY and DATE_AND_TIME are alternative forms for the data types TIME , TOD , and DT . T , TIME_OF_DAY and DATE_AND_TIME are not represented as a type conversion command.
If the operand value for a type conversion operator is outside of the value range of the target data type, then the result output depends on the processor type and is therefore undefined. This is the case, for example, when a negative operand value is converted from LREAL to the target data type UINT .
Information can be lost when converting from larger data types to smaller data types.
String manipulation when converting to STRING or WSTRING
When converting the type to STRING or WSTRING , the typed value is left-aligned as a character string and truncated if it is too long. Therefore, declare the return variable for the type conversion operators <>_TO_STRING and <>_TO_WSTRING long enough that the character string has enough space without any manipulation.
ST (Structured Text) – это текстовый язык высокого уровня общего назначения, по синтаксису схожий с языком Pascal. Удобен для программ, включающих числовой анализ или сложные алгоритмы. Может использоваться в программах, в теле функции или функционального блока, а также для описания действия и перехода внутри элементов SFC. Согласно IEC 61131-3 ключевые слова должны быть введены в символах верхнего регистра. Пробелы и метки табуляции не влияют на синтаксис, они могут использоваться везде.
Выражения в ST выглядят точно также, как и в языке Pascal:
Порядок их выполнения – справа налево. Выражения состоят из операндов и операторов. Операндом является литерал, переменная, структурированная переменная, компонент структурированной переменной, обращение к функции или прямой адрес.
Типы данных¶
Согласно стандарту IEC 61131-3, язык ST поддерживает весь необходимый набор типов, аналогичный классическим языкам программирования. Целочисленные типы: SINT (char), USINT (unsigned char), INT (short int), UINT (unsigned int), DINT (long), UDINT (unsigned long), LINT (64 бит целое), ULINT (64 бит целое без знака). Действительные типы: REAL (float), LREAL (double). Специальные типы BYTE, WORD, DWORD, LWORD представляют собой битовые строки длиной 8, 16, 32 и 64 бит соответственно. Битовых полей в ST нет. К битовым строкам можно непосредственно обращаться побитно. Например:
a.3 := 1; (* Установить бит 3 переменной a *)
Логический тип BOOL может иметь значение TRUE или FALSE. Физически переменная типа BOOL может соответствовать одному биту. Строка STRING является именно строкой, а не массивом. Есть возможность сравнивать и копировать строки стандартными операторами. Например:
Для работы со строками есть стандартный набор функций (см. приложение 2, раздел «Строковые операции с переменными типа STRING»).
Специальные типы в стандарте IEC определены для длительности (TIME), времени суток (TOD), календарной даты (DATE) и момента времени (DT).
В таблице 3.1 приведены значения по умолчанию, соответствующие описанным выше типам.
Таблица 3.1 – Значения по умолчанию для типов данных IEC 61131-3
По умолчанию, все переменные инициализируются нулем. Иное значение переменной можно указать явно при ее объявлении. Например:
str1: STRING := ‘Hello world’;
В определённых ситуациях при разработке программных модулей удобно использовать обобщения типов, т.е. общее именование группы типов данных. Данные обобщения приведены в таблице 3.2.
Случается программировать контроллеры (ПЛК) в среде CODESYS. Все, кто имел дело с этой системой, знают, что в любом проекте присутствует библиотека Standard.lib, в которой реализованы базовые таймеры, триггеры, счетчики и некоторое кол-во других функций и функциональных блоков. Многие из этих блоков постоянно используются в программах для ПЛК. А сама библиотека, как и языки программирования CODESYS, является воплощением стандарта IEC 61131-3, т.е. призвана помочь при программировании классических ПЛК задач.
Одна из особенностей программ для ПЛК в том, что основной цикл программы должен выполняться без существенных задержек, в нем не должно быть внутренних циклов с неопределенным временем выхода или синхронных вызовов «задумчивых» функций, особенно это касается коммуникаций по медленным каналам. Обновление входных и выходным образов процесса происходит только на границе основного цикла, и чем дольше мы будем «сидеть» внутри одной итерации цикла, тем меньше мы будет знать о реальном состоянии объекта управления, в конечном итоге сработает watchdog переполнения времени выполнения цикла. Многие могут мне возразить, сказав, что современные ПЛК многозначны, есть с поддержкой аппаратных прерываний. Согласен, но разговор о таких системах не входит в мои планы, я же хочу поговорить о (квази, псевдо — выбирайте) ПЛК однозадачной реализации (без прерываний) на базе микропроцессорной платформы Arduino, в котором есть только один основной цикл. Кстати, не лишним будет сказать, что на написание данной заметки меня сподвигла статья Ардуино-совместимый ПЛК CONTROLLINO, часть 1 о попытке аппаратного воплощения Arduino в пром. ПЛК.
Несколько слов об Arduino. С точки зрения программиста ПЛК, Arduino — это типичный контроллер с одним очень быстрым или, наоборот, очень медленным циклом loop(). На время выполнения цикла не накладывается никаких ограничений, и он может отработать и один, и бесконечное кол-во раз — по замыслу программиста. Когда программа проста и сводится к выполнению последовательных операций, регуляторов, без параллельных событий, то достаточно чередовать операции бесконечными вложенными циклами проверки условий и синхронными задержками типа delay(). Последовательные шаги такой программы будут выполняться буквально построчно, просто и логично. Но, как только возникает необходимость в программировании параллельных операций, необходимо менять парадигму программы.
В однозадачной системе добиться видимой параллельности можно только очень быстрым последовательным сканированием параллельных состояний, не задерживаясь подолгу на каждом вызове функции или проверке условия. С физическими входами-выходами проблем нет, функции отрабатывают достаточно быстро, а вот delay() становится неоправданным тормозом. И вот тут на смену приходят неблокирующие таймеры, те самые, которые в программировании ПЛК являются классикой. Суть в том, что для их работы используется миллисекундный счетчик времени, и все действия привязаны к значениям этого глобального счетчика.
А теперь давайте вспомним ту самую Standard.lib из CODESYS. В ней как раз реализованы МЭК-овские неблокирующие таймеры. Я взял ее за основу и портировал функции таймеров и триггеров в библиотечный код Arduino (С++). Т.е. попытался приблизить Arduino к классическому ПЛК.
Ниже я приведу краткое описание портированных функциональных блоков (FB) CODESYS и их аналоги в моей библиотеке plcStandardLib, все временные диаграммы верны для новой библиотеки Arduino. Подробнее описание исходных блоков можно посмотреть, например, в русскоязычной справке по CODESYS.
TON — функциональный блок «таймер с задержкой включения»
В Arduino IDE:
Временная диаграмма работы TON:
TOF — функциональный блок «таймер с задержкой выключения»
В Arduino IDE:
Очень похоже на TON, для краткости:
Временная диаграмма работы TOF:
TP — функциональный блок «импульс-таймер»
В Arduino IDE:
Очень похоже на TON, для краткости:
Временная диаграмма работы TP:
R_TRIG — функциональный блок «дeтектор фронта»
Функциональный блок R_TRIG генерирует импульс по переднему фронту входного сигнала. Выход Q равен FALSE до тех пор, пока вход CLK равен FALSE. Как только CLK получает значение TRUE, Q устанавливается в TRUE. При следующем вызове функционального блока выход сбрасывается в FALSE. Таким образом, блок выдает единичный импульс при каждом переходе CLK из FALSE в TRUE.
Пример CODEDESYS на языке ST:
В Arduino IDE:
F_TRIG — функциональный блок «дeтектор спада»
Функциональный блок F_TRIG генерирует импульс по заднему фронту входного сигнала.
Выход Q равен FALSE до тех пор, пока вход CLK равен TRUE. Как только CLK получает значение FALSE, Q устанавливается в TRUE. При следующем вызове функционального блока выход сбрасывается в FALSE. Таким образом, блок выдает единичный импульс при каждом переходе CLK из TRUE в FALSE.
В Arduino IDE:
RS_TRIG — функциональный блок RS-триггер / SR_TRIG — функциональный блок SR-триггер
Переключатель с доминантой выключения, RS-триггер:
Переключатель с доминантой включения:
Читайте также: