По сути это программная реализация двоичного дешифратора (декодера). Он преобразует двоичный код номера бита в унитарный код со значащей единицей (нулем).
В стандартной библиотеке уже есть функция FC97 «DECO» для этой цели.
FUNCTION "DECO" : DWORD
TITLE = DECO (Decode Binary Position)
AUTHOR : SEA
FAMILY : CONVERT
NAME : DECO
VERSION : 2.0
VAR_INPUT
IN : WORD;
END_VAR
VAR_TEMP
wrk : WORD;
END_VAR
BEGIN
NETWORK
TITLE =
L 1; // set default out-value
T #RET_VAL; // .
L #IN; // for(wrk = in % 32; wrk > 0; wrk--)
AD DW#16#1F; // {
L 1; // .
+I ; // .
JU A001; // .
A002:
T #wrk; // .
L #RET_VAL; // out <<= 1
SLD 1; // .
T #RET_VAL; // .
L #wrk; // }
A001:
LOOP A002; // .
SET; // set BR
SAVE; // .
END_FUNCTION
Алгоритм работы сдвигает единицу в регистре в цикле. В качестве счетчика цикла используется копия номера бита, т.е. цикл может выполниться до 32 раз. Это небыстрый алгоритм. Можно посчитать число команд, которые будут выполнены при входных аргументах 0 и 31.
- аргумент 0, 7 + 6 * 1 + 2 = 15 команд;
- аргумент 31, 7 + 6 * 32 + 2 = 201 команда;
Строго говоря две последние команды к алгоритму отношения не имеют, состояние бита ВР учитывается только в языке FBD для входа/выхода разрешения EN/ENO.
Очень быстрый алгоритм дешифратора можно получить используя STL команду распределенного перехода JL.
FUNCTION FC12: DWORD
TITLE = Установка бита по номеру
AUTHOR: Anakost
FAMILY: SOHO
NAME: NumSetBt // Number + Setting + Bit
VERSION: 1.0
VAR_INPUT
InCod: BYTE; //номер бита
END_VAR
BEGIN
NETWORK
TITLE = Распределенный переход по номеру
L #InCod; // Загрузка номера перехода в ACCU1-L-L
JL Exit; // Переход выполнится при ACCU1-L-L > 32
JU L000; // Переход выполнится при ACCU1-L-L = 0
JU L001; // Переход выполнится при ACCU1-L-L = 1
JU L002; // Переход выполнится при ACCU1-L-L = 2
JU L003; // Переход выполнится при ACCU1-L-L = 3
JU L004; // Переход выполнится при ACCU1-L-L = 4
JU L005; // Переход выполнится при ACCU1-L-L = 5
JU L006; // Переход выполнится при ACCU1-L-L = 6
JU L007; // Переход выполнится при ACCU1-L-L = 7
JU L008; // Переход выполнится при ACCU1-L-L = 8
JU L009; // Переход выполнится при ACCU1-L-L = 9
JU L010; // Переход выполнится при ACCU1-L-L = 10
JU L011; // Переход выполнится при ACCU1-L-L = 11
JU L012; // Переход выполнится при ACCU1-L-L = 12
JU L013; // Переход выполнится при ACCU1-L-L = 13
JU L014; // Переход выполнится при ACCU1-L-L = 14
JU L015; // Переход выполнится при ACCU1-L-L = 15
JU L016; // Переход выполнится при ACCU1-L-L = 16
JU L017; // Переход выполнится при ACCU1-L-L = 17
JU L018; // Переход выполнится при ACCU1-L-L = 18
JU L019; // Переход выполнится при ACCU1-L-L = 19
JU L020; // Переход выполнится при ACCU1-L-L = 20
JU L021; // Переход выполнится при ACCU1-L-L = 21
JU L022; // Переход выполнится при ACCU1-L-L = 22
JU L023; // Переход выполнится при ACCU1-L-L = 23
JU L024; // Переход выполнится при ACCU1-L-L = 24
JU L025; // Переход выполнится при ACCU1-L-L = 25
JU L026; // Переход выполнится при ACCU1-L-L = 26
JU L027; // Переход выполнится при ACCU1-L-L = 27
JU L028; // Переход выполнится при ACCU1-L-L = 28
JU L029; // Переход выполнится при ACCU1-L-L = 29
JU L030; // Переход выполнится при ACCU1-L-L = 30
JU L031; // Переход выполнится при ACCU1-L-L = 31
JU L032; // Переход выполнится при ACCU1-L-L = 32
Exit: JU Err; // Ошибочный ввод
L000: JU Err; // Ветвь кода при ACCU1-L-L = 0
L001: L DW#16#00000001; JU Out; // Ветвь кода при ACCU1-L-L = 1
L002: L DW#16#00000002; JU Out; // Ветвь кода при ACCU1-L-L = 2
L003: L DW#16#00000004; JU Out; // Ветвь кода при ACCU1-L-L = 3
L004: L DW#16#00000008; JU Out; // Ветвь кода при ACCU1-L-L = 4
L005: L DW#16#00000010; JU Out; // Ветвь кода при ACCU1-L-L = 5
L006: L DW#16#00000020; JU Out; // Ветвь кода при ACCU1-L-L = 6
L007: L DW#16#00000040; JU Out; // Ветвь кода при ACCU1-L-L = 7
L008: L DW#16#00000080; JU Out; // Ветвь кода при ACCU1-L-L = 8
L009: L DW#16#00000100; JU Out; // Ветвь кода при ACCU1-L-L = 9
L010: L DW#16#00000200; JU Out; // Ветвь кода при ACCU1-L-L = 10
L011: L DW#16#00000400; JU Out; // Ветвь кода при ACCU1-L-L = 11
L012: L DW#16#00000800; JU Out; // Ветвь кода при ACCU1-L-L = 12
L013: L DW#16#00001000; JU Out; // Ветвь кода при ACCU1-L-L = 13
L014: L DW#16#00002000; JU Out; // Ветвь кода при ACCU1-L-L = 14
L015: L DW#16#00004000; JU Out; // Ветвь кода при ACCU1-L-L = 15
L016: L DW#16#00008000; JU Out; // Ветвь кода при ACCU1-L-L = 16
L017: L DW#16#00010000; JU Out; // Ветвь кода при ACCU1-L-L = 17
L018: L DW#16#00020000; JU Out; // Ветвь кода при ACCU1-L-L = 18
L019: L DW#16#00040000; JU Out; // Ветвь кода при ACCU1-L-L = 19
L020: L DW#16#00080000; JU Out; // Ветвь кода при ACCU1-L-L = 20
L021: L DW#16#00100000; JU Out; // Ветвь кода при ACCU1-L-L = 21
L022: L DW#16#00200000; JU Out; // Ветвь кода при ACCU1-L-L = 22
L023: L DW#16#00400000; JU Out; // Ветвь кода при ACCU1-L-L = 23
L024: L DW#16#00800000; JU Out; // Ветвь кода при ACCU1-L-L = 24
L025: L DW#16#01000000; JU Out; // Ветвь кода при ACCU1-L-L = 25
L026: L DW#16#02000000; JU Out; // Ветвь кода при ACCU1-L-L = 26
L027: L DW#16#04000000; JU Out; // Ветвь кода при ACCU1-L-L = 27
L028: L DW#16#08000000; JU Out; // Ветвь кода при ACCU1-L-L = 28
L029: L DW#16#10000000; JU Out; // Ветвь кода при ACCU1-L-L = 29
L030: L DW#16#20000000; JU Out; // Ветвь кода при ACCU1-L-L = 30
L031: L DW#16#40000000; JU Out; // Ветвь кода при ACCU1-L-L = 31
L032: L DW#16#80000000; JU Out; // Ветвь кода при ACCU1-L-L = 32
Err: L DW#16#00000000; // Ошибочный ввод
Out: T #RET_VAL; // Результат
END_FUNCTION
В этом алгоритме кол-во выполняемых команд не превышает пяти для любого аргумента.
Есть не принципиальное отличие в логике работы. Библиотечная функция принимает в качестве аргумента слово WORD и при необходимости обрезает его по модулю 32 (5 значащих бит). 0 используется как значащий аргумент и устанавливает младший бит в слове.
Я написал функцию под свой алгоритм, а мне было нужно чтобы 0 и числа более 32 использовались как запрещающий сигнал на выходе.
Функция с распределенным переходом получилась настолько гибкая, что реакцию выхода на входной аргумент можно настроить как угодно. Двоичный код 0..255 можно преобразовать в унитарный, семисегментный, ASCII, Грея и т.д.
Не обошлось и без ложки дегтя, платой за универсальность и быстродействие стал гораздо больший размер функции (516 слов вместо 92).
Источник: http://we.easyelectronics.ru/plc/simatic-step-7-stl-ustanovka-sbros-bita-po-nomeru.html