Simatic это абревиатура семейств PLC фирмы Siemens для общепромышленного применения (SIMATIC S7-300/S7-400/C7/WinAC). Сейчас есть и более новые SIMATIC S7-1200/S7-1500, программируются через TIA Portal.
Siemens выпускает и узко специализированные линейки PLC (Sinumerik — для станков ЧПУ, Simadyn — линейка повышенной производительности, многие задачи решаются аппаратно, специализированными блоками). Так же широко распостранены абревиатуры, которые относятся к области применения, а не к линейке аппаратного обеспечения на котором оно собрано, естественно оно должно поддерживать стандарты фирмы Siemens (SIMATIC HMI — управление оборудованием с панели оператора, SIMATIС NET — все что связано с межблоковой связью, SIMOTION — моторизованные приводы, управляющие движением, SIMODRIVE — инверторы, управляемые через ProfiBus, и еще куча абревиатур на которые Siemens имеет товарные знаки).
Step 7 это IDE для программирования всего этого хозяйства (кроме устаревшего S7-200, для него используется STEP 7-Micro/WIN, несмотря на схожее название, это отдельная программа и в IDE Step 7 не интегрируется). Составить представление можно почитав статью на Хабре Программирование ПЛК Siemens на Simatic Step7. Дополнительные языки программирования, драйвера оборудования и т.д. интегрируются в Step 7. Доступны драйверы для широкой номенклатуры стороннего оборудования (не Siemens).
Инструментальные средства STEP 7 позволяют выполнять:
- Конфигурирование и определение параметров настройки аппаратуры;
- Конфигурирование систем промышленной связи и настройку параметров передачи данных;
- Программирование, тестирование, отладку и запуск программ отдельных систем автоматизации, а также их локальное или дистанционное обслуживание;
- Документирование и архивирование данных проекта;
- Функции оперативного управления и диагностирования аппаратуры.
STL — один из МЭК (IEC) стандарта IEC61131-3 языков программирования (англ. Statement List, список операторов). Немцы зовут его AWL (нем. Anweisungsliste), это же расширение имеют и исходники, написанные на STL. Тут есть несоответствие в абревиатурах стандартных языков МЭК и фирмы Siemens. Дело в том, что по стандартам МЭК язык STL должен называться IL (Instruction List), а абревиатура ST (Structured Text) зарезервирована за Pascal-подобным языком, который у Siemens называется SCL (Structured Control Language).
Кроме STL, Step 7 включает в дистрибутив поддержку МЭК языков LAD (Ladder Diagram, язык релейной (лестничной) логики) и FBD (Function Block Diagram, программирование функциональными блоками). При приобретении лицензии интегрируются языки SCL (Pascal-подобный язык), S7-GRAPH (позволяет выполнять конфигурирование и программирование систем графическими способами, стандарт DIN EN 6.1131-3), S7-HiGraph (позволяет разрабатывать программы систем автоматизации SIMATIC в виде графа состояния системы), S7-PDIAG (позволяет разрабатывать однородные процедуры диагностирования систем автоматизации SIMATIC), S7-PLCSIM (позволяет эмулировать работу систем автоматизации SIMATIC, предназначен для отладки программ указанных систем на программаторе/компьютере без использования реальных технических средств автоматизации).
В настоящее время Siemens активно рекомендует переходить со Step 7 на TIA Portal. Это логическое развитие Step 7, но не всегда однозначное (IMXO, что-то теряем, что-то находим…).
Представленный функциональный блок выполняет функции ограничителя аналогового сигнала (4..20mA) с индикацией выхода за диапазон (Limiter) и его сглаживания по алгоритму простого (арифметического) скользящего среднего (SMA).
Алгоритмов скользящего среднего несколько, SMA (простой, Simple Moving Average), EMA (экспоненциальный, Exponential Moving Average), WMA (взвешенный, Weighted Moving Average). Последние еще и разновидности имеют. Здесь рассмотрен только первый.
Код функционального блока был написан для контроллера семейства Simatic S7-300, конкретно для S7-313C.
Как правило (за редким исключением, S7-313C как раз из них), входные аналоговые модули S7-300 имеют универсальные входы. У ранних ревизий переключателем на боковой стенке модуля можно перевести вход в режим работы с сигналами напряжения, тока, термометров сопротивления и резисторов, термопар (4 положения). Аналоговые модули не имеющие переключателя (новые ревизии), конфигурируются утилитой Hardware Configuration, входящей в состав пакета STEP7.
Здесь рассмотрена работа с аналоговым входом, настроенным на измерение тока 4-20mA. Он преобразует входной ток в слово (16-разрядное HEX число).
У различных модулей аналоговых входов Simatic разрешающая способность может быть от 9 до 15 бит + знак. Если разрешающая способность аналогового модуля составляет менее 16 бит, то аналоговая величина сохраняется в модуле с выравниванием влево. Младшие, не используемые, битовые разряды заполняются нулями.
Из таблицы видно, что модуль с состоянии работать с входным током в диапазоне 1,185mA — 22,81mA. Ток не входящий в данный диапазон вызывает переполнение и показания являются недействительными. Нередкие в промышленности отказ датчика или обрыв провода приведут к выходу измеряемого тока из диапазона работы аналогового входа.
Поэтому перед любой обработкой полученных данных от аналогового входа необходимо их нормализовать, т.е. отсечь недействительные значения. Один из вариантов такой функции на языке STL:
FUNCTION FC20: VOID
TITLE = Ограничитель аналового сигнала 4-20mA
AUTHOR: Anakost
FAMILY: SOHO
NAME: LIMITER
VERSION: 1.0
VAR_INPUT
INPUT: INT; // входной ток
END_VAR
VAR_OUTPUT
OUTPUT: INT; // выходной ток
RANGE: BOOL; // выход за диапазон
END_VAR
BEGIN
NETWORK
TITLE = Ограничение аналогового сигнала
L #INPUT; // ACCU 1 <- INPUT, входной ток
L W#16#6C00; // ACCU 1 <- константа 20mA, ACCU 2 <- ACCU 1
>I; // в RLO результат сравнения ACCU 2 > ACCU 1
= #RANGE; // RANGE <- RLO
JC A00; // в ACCU 1 верхняя граница диапазона
L #INPUT; // ACCU 1 <- INPUT, входной ток
L W#16#0; // константа 4mA
<I; // в RLO результат сравнения ACCU 2 < ACCU 1
= #RANGE; // RANGE <- RLO
JC A00; // в ACCU 1 нижняя граница диапазона
L #INPUT; // ACCU 1 <- INPUT, входной ток
A00:
T #OUTPUT; // OUTPUT <- ACCU 1, результат на выход
END_FUNCTION
Небольшое обьяснение к коду для тех, кто незнаком с промышленными контроллерами Siemens. Simatic S7-300 имеет два 32-х разрядных аккумулятора. При загрузке в первый, его предыдущее содержимое сдвигается во второй. Поэтому применение операции сравнения или математической операции требует двух предварительных операций загрузки. Результат сохраняется в первом аккумуляторе. Бит RLO — результат логической операции, применим и для операций сравнения. JC — переход при RLO=1, JCN — переход при RLO=0. W#16#6C00 расшифровывается как шестнадцатиричное (#16) представление слова (W) 6C00, его можно записать и в десятичном виде W#27648 или просто 27648.
Ограничитель можно оформить в виде функции, т.к. статичной памяти для работы ему не требуется.
Алгоритм же вычисления арифметического плавающего среднего должен хранить в статичной памяти результаты последних замеров (кольцевой буфер), указатель на последний замер и сумму замеров в буфере. Т.е. иметь статичную память, неизменную между вызовами функции. В Step 7 этим требованиям отвечает функциональный блок. Помимо функции он имеет жестко ассоциированный (экземплярный) блок данных для расчетов. Обращаться к этим данным изнутри функционального блока проще чем к глобальным. Доступ снаружи (не из функционального блока) запрещен и блокируется.
На рисунке ниже представлена реакция функции простого скользящего среднего на скачок сигнала полного диапазона при буфере в 16 слов, функциональный блок вызывается из блока циклического прерывания ОВ35 с цикличностью 100mc.
FUNCTION_BLOCK FB30
TITLE = Функция простого скользящего среднего
AUTHOR: Anakost //
FAMILY: SOHO //
NAME: LIM_SMA // Limiter + Simple Moving Average
VERSION: 1.0 //
VAR_INPUT
INPUT: INT; // входной ток (Iin)
END_VAR
VAR_OUTPUT
OUTPUT: INT; // выходной ток (Iout)
RANGE: BOOL; // ошибка диапазона
END_VAR
VAR
VALUES: ARRAY[0..15] OF INT; // буфер
STEPER: WORD; // текущий указатель в буфере
TOTAL: DWORD; // сумма значений
END_VAR
VAR_TEMP
TEMP_VAL: INT; // временная внутренняя величина
END_VAR
BEGIN
NETWORK
TITLE = Ограничение и сглаживание 4..20mA
// Ограничение
L #INPUT; // ACCU 1 <- INPUT, входной ток
T #TEMP_VAL; // TEMP_VAL <-ACCU 1, во локальную переменную
L W#16#6C00; // ACCU 1 <- константа 20mA, ACCU 2 <- ACCU 1, верхняя граница диапазона
>I; // в RLO результат сравнения ACCU 2 > ACCU 1, проверка на превышение
= #RANGE; // RANGE <- RLO
JC A00; // в ACCU 1 верхняя граница диапазона
L #TEMP_VAL; // ACCU 1 <- INPUT
L W#16#0; // ACCU 1 <- константа 4mA, нижняя граница диапазона
<I; // в RLO результат сравнения ACCU 2 < ACCU 1, проверка на превышение
= #RANGE; // RANGE <- RLO
JCN A01; // в ACCU 1 нижняя граница диапазона
A00:
T #TEMP_VAL; // TEMP_VAL <- INPUT(Limiter), ограничение входного тока
A01:
// Сглаживание
L #STEPER; // ACCU 1 <- STEPER, загрузка текущего указателя
L P##VALUES; // ACCU 1 <- @VALUES, загрузка указателя на начало массива
+D; // ACCU 1 <- @VALUES + STEPER, сдвиг начального адреса на адрес слова
LAR1; // AR1 <- ACCU 1, регистр-указатель на нужное слово
POP; // ACCU 1 <- ACCU 2, ACCU 1 <- STEPER
+ 16; // ACCU 1 <- STEPER + 16 (длина слова), на следующий адрес
AW W#16#00FF; // ACCU 1 <- ACCU 1 AND 00FF, адрес ограничен одним байтом (16х16)
T #STEPER; // STEPER <- ACCU 1, сохранить новый адрес
L #TOTAL; // ACCU 1 <- TOTAL, загрузить сумму
L DIW [AR1,P#0.0]; // ACCU 1 <- VALUES[STEPER], чтение старого замера
-D; // ACCU 1 <- TOTAL - VALUES[STEPER], вычтем из суммы
L #TEMP_VAL; // ACCU 1 <- INPUT(Limiter), новый замер
T DIW [AR1,P#0.0]; // VALUES[STEPER] <- ACCU 1, сохранение в буфере
+D; // ACCU 1 <- TOTAL + INPUT(Limiter), прибавим к сумме
T #TOTAL; // TOTAL <- ACCU 1, сохраним новую сумму
SRD 4; // ACCU 1 >>>> 4, деление на 16, среднее арифметическое
T #OUTPUT; // OUTPUT <- ACCU 1, результат на выход
END_FUNCTION_BLOCK
Обычно при тестах я пользуюсь симулятором PLCSIM, т.к. не всегда можно собрать стенд, а тем более залезть в работающее оборудование. По словам Siemens PLCSIM позволяет выполнять отладку программы на ранних стадиях разработки проекта и предоставляет следующие преимущества:
- Ускорение отладки программы и снижение затрат на проектирование.
- Повышение качества разрабатываемого программного обеспечения.
И все было ничего, но на этом функциональном блоке PLCSIM меня подвел.
По рускоязычному мануалу от Siemens второй аккумулятор после математической операции не изменяется. Я этим воспользовался в своем коде, но обнаружил что при запуске под PLCSIM второй аккумулятор обнуляется.
Это привело к тому, что адрес указателя в буфере не изменяется и программа постоянно стоит на первом слове.
Проверил на рабочем S7-300, нет, все работает как и должно быть.
И ревизия PLCSIM у меня вроде не старая (K5.4.5.2), раньше проблем не было, в общем не понял…
Если хотите, чтобы FB нормально работал и в симуляторе, его нужно немного изменить. Не полагаться на то, что нужное число осталось в ACCU 2, а принудительно загрузить его в ACCU 1. Вырезаем следующие строки:
POP; // ACCU 1 <- ACCU 2, ACCU 1 <- STEPER
+ 16; // ACCU 1 <- STEPER + 16 (длина слова), на следующий адрес
AW W#16#00FF; // ACCU 1 <- ACCU 1 AND 00FF, адрес ограничен одним байтом (16х16)
T #STEPER; // STEPER <- ACCU 1, сохранить новый адрес
и в самый конец блока (после T #OUTPUT) добавляем:
L #STEPER; // ACCU 1 <- STEPER, загрузка текущего указателя
+ 16; // ACCU 1 <- STEPER + 16 (длина слова), на следующий адрес
AW W#16#00FF; // ACCU 1 <- ACCU 1 AND 00FF, адрес ограничен одним байтом (16х16)
T #STEPER; // STEPER <- ACCU 1, сохранить новый адрес
Создавать блоки данных для функциональных блоков вручную нет необходимости и не рекомендуется. Лучше чтобы их создал STEP 7. Для этого нужно в месте вызова функционального блока вызвать его с номером требуемого блока данных. Примерно так:
CALL FB30, DB30 <Enter>
При этом FB30 должен быть скомпилирован и находиться в папке Blocks, номер блока данных может быть любым, еще не используемым. После нажатия «Enter» STEP 7 предупредит, что данного блока не существует и спросит, надо ли его создать.
При нажатии «Yes» блок данных с необходимой внутренней структурой, правильным TimeStamp (отметка времени) и привязкой к FB30 будет создан:
Вызов блока также дополнится формальными обозначениями входов/выходов:
Блок был опробован на измерении уровня воды в буферном баке (120 м3) датчиком давления. Уровень (0..6м) отслеживается с шагом изменения 0,01м. Ранее при медленном опорожнении бака происходило 4-6 переключений во время смены показаний. После подключения на выход датчика этого функционального блока показания сгладились, происходило 1-2 переключения. Хотелось бы еще плавнее. Это было достигнуто увеличением постоянной времени фильтра. Сделать это несложно, необходимо пропускать некоторые из вызовов фильтра.
L DB5.Cycle_Counter // Загрузка счетчика цикла
LOOP M001 // Декремент и выход если ACCU1 > 0
CALL FB30, DB30
INPUT := PIW 754
OUTPUT:= MW 112
RANGE := M 3.4
L DB5.Division_Factor // Коэффициент деления
M001:
T DB5.Cycle_Counter // Сохранение счетчика цикла
Коэффициент деления и счетчик цикла хранятся в глобальном блоке данных. Это сделано для удобной подстройки коэффициента сглаживания во время работы без подключения програматора.
DATA_BLOCK DB5
TITLE = "Параметры сглажив
ания"VERSION : 1.0
STRUCT
Cycle_Counter : BYTE := B#16#0; // Счетчик цикла
Division_Factor : BYTE := B#16#4; // Коэффициент деления
END_STRUCT;
BEGIN
Division_Factor := B#16#4;
END_DATA_BLOCK
Коэффициент деления Division_Factor выведен как тег в операционной панели.
И в заключение расскажу еще об одном эксперименте с этим функциональным блоком. Вход и выход блока имеют одинаковый тип данных. А что если включить два блока цепочкой, один за другим? Чтобы оставить только необходимое, был оформлен новый функциональный блок.
FUNCTION_BLOCK FB40
TITLE = Функция сдвоенного простого скользящего среднего
AUTHOR: Anakost //
FAMILY: SOHO //
NAME: LIM_DSMA //Limiter + Double Simple Moving Average
VERSION: 1.0 //
VAR_INPUT
INPUT: INT; // входной ток (Iin)
END_VAR
VAR_OUTPUT
OUTPUT: INT; // выходной ток (Iout)
RANGE: BOOL; // ошибка диапазона
END_VAR
VAR
VALUES_1: ARRAY[0..15] OF INT; // буфер 1 ступени
VALUES_2: ARRAY[0..15] OF INT; // буфер 2 ступени
STEPER_1: WORD; // текущий указатель в буфере 1 ступени
STEPER_2: WORD; // текущий указатель в буфере 2 ступени
TOTAL_1: DWORD ; // сумма значений 1 ступени
TOTAL_2: DWORD ; // сумма значений 2 ступени
END_VAR
VAR_TEMP
TEMP_VAL: INT; // временная внутренняя величина
END_VAR
BEGIN
NETWORK
TITLE = Ограничение и двухступенчатое сглаживание 4..20mA
// Ограничение
L #INPUT; // ACCU 1 <- INPUT, входной ток
T #TEMP_VAL; // TEMP_VAR <-ACCU 1, в локальную переменную
L 27648; // ACCU 1 <- константа 20mA, ACCU 2 <- ACCU 1, верхняя граница диапазона
>I; // в RLO результат сравнения ACCU 2 > ACCU 1, проверка на превышение
= #RANGE; // RANGE <- RLO
JC A00; // в ACCU 1 верхняя граница диапазона
L #TEMP_VAL; // ACCU 1 <- INPUT
L 0; // ACCU 1 <- константа 4mA, нижняя граница диапазона
<I; // в RLO результат сравнения ACCU 2 < ACCU 1, проверка на превышение
= #RANGE; // RANGE <- RLO
JCN A01; // в ACCU 1 нижняя граница диапазона
A00:
T #TEMP_VAL; //ограничение входной величины
A01:
// Сглаживание 1 ступени
L #STEPER_1; // ACCU 1 <- STEPER_1, загрузка текущего указателя
L P##VALUES_1; // ACCU 1 <- @VALUES_1, загрузка указателя на начало массива
+D; // ACCU 1 <- @VALUES_1 + STEPER_1, сдвиг начального адреса на адрес слова
LAR1; // AR1 <- ACCU 1, регистр-указатель на нужное слово
POP; // ACCU 1 <- ACCU 2, ACCU 1 <- STEPER_1
+ 16; // ACCU 1 <- STEPER + 16 (длина слова), на следующий адрес
AW W#16#00FF; // ACCU 1 <- ACCU 1 AND 00FF, адрес ограничен одним байтом (16х16)
T #STEPER_1; // STEPER <- ACCU 1, сохранить новый адрес
L #TOTAL_1; // ACCU 1 <- TOTAL_1, загрузить сумму
L DIW [AR1,P#0.0]; // ACCU 1 <- VALUES_1[STEPER_1], чтение старого замера
-D; // ACCU 1 <- TOTAL_1 - VALUES_1[STEPER_1], вычтем из суммы
L #TEMP_VAL; // ACCU 1 <- INPUT(Limiter), новый замер
T DIW [AR1,P#0.0]; // VALUES_1[STEPER_1] <- ACCU 1, сохранение в буфере
+D; // ACCU 1 <- TOTAL_1 + INPUT(Limiter), прибавим к сумме
T #TOTAL_1; // TOTAL_1 <- ACCU 1, сохраним новую сумму
SRD 4; // ACCU 1 >>>> 4, деление на 16, среднее арифметическое
T #TEMP_VAL; // OUTPUT <- ACCU 1, результат в локальную переменную
// Сглаживание 2 ступени
L #STEPER_2; // ACCU 1 <- STEPER_2, загрузка текущего указателя
L P##VALUES_2; // ACCU 1 <- @VALUES_2, загрузка указателя на начало массива
+D; // ACCU 1 <- @VALUES_2 + STEPER_2, сдвиг начального адреса на адрес слова
LAR1; // AR1 <- ACCU 1, регистр-указатель на нужное слово
POP; // ACCU 1 <- ACCU 2, ACCU 1 <- STEPER_2
+ 16; // ACCU 1 <- STEPER + 16 (длина слова), на следующий адрес
AW W#16#00FF; // ACCU 1 <- ACCU 1 AND 00FF, адрес ограничен одним байтом (16х16)
T #STEPER_2; // STEPER <- ACCU 1, сохранить новый адрес
L #TOTAL_2; // ACCU 1 <- TOTAL_2, загрузить сумму
L DIW [AR1,P#0.0]; // ACCU 1 <- VALUES_2[STEPER_2], чтение старого замера
-D; // ACCU 1 <- TOTAL_2 - VALUES_2[STEPER_2], вычтем из суммы
L #TEMP_VAL; // ACCU 1 <- INPUT(Limiter+SMA), новый замер
T DIW [AR1,P#0.0]; // VALUES_2[STEPER_2] <- ACCU 1, сохранение в буфере
+D; // ACCU 1 <- TOTAL_2 + INPUT(Limiter), прибавим к сумме
T #TOTAL_2; // TOTAL_2 <- ACCU 1, сохраним новую сумму
SRD 4; // ACCU 1 >>>> 4, деление на 16, среднее арифметическое
T #OUTPUT; // OUTPUT <- ACCU 1, результат на выход
END_FUNCTION_BLOCK
Для сравнения график исходной функции FB30, постоянная времени фильтра 1,6 сек.
И график «тандемной» функции FB40, постоянная времени фильтра 3,2 сек. График из прямого стал S-образным.
Качественной рускоязычной документации по устройству и программированию Simatic очень много. Перевод как правило произведен фирмой Siemens, и самая полная подборка со свежими исправлениями лежит на официальном сайте. К сожалению для скачивания требуется регистрация.
🔗 Simatic Step 7, STL, сглаживание (Smooth) сигнала аналогового входа 4-20mA.