Здравствуйте!
Можно ли так (речь о кнопке без фиксации):
- первое нажатие - включить, запись в одну переменную (в ОРС и соответственно в контроллер), надпись меняется с "включить" на "выключить"
- второе нажатие - выключить, запись в другую переменную, надпись меняется с "выключить" на "включить"
Вы можете менять значение нужной переменной по событию OnClick кнопки используя свойство Value (https://simple-scada.com/help/script/varvalue.html):
begin
{ записываем значение 10 в переменную MyVar }
MyVar.Value := 10;
end.
Менять надписи, цвет и другие свойства нужно у состояния кнопки, например:
begin
Button1.States[0].Caption := 'Включить'; // изменить название кнопки в состоянии 0
Button1.States[0].Color := clGreen; // изменить цвет кнопки в состоянии 0
Button1.States[0].BorderColor := clBlack; // изменить цвет рамки кнопки в состоянии 0
end.
При таком подходе вряд ли получится сделать проще чем сделано у Вас сейчас. Гораздо проще и правильнее было бы внести изменения в программу контроллера для реализации управления с одной кнопки или просто использовать две кнопки не скрывая их друг за другом.
Как я понял если у кнопки с фиксацией оставить 1 состояние (запись единицы), то это равнозначно кнопке без фиксации, т.е. запись единицы будет происходить однократно?
Нет, не равнозначно. При нажатии на кнопку без фиксации в переменную записывается 1, а при отпускании записывается 0. При нажатии кнопки с фиксацией и одним состоянием в переменную всегда записывается 1.
asnik, конечно, Вы можете работать в скрипте с любым количеством переменных как угодно. Можете например менять у кнопки значение "Тег" при каждом нажатии и в зависимости от значения тега работать с разными переменными, например:
begin
{ если тег кнопки равен 0, то работаем с первой переменной }
if Button1.Tag = 0 then
begin
MyVariable1.Value := 1;
Button1.Tag := 1; // отмечаем, что следующий клик должен работать со второй переменной
end else
{ если тег кнопки не равен 0, то работаем со второй переменной }
begin
MyVariable2.Value := 1;
Button1.Tag := 0; // отмечаем, что следующий клик должен работать с первой переменной
end;
end.
Учитывайте, что кнопка не должна быть связана с переменной, иначе по-клику скада будет автоматически менять эту переменную. Также нужно учитывать, что предложенный выше вариант работы с двумя переменными никак не связан с состояниями кнопки, т.е. состояние кнопки будет всегда одним и тем же, просто каждый четный клик будет выполнять присвоение в первую переменную, а каждый нечётный во вторую. Также после перезапуска проекта на сервере тег у кнопки будет равен 0 (т.к. он не зависит от значений переменных) и первый клик всегда будет работать с первой переменной (что может привести к проблемам).
Спасибо, примерно так я себе это и представлял. Опять же, если я буду иметь информацию с контроллера, что в данный момент механизм "Выкл" , то соответственно кнопка должна быть с надписью "Вкл" и при нажатии писать 1-цу в соответствующую переменную контроллера
Извините, я не понял.
Приведу пример своей проблемы. Дано:
Simple-SCADA Демо-версия с ограничением по времени работы. Я автоматчик, но о языках программирования только слышу от программистов, которым ставлю задачу. Никто из них не знает Simple-SCADA. Вижу перспективу в этом продукте у нас в плане построения диспетчеризации на руднике - Решил сам учиться. Извините за длиннотекст, больше так не буду)).
Создал пробный проект типа для "Брэйн-Ринга" через веб-интерфейс между нашими сотрудниками)). В нём задействован скриптовый таймер на событии "Прошла секунда":
begin
// Если таймер разрешён и не дошёл до граничной уставки,
//то таймер считает дальше
if TimerRun.Value and (Time.Value < TimerSetPoint.Value) then
begin
Time.Value := Time.Value + 1;
end;
// Если Таймер дошёл до предупредительной уставки,
// то просигнализировать о достижении предупредительной уставки
if Time.Value >= TimerPreAlarmSetPoint.Value then
begin
TimerAlarm_1.Value := True;
end;
// Если Таймер дошёл до граничной уставки,
// то запретить таймер и просигнализировать о достижении граничной уставки
if Time.Value >= TimerSetPoint.Value then
begin
TimerRun.Value := False;
TimerAlarm_2.Value := True;
end;
end.
Нужны были кнопки без фиксации с надписью "ПУСК", "СТОП", "СБРОС". После нажатия и отпускания кнопок я должен получить в переменную логическую единицу ("1"), а нажатая кнопка должна вернуться в исходное ненажатое состояние.
Как делал:
Добавил на экран кнопку;
Выбрал Тип "Без фиксации";
Оставил Состояние по умолчанию "Отпущена" (Номер 0, Значение 1, Текст "Включить");
Создал переменную btnStart_1 типа "Boolean" и прицепил к кнопке, потому что без прицепленной к кнопке переменной ничего не выходит - проверял выводом значений переменных кнопок в виде состояний элементов CheckBox на мнемосхеме;
Создал вторую такую переменную btnStart_2 что бы запоминать факт того что кнопка была нажата, даже если уже отпустили - прицепил к кнопке скрипт по событию OnClick (Аналогичные скрипты на кнопку СТОП и СБРОС):
begin
// Если нажат ПУСК, то запомнить это и обнулить СТОП, СБРОС
if btnStart_1.Value then
begin
btnStart_2.Value := True;
btnStop_2.Value := False;
btnReset_2.Value := False;
// Алгоритмическая часть
FirstTeamFlag.Value := False;
FirstTeamNumber.Value := 0;
TimerRun.Value := True;
end;
end.
Проблема:
После нажатия и отпускания кнопок, индикация кнопки остаётся в нажатом состоянии, о чём свидетельствует текст на кнопке "Выключить".
Вопрос:
Что я делаю не так? Я же вроде не влияю на переменную, прикреплённую к кнопке, и Тип кнопки "Без фиксации".
Такая же проблема возникает у кнопок команд столов:
begin
if FirstTeamFlag.Value = False then
begin
// Обработка кнопки 1
if btnTeam1_1.Value and (btnTeam1_2.Value = False) then
begin
btnTeam1_2.Value := True;
FirstTeamFlag.Value := True;
FirstTeamNumber.Value := 1;
TimerRun.Value := False;
end;
// Обработка кнопки 2
if btnTeam2_1.Value and (btnTeam2_2.Value = False) then
begin
btnTeam2_2.Value := True;
// Алгоритмическая часть
FirstTeamFlag.Value := True;
FirstTeamNumber.Value := 2;
TimerRun.Value := False;
end;
// Обработка кнопки 3
if btnTeam3_1.Value and (btnTeam3_2.Value = False) then
begin
btnTeam3_2.Value := True;
// Алгоритмическая часть
FirstTeamFlag.Value := True;
FirstTeamNumber.Value := 3;
TimerRun.Value := False;
end;
// Обработка кнопки 4
if btnTeam4_1.Value and (btnTeam4_2.Value = False) then
begin
btnTeam4_2.Value := True;
// Алгоритмическая часть
FirstTeamFlag.Value := True;
FirstTeamNumber.Value := 4;
TimerRun.Value := False;
end;
// Обработка кнопки 5
if btnTeam5_1.Value and (btnTeam5_2.Value = False) then
begin
btnTeam5_2.Value := True;
// Алгоритмическая часть
FirstTeamFlag.Value := True;
FirstTeamNumber.Value := 5;
TimerRun.Value := False;
end;
end;
end.
Проблема:
После нажатия и отпускания кнопок, индикация кнопки остаётся в нажатом состоянии, о чём свидетельствует текст на кнопке "Выключить".
Кажется я понял в чем ваша проблема, сам недавно сталкивался с подобным.
Для глобальных переменных TM_Variable с типом boolean (которые вы создаете в меню "переменные") такой код не работает:
if Variable.Value = True then myVar := True;
Хотя никакой ошибки при компиляции нет.
Для использования с условным оператором нужно глобальную переменную приводить к логическому типу:
if Variable.asBool = True then myVar := True;
Выглядит немного странно, что к Boolean надо применять метод AsBool. Скорее всего, это особенность типа TM_Variable у SimpleScada.
Выглядит немного странно, что к Boolean надо применять метод AsBool. Скорее всего, это особенность типа TM_Variable у SimpleScada.
Neskad, у типа TM_Variable нет никаких особенностей, как и у всех других типов в Simple-Scada, все работают стандартно. Компилятор который мы используем в Simple-Scada работает с переменными также как и любой другой современный компилятор. Он никак не меняет значения переменных, не выполняет с ними никаких лишних преобразований. Поэтому, если бы переменная действительная была Boolean, то не нужно было бы вызывать AsBool. Это значит, что в Вашу переменную с OPC-сервера приходит не Boolean значение (true или false), а например целочисленное (1 или 0), поэтому Вам и приходится явно приводить его к типу Boolean вызывая AsBool. В этой ситуации можно обойтись и без AsBool, только в этом случае 1 или 0 нельзя сравнивать с true и false и нужно писать так:
if Variable.Value then myVar := True;
Да, если тег записывается из скады, например через Кнопку, то, как мы и писали выше, в тег идут значения 1 и 0 (кнопка всегда записывает в целочисленном виде). Если запись идёт через скрипты, то скада будет записывать то, что написано в скрипте:
Variable.Value := True; // скада запишет True
Variable.Value := 1; // скада запишет 1
Но далее OPC-сервер может по-разному работать с значением, например он может знать что переменная имеет тип Boolean и вместо 1 которую хочет записать скада он может записать True в переменную и вернуть скаде True. Другой OPC-сервер может записать 1 и вернуть скаде 1, это зависит от OPC-сервера и типа данных который назначен переменной на OPC-сервере. Мы только говорим о том, что скаде все эти значения безразличны и она никак дополнительно не работает с этими значениями и не меняет их. Если переменная внешняя и от OPC-сервера пришла 1, то скада будет работать с ней как с 1. Если придёт True, то будет работать как с Boolean-значением True. Для внутренних переменных правила те же, только значения внутренних переменных присваиваются либо скриптами внутри скады, либо через компоненты скады, такие как Кнопка (целочисленные значения 1 и 0).