Просмотр полной версии : Управление устройствами через битовую маску
Всех приветствую.
Проблема с управлением устройств через битовую маску. Что-то делаю не так и не пойму что.
Есть два параметра - входной и выходной параметры SYSTEM_WORD_PARAM.
Допустим, что на входе 16 состояний работы устройств и на выходе 16 команд управления, то есть WORD = 2 байта = 16 битов.
По входным состояниям битов вопросов нет - я их "распаковываю" через ST.
А вот по выходным параметрам что-то неправильно выстраиваю.
Значит на экран добавил 16 кнопок нефиксируемых (вкл/откл). Поставил галку на "использовать входящую связь только для отображения". Привязал входной бит состояния.
На событие нажатия этой кнопки привязал выдачу импульса на 500ms и все кнопки проходит через этот алгоритм, но при нажатии иногда вроде бы работает нормально, а иногда не работает:
VAR
firstScan: BOOL := TRUE;
systemInitialized: BOOL := FALSE;
initCounter: INT := 0; // Счетчик для задержки инициализации
prevState_0: BOOL := FALSE;
.
.
.
prevState_15: BOOL := FALSE;
END_VAR
VAR_TEMP
needUpdate: BOOL;
END_VAR
// Основной алгоритм
needUpdate := FALSE;
tempWord.Value := inputWord.Value;
tempWord.SourceTime := inputWord.SourceTime;
tempWord.StatusCode := inputWord.StatusCode;
// Бит 0
IF (state_0.Value = TRUE) AND (prevState_0 = FALSE) THEN
tempWord.Value.0 := NOT inputWord.Value.0;
needUpdate := TRUE;
END_IF;
prevState_0 := state_0.Value;
.
.
.
// Бит 15
IF (state_15.Value = TRUE) AND (prevState_15 = FALSE) THEN
tempWord.Value.15 := NOT inputWord.Value.15;
needUpdate := TRUE;
END_IF;
prevState_15 := state_15.Value;
// Записываем результат только если были изменения
IF needUpdate THEN
outputWord.Value := tempWord.Value;
outputWord.SourceTime := tempWord.SourceTime;
outputWord.StatusCode := tempWord.StatusCode;
END_IF;
// Отложенная инициализация после полной загрузки системы
IF firstScan THEN
initCounter := initCounter + 1;
// Ждем несколько циклов (например, 3) для полной инициализации
IF initCounter >= 3 THEN
// Проверяем, что inputWord содержит актуальные данные
IF inputWord.Value <> 0 OR inputWord.StatusCode <> 0 THEN
outputWord.Value := inputWord.Value;
outputWord.SourceTime := inputWord.SourceTime;
outputWord.StatusCode := inputWord.StatusCode;
systemInitialized := TRUE;
firstScan := FALSE;
END_IF;
END_IF;
END_IF;
Что я делаю не так, подскажите как правильно должна быть выстроена структура и алгоритм.
Всех приветствую.
Проблема с управлением устройств через битовую маску. Что-то делаю не так и не пойму что.
Есть два параметра - входной и выходной параметры SYSTEM_WORD_PARAM.
Допустим, что на входе 16 состояний работы устройств и на выходе 16 команд управления, то есть WORD = 2 байта = 16 битов.
По входным состояниям битов вопросов нет - я их "распаковываю" через ST.
А вот по выходным параметрам что-то неправильно выстраиваю.
Значит на экран добавил 16 кнопок нефиксируемых (вкл/откл). Поставил галку на "использовать входящую связь только для отображения". Привязал входной бит состояния.
На событие нажатия этой кнопки привязал выдачу импульса на 500ms и все кнопки проходит через этот алгоритм, но при нажатии иногда вроде бы работает нормально, а иногда не работает:
VAR
firstScan: BOOL := TRUE;
systemInitialized: BOOL := FALSE;
initCounter: INT := 0; // Счетчик для задержки инициализации
prevState_0: BOOL := FALSE;
.
.
.
prevState_15: BOOL := FALSE;
END_VAR
VAR_TEMP
needUpdate: BOOL;
END_VAR
// Основной алгоритм
needUpdate := FALSE;
tempWord.Value := inputWord.Value;
tempWord.SourceTime := inputWord.SourceTime;
tempWord.StatusCode := inputWord.StatusCode;
// Бит 0
IF (state_0.Value = TRUE) AND (prevState_0 = FALSE) THEN
tempWord.Value.0 := NOT inputWord.Value.0;
needUpdate := TRUE;
END_IF;
prevState_0 := state_0.Value;
.
.
.
// Бит 15
IF (state_15.Value = TRUE) AND (prevState_15 = FALSE) THEN
tempWord.Value.15 := NOT inputWord.Value.15;
needUpdate := TRUE;
END_IF;
prevState_15 := state_15.Value;
// Записываем результат только если были изменения
IF needUpdate THEN
outputWord.Value := tempWord.Value;
outputWord.SourceTime := tempWord.SourceTime;
outputWord.StatusCode := tempWord.StatusCode;
END_IF;
// Отложенная инициализация после полной загрузки системы
IF firstScan THEN
initCounter := initCounter + 1;
// Ждем несколько циклов (например, 3) для полной инициализации
IF initCounter >= 3 THEN
// Проверяем, что inputWord содержит актуальные данные
IF inputWord.Value <> 0 OR inputWord.StatusCode <> 0 THEN
outputWord.Value := inputWord.Value;
outputWord.SourceTime := inputWord.SourceTime;
outputWord.StatusCode := inputWord.StatusCode;
systemInitialized := TRUE;
firstScan := FALSE;
END_IF;
END_IF;
END_IF;
Что я делаю не так, подскажите как правильно должна быть выстроена структура и алгоритм.
Не изучал подробно ваш код, но попробуйте учитывать такой момент, что по умолчанию протоколы MS настроены на запись значения только по его изменению (значения). Можно добавить (https://owen.ru/forum/showthread.php?t=41567&p=467204&viewfull=1#post467204) в условие запись по изменению метки времени значения.
Если у вас команды управления импульсные - зачем вам ЧИТАТЬ значение регистра с этими командами?
Можно добавить (https://owen.ru/forum/showthread.php?t=41567&p=467204&viewfull=1#post467204) в условие запись по изменению метки времени значения.
Как-то раз тех поддержка тоже такое советовало, но это замедляет работу протокола. И у меня в общей сложности устройств намного больше, а 16 привел только для примера.
Если у вас команды управления импульсные - зачем вам ЧИТАТЬ значение регистра с этими командами?Кнопки только импульсные, на самом деле в алгоритме делаю, что-то наподобие самоподхвата. А читаю регистры, потому что было такое, что при изменении какого-либо бита в остальные биты записывались False (0), поэтому я начал туда записывать актуальные значения.
Как-то раз тех поддержка тоже такое советовало, но это замедляет работу протокола. И у меня в общей сложности устройств намного больше, а 16 привел только для примера.
Кнопки только импульсные, на самом деле в алгоритме делаю, что-то наподобие самоподхвата. А читаю регистры, потому что было такое, что при изменении какого-либо бита в остальные биты записывались False (0), поэтому я начал туда записывать актуальные значения.
Попробуйте так:
Выход.Value.0 := x0;
Выход.Value.1 := x1;
Выход.Value.2 := x2;
Выход.Value.3 := x3;
Выход.Value.4 := x4;
Выход.Value.5 := x5;
Выход.Value.6 := x6;
Выход.Value.7 := x7;
Выход.Value.8 := x8;
Выход.Value.9 := x9;
Выход.Value.10 := x10;
Выход.Value.11 := x11;
Выход.Value.12 := x12;
Выход.Value.13 := x13;
Выход.Value.14 := x14;
Выход.Value.15 := x15;
Выход.StatusCode := Вход.StatusCode;
т.е. просто упаковать сигналы с кнопок (импульсы) и присвоить выходу статус входного слова.
А для надёжности было бы в конце программного цикла ПЛК обнулять регистр с командами (если конечно есть такая возможность)
т.е. просто упаковать сигналы с кнопок (импульсы)так это самый элементарный вариант - я с него и начал и у меня возникла проблема с тем, что я нажимаю какую либо кнопку, он отправляет на запись True в нужный бит, а все что не было нажато записывается как False и он выключал все остальные устройства.
То есть вся проблема в том, что при запуске скады кнопки и выходное состояние должны синхронизироваться с текущим актуальным состоянием и соотвественно, при изменении какого-либо бита на выход отправляться вся актуальная битовая маска, кроме последнего измененного, разве нет?
так вам надо не просто отправить true в бит, если вы используете слово для записи. А изменить бит в слове и уже его отправить. Чтобы значения других бит не изменились.
То есть взять не новое слово, где все по нулям, а текущее состояние слова.
так вам надо не просто отправить true в бит, если вы используете слово для записи. А изменить бит в слове и уже его отправить. Чтобы значения других бит не изменились.
То есть взять не новое слово, где все по нулям, а текущее состояние слова.
В моем изначальном алгоритме я именно так и делаю
Попробую убрать все лишнее и сделать все заново
IF (state_0.Value = TRUE) AND (prevState_0 = FALSE) THEN
плохо понимаю ST, но ... вы проверяете, что ваш бит True и тут же какую-то булевую переменную предыдущего состояния - простой вопрос, а нахрена все это?
Вот просто сделать функцию SetBit и пофигу что вы там хотите записать 0 или 1 и не париться ?
Или как-то обязательно только 1 записывать в бит ?
так это самый элементарный вариант - я с него и начал и у меня возникла проблема с тем, что я нажимаю какую либо кнопку, он отправляет на запись True в нужный бит, а все что не было нажато записывается как False и он выключал все остальные устройства.
То есть вся проблема в том, что при запуске скады кнопки и выходное состояние должны синхронизироваться с текущим актуальным состоянием и соотвественно, при изменении какого-либо бита на выход отправляться вся актуальная битовая маска, кроме последнего измененного, разве нет?
Как-то раз тех поддержка тоже такое советовало, но это замедляет работу протокола. И у меня в общей сложности устройств намного больше, а 16 привел только для примера.
Кнопки только импульсные, на самом деле в алгоритме делаю, что-то наподобие самоподхвата. А читаю регистры, потому что было такое, что при изменении какого-либо бита в остальные биты записывались False (0), поэтому я начал туда записывать актуальные значения.
Я из этого понял что сигналы "ТОЛЬКО ИМПУЛЬСНЫЕ".
Если это не так - то я, например, изрядно помучившись, отказался от идеи записывать такие биты словом. Завожу отдельные битовые теги для таких целей
Powered by vBulletin® Version 4.2.3 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot