PDA

Просмотр полной версии : Управление устройствами через битовую маску



Asbi
07.07.2025, 20:59
Всех приветствую.

Проблема с управлением устройств через битовую маску. Что-то делаю не так и не пойму что.

Есть два параметра - входной и выходной параметры 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;

Что я делаю не так, подскажите как правильно должна быть выстроена структура и алгоритм.

1exan
08.07.2025, 05:06
Всех приветствую.

Проблема с управлением устройств через битовую маску. Что-то делаю не так и не пойму что.

Есть два параметра - входной и выходной параметры 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) в условие запись по изменению метки времени значения.

Если у вас команды управления импульсные - зачем вам ЧИТАТЬ значение регистра с этими командами?

Asbi
08.07.2025, 08:07
Можно добавить (https://owen.ru/forum/showthread.php?t=41567&p=467204&viewfull=1#post467204) в условие запись по изменению метки времени значения.

Как-то раз тех поддержка тоже такое советовало, но это замедляет работу протокола. И у меня в общей сложности устройств намного больше, а 16 привел только для примера.


Если у вас команды управления импульсные - зачем вам ЧИТАТЬ значение регистра с этими командами?Кнопки только импульсные, на самом деле в алгоритме делаю, что-то наподобие самоподхвата. А читаю регистры, потому что было такое, что при изменении какого-либо бита в остальные биты записывались False (0), поэтому я начал туда записывать актуальные значения.

1exan
08.07.2025, 08:27
Как-то раз тех поддержка тоже такое советовало, но это замедляет работу протокола. И у меня в общей сложности устройств намного больше, а 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;
т.е. просто упаковать сигналы с кнопок (импульсы) и присвоить выходу статус входного слова.
А для надёжности было бы в конце программного цикла ПЛК обнулять регистр с командами (если конечно есть такая возможность)

Asbi
08.07.2025, 09:05
т.е. просто упаковать сигналы с кнопок (импульсы)так это самый элементарный вариант - я с него и начал и у меня возникла проблема с тем, что я нажимаю какую либо кнопку, он отправляет на запись True в нужный бит, а все что не было нажато записывается как False и он выключал все остальные устройства.

То есть вся проблема в том, что при запуске скады кнопки и выходное состояние должны синхронизироваться с текущим актуальным состоянием и соотвественно, при изменении какого-либо бита на выход отправляться вся актуальная битовая маска, кроме последнего измененного, разве нет?

melky
08.07.2025, 09:10
так вам надо не просто отправить true в бит, если вы используете слово для записи. А изменить бит в слове и уже его отправить. Чтобы значения других бит не изменились.
То есть взять не новое слово, где все по нулям, а текущее состояние слова.

Asbi
08.07.2025, 09:20
так вам надо не просто отправить true в бит, если вы используете слово для записи. А изменить бит в слове и уже его отправить. Чтобы значения других бит не изменились.
То есть взять не новое слово, где все по нулям, а текущее состояние слова.

В моем изначальном алгоритме я именно так и делаю

Попробую убрать все лишнее и сделать все заново

melky
08.07.2025, 09:24
IF (state_0.Value = TRUE) AND (prevState_0 = FALSE) THEN

плохо понимаю ST, но ... вы проверяете, что ваш бит True и тут же какую-то булевую переменную предыдущего состояния - простой вопрос, а нахрена все это?
Вот просто сделать функцию SetBit и пофигу что вы там хотите записать 0 или 1 и не париться ?
Или как-то обязательно только 1 записывать в бит ?

1exan
08.07.2025, 10:03
так это самый элементарный вариант - я с него и начал и у меня возникла проблема с тем, что я нажимаю какую либо кнопку, он отправляет на запись True в нужный бит, а все что не было нажато записывается как False и он выключал все остальные устройства.

То есть вся проблема в том, что при запуске скады кнопки и выходное состояние должны синхронизироваться с текущим актуальным состоянием и соотвественно, при изменении какого-либо бита на выход отправляться вся актуальная битовая маска, кроме последнего измененного, разве нет?


Как-то раз тех поддержка тоже такое советовало, но это замедляет работу протокола. И у меня в общей сложности устройств намного больше, а 16 привел только для примера.

Кнопки только импульсные, на самом деле в алгоритме делаю, что-то наподобие самоподхвата. А читаю регистры, потому что было такое, что при изменении какого-либо бита в остальные биты записывались False (0), поэтому я начал туда записывать актуальные значения.

Я из этого понял что сигналы "ТОЛЬКО ИМПУЛЬСНЫЕ".

Если это не так - то я, например, изрядно помучившись, отказался от идеи записывать такие биты словом. Завожу отдельные битовые теги для таких целей