В разделе "Трёп (Курилка)" действует ручная премодерация перед публикацией темы.
Конкретно для этой - премодерация длилась почти 2 недели, так что актуальности вопроса уже нет.
Просто отпишусь, как решил.
Перед созданием темы полагал, что скрипты в панелях Weintek помогают получить дополнительный функционал, поэтому не брался их изучать и применять. Сейчас же - уверен, что скрипты требуются для реализации основного функционала, их изучение и применение - единственный способ решить задачи.
Итак.
Задача:
1. события от контроллера поступают в виде битовой маски из нескольких регистров (регистры флагов событий)
2. не используется "журнал событий (аварий)" и его визуальные элементы, поэтому его свойства реакции на события также не используются
3. при возникновении нового события (установки "нового" бита в любом из регистров флагов событий) должны: включиться звук динамика панели, появиться всплывающее окно с кнопкой квитирования (отключения звука)
4. оператор нажимает кнопку квитирования на всплывающем окне и после этого окно закрывается, звуковая сигнализация выключается.
5. если флаг события оказался снят до квитирования (например, кнопкой сброс со щита автоматики), то окно не закрывается, звуковая сигнализация не выключается - продолжает ожидать реакции оператора.
Реализация:
1. Уже существовали переменные - регистры флагов событий - принимаемые из контроллера - wMS_Common_Alarm, wMS_Pump1_Alarm, wMS_Pump2_Alarm, wMS_PumpFill_Alarm, wMS_HeatSens_Alarm, wMS_HeatPumpFill_Alarm
2. объявил переменную bNoAcknowledge ("Local HMI" LB-100) - подтверждение (квитирование) события
3. объявил переменные в области LW - wMS_Common_Alarm_Prev, wMS_Pump1_Alarm_Prev, wMS_Pump2_Alarm_Prev, wMS_PumpFill_Alarm_Prev, wMS_HeatSens_Alarm_Prev, wMS_HeatPumpFill_Alarm_Prev - состояния регистров флагов на предыдущем опросе
4. объявил макрос, вызываемый однократно при инициализации - вероятно, после включения питания переменные и так обнуляются, но мне не жалко принудительно это сделать
Код:
// инициализация переменных, требуемых для сигнализации
macro_command main()
bool init_bool_false = 0
unsigned short init_uint16 = 0
// определение добавления флагов событий сигнализации для каждой подсистемы
init_uint16 = 0
SetData(init_uint16, "Local HMI", "wMS_Common_Alarm_Prev", 1) // - общее
SetData(init_uint16, "Local HMI", "wMS_Pump1_Alarm_Prev", 1) // - насос 1
SetData(init_uint16, "Local HMI", "wMS_Pump2_Alarm_Prev", 1) // - насос 2
SetData(init_uint16, "Local HMI", "wMS_PumpFill_Alarm_Prev", 1) // - насос заполнения
SetData(init_uint16, "Local HMI", "wMS_HeatSens_Alarm_Prev", 1) // - самонагревающийся кабель нагрева датчиков
SetData(init_uint16, "Local HMI", "wMS_HeatPumpFill_Alarm_Prev", 1) // - самонагревающийся кабель нагрева насосов заполнения
// подтверждение событий
SetData(init_bool_false, "Local HMI", "bNoAcknowledge", 1)
end macro_command
5. объявил периодически (1000 мс) вызываемый макрос для установки в true переменной bNoAcknowledge по возникновению нового события и для кратковременного включения динамика. пока не разобрался, что делать с ошибкой обмена по Modbus, поэтому переменную error не использовал
Код:
// получение флага добавления сигнала неисправности
// формирование прерывистых звуковых сигналов
macro_command main()
bool new_alarm = 0 // флаг появления нового сигнала неисправности
bool no_acknowledge = 0 // флаг отсутствия квитирования сигнала неисправности
unsigned short alarms_current = 0 // текущее состояние регистра флагов неисправностей
unsigned short alarms_previous = 0 // предыдущее состояние регистра флагов неисправностей
unsigned short error = 0 // код ошибки (0 - ошибки нет)
// инициализация
GetData(no_acknowledge, "Local HMI", "bNoAcknowledge", 1)
new_alarm = 0
// определение добавления флагов событий сигнализации для каждой подсистемы
// регистры флагов состояния нигде кроме этого макроса не опрашиваются, поэтому
// опрашиваем их командами GetData/GetDataEx и не беспокоимся о избыточности количества опросов
// - общее
GetDataEx(alarms_current, "PLC", "wMS_Common_Alarm", 1)
GetError(error)
GetData(alarms_previous, "Local HMI", "wMS_Common_Alarm_Prev", 1)
SetData(alarms_current, "Local HMI", "wMS_Common_Alarm_Prev", 1)
new_alarm = new_alarm or ((alarms_current & (~alarms_previous)) > 0)
// - насос 1
GetDataEx(alarms_current, "PLC", "wMS_Pump1_Alarm", 1)
GetError(error)
GetData(alarms_previous, "Local HMI", "wMS_Pump1_Alarm_Prev", 1)
SetData(alarms_current, "Local HMI", "wMS_Pump1_Alarm_Prev", 1)
new_alarm = new_alarm or ((alarms_current & (~alarms_previous)) > 0)
// - насос 2
GetDataEx(alarms_current, "PLC", "wMS_Pump2_Alarm", 1)
GetError(error)
GetData(alarms_previous, "Local HMI", "wMS_Pump2_Alarm_Prev", 1)
SetData(alarms_current, "Local HMI", "wMS_Pump2_Alarm_Prev", 1)
new_alarm = new_alarm or ((alarms_current & (~alarms_previous)) > 0)
// - насос заполнения
GetDataEx(alarms_current, "PLC", "wMS_PumpFill_Alarm", 1)
GetError(error)
GetData(alarms_previous, "Local HMI", "wMS_PumpFill_Alarm_Prev", 1)
SetData(alarms_current, "Local HMI", "wMS_PumpFill_Alarm_Prev", 1)
new_alarm = new_alarm or ((alarms_current & (~alarms_previous)) > 0)
// - электрообогрев датчиков
GetDataEx(alarms_current, "PLC", "wMS_HeatSens_Alarm", 1)
GetError(error)
GetData(alarms_previous, "Local HMI", "wMS_HeatSens_Alarm_Prev", 1)
SetData(alarms_current, "Local HMI", "wMS_HeatSens_Alarm_Prev", 1)
new_alarm = new_alarm or ((alarms_current & (~alarms_previous)) > 0)
// - электрообогрев насосов заполнения
GetDataEx(alarms_current, "PLC", "wMS_HeatPumpFill_Alarm", 1)
GetError(error)
GetData(alarms_previous, "Local HMI", "wMS_HeatPumpFill_Alarm_Prev", 1)
SetData(alarms_current, "Local HMI", "wMS_HeatPumpFill_Alarm_Prev", 1)
new_alarm = new_alarm or ((alarms_current & (~alarms_previous)) > 0)
// если произошло новое событие, то установить требование квитирования
no_acknowledge = no_acknowledge or new_alarm
// если событие не квитировано, то включить звуковой сигнал
if no_acknowledge then
Beep()
end if
// сохранение состояния квитирования
SetData(no_acknowledge, "Local HMI", "bNoAcknowledge", 1)
end macro_command
// current previous result
// 0 0 0
// 0 1 0
// 1 0 1
// 1 1 0
6. создал небольшое всплывающее окно с элементами
- функциональная кнопка с действием "Закрыть окно"
- битовая кнопка с атрибутом "OFF при закрытии окна" для переменной bNoAcknowledge
- числовой индикатор для анимации мигающего колокольчика
7. на "4. Common Window" по центру добавил объект "Прямой вызов окна" со свойствами:
- триггер - ON
- № окна - моё всплывающее окно
- Чтение устройство: Local HMI
- Чтение адрес: bNoAcknowledge
- вкладка Позиция - автонастройка размеров окна
Т.е. механизм такой:
При нормальной работе устройства переменная bNoAcknowledge равна false.
При возникновении события контроллером устанавливается один или несколько битов регистров флагов.
Периодически вызываемый макрос принимает регистры флагов из контроллера и при появлении нового события (установленного бита) устанавливает переменную bNoAcknowledge в true, а также включает кратковременный звук на динамике при bNoAcknowledge.
Общее окно "4. Common Window" объектом "Прямой вызов окна" при bNoAcknowledge равном true открывает всплывающее окно.
Оператор нажимает кнопку "Сброс звука" во всплывающем окне, после чего окно закрывается и при закрытии переменной bNoAcknowledge присваивается false - снимается условие формирования звуковой сигнализации.
Пока разбирался с задачей, немного поднял уровень знаний по работе с макросами панелей Weintek, разобрался с работой визуальных объектов "журнала событий". Готовлю небольшую статью-памятку в своём блоге.