Simatic Step 7. STL. Подсчет установленных бит. — АСУ ТП: сообщество инженеров

Simatic Step 7. STL. Подсчет установленных бит.

Коротко о статье

Статья о подсчёте количества единичных бит в аргументе на языке STL для Simatic Step 7. Приведены готовая функция FC99 «BITSUM» из стандартной библиотеки и реализации алгоритма бинарного поиска для DWORD, WORD и BYTE, включая оптимизированный вариант.

Главное
  • Функция возвращает число установленных единичных бит в аргументе, это значение также называют весом Хемминга.
  • По возвращаемому значению можно определить чётность аргумента по нулевому биту.
  • В стандартной библиотеке уже имеется функция FC99 «BITSUM», реализующая последовательный перебор бит в цикле.
  • Переборный алгоритм не самый быстрый; одним из самых быстрых считается алгоритм бинарного поиска.
  • Для DWORD приведена реализация FC10 на STL, использующая только внутренние регистры.
  • Для WORD и BYTE алгоритм упрощается за счёт сокращения числа шагов.
  • В книге Генри Уорена 2014 года описан более оптимизированный вариант бинарного поиска и его код на STL.
Термины и технологии
  • STL
  • FC99 «BITSUM»
  • DWORD
  • WORD
  • BYTE
  • FC10

Кому полезно: Инженерам АСУ ТП, программирующим ПЛК Simatic на STL

По теме на сайте

Выжимка составлена редакцией сайта с помощью ИИ по тексту статьи.

Эта функция возвращает кол-во установленных (единичных) бит в аргументе. Иногда возвращаемое значение называют весом Хемминга. Кроме самостоятельной ценности, по возвращаемому значению функции легко определить четность аргумента (нулевой бит).

В стандартной библиотеке уже есть функция FC99 «BITSUM» для этой цели.

FUNCTION "BITSUM" : INT
TITLE = BITSUM (Sum Number of Bits)
AUTHOR : SEA
FAMILY : CONVERT
NAME : BITSUM
VERSION : 2.0
VAR_INPUT
  IN : DWORD ;  
END_VAR
VAR_TEMP
  wrkVal : DWORD ;      
END_VAR
BEGIN
NETWORK
TITLE =
  L     0;              // set default RET_VAL
  T     #RET_VAL;       // .
  L     #IN;            // for(wrk = in; wrk <> 0; wrk >>= 1)
  T     #wrkVal;        // {
A001:
  L     0;              //   if(wrk == 0) break;
  L     #wrkVal;        //   .
  ==D   ;               //   .
  JC    A002;           //   .
  SRD   1;              //   wrk >>= 1
  T     #wrkVal;        //   .
  JZ    A001;           //   if(LSB == 0) continue;
  L     #RET_VAL;       //   RET_VAL++
  L     1;              //   .
  +I    ;               //   .
  T     #RET_VAL;       //   .
  JU    A001;           // }
A002:
  SET   ;               // set BR
  SAVE  ;               //
 
END_FUNCTION

Алгоритм работы основан на последовательном переборе бит в цикле с подсчетом установленных. Это не самый быстрый алгоритм.
Одним из самых быстрых считается алгоритм бинарного поиска, его реализация на С:

  x = (x & 0x55555555) + (x & 0xAAAAAAAA) >> 1;
  x = (x & 0x33333333) + (x & 0xCCCCCCCC) >> 2;
  x = (x & 0x0F0F0F0F) + (x & 0xF0F0F0F0) >> 4;
  x = (x & 0x00FF00FF) + (x & 0xFF00FF00) >> 8;
  x = (x & 0x0000FFFF) + (x & 0xFFFF0000) >> 16;

Его реализация на STL при расчетах использует только внутренние регистры:

FUNCTION FC10: VOID     
TITLE = "Подсчет кол-ва единичных бит"
AUTHOR:   Anakost       // 
FAMILY:   SOHO          //
NAME:     BitTotal      //  
VERSION:  1.0           //
VAR_INPUT            
  INPUT: DWORD;    
END_VAR
VAR_OUTPUT            
  OUTPUT: BYTE;
END_VAR
BEGIN
NETWORK
TITLE = Алгоритм бинарного поиска для DWORD
  L #INPUT;
// x = (x & 0x55555555) + (x & 0xAAAAAAAA) >> 1;
  PUSH;                 // копия ACCU1 в ACCU2
  AD DW#16#55555555;    // ACCU1 and 0x55555555
  TAK;                  // ACCU1 <-> ACCU2
  AD DW#16#AAAAAAAA;    // ACCU1 and 0xAAAAAAAA
  SRD 1;                // ACCU1 >> 1
  +D;                   // ACCU1 <- ACCU1 + ACCU2
// x = (x & 0x33333333) + (x & 0xCCCCCCCC) >> 2;
  PUSH;                 //
  AD DW#16#33333333;    //
  TAK;                  //
  AD DW#16#CCCCCCCC;    //
  SRD 2;                //
  +D;                   //
// x = (x & 0x0F0F0F0F) + (x & 0xF0F0F0F0) >> 4;
  PUSH;                 //
  AD DW#16#0F0F0F0F;    //
  TAK;                  //
  AD DW#16#F0F0F0F0;    //
  SRD 4;                //
  +D;                   //
// x = (x & 0x00FF00FF) + (x & 0xFF00FF00) >> 8;
  PUSH;                 //
  AD DW#16#00FF00FF;    //
  TAK;                  //
  AD DW#16#FF00FF00;    //
  SRD 8;                //
  +D;                   //
// x = (x & 0x0000FFFF) + (x & 0xFFFF0000) >> 16;
  PUSH;                 //
  AD DW#16#0000FFFF;    //
  TAK;                  //
  AD DW#16#FFFF0000;    //
  SRD 16;               //
  +D;                   //
//-----------------------
  T #OUTPUT;            //
 
END_FUNCTION

Если входная величина ограничена словом WORD, алгоритм можно упростить (не нужна последняя строчка):

VAR_INPUT            
  INPUT: WORD;    
END_VAR
...
NETWORK
TITLE = Алгоритм бинарного поиска для WORD
  L #INPUT;
// x = (x & 0x5555) + (x & 0xAAAA) >> 1;
  PUSH;                 // копия ACCU1 в ACCU2
  AW W#16#5555;         // ACCU1 and 0x5555
  TAK;                  // ACCU1 <-> ACCU2
  AW W#16#AAAA;         // ACCU1 and 0xAAAA
  SRW 1;                // ACCU1 >> 1
  +I;                   // ACCU1 <- ACCU1 + ACCU2
// x = (x & 0x3333) + (x & 0xCCCC) >> 2;
  PUSH;                 //
  AW W#16#3333;         //
  TAK;                  //
  AW W#16#CCCC;         //
  SRW 2;                //
  +I;                   //
// x = (x & 0x0F0F) + (x & 0xF0F0) >> 4;
  PUSH;                 //
  AW W#16#0F0F;         //
  TAK;                  //
  AW W#16#F0F0;         //
  SRW 4;                //
  +I;                   //
// x = (x & 0x00FF) + (x & 0xFF00) >> 8;
  PUSH;                 //
  AW W#16#00FF;         //
  TAK;                  //
  AW W#16#FF00;         //
  SRW 8;                //
  +I;                   //
//-----------------
  T #OUTPUT;            //

Если же входная величина ограничена BYTE, можно убрать еще одну строчку:

VAR_INPUT            
  INPUT: BYTE;    
END_VAR
...
NETWORK
TITLE = Алгоритм бинарного поиска для BYTE
  L #INPUT;
// x = (x & 0x55) + (x & 0xAA) >> 1;
  PUSH;             // копия ACCU1 в ACCU2
  AW B#16#55;       // ACCU1 and 0x55
  TAK;              // ACCU1 <-> ACCU2
  AW B#16#AA;       // ACCU1 and 0xAA
  SRW 1;            // ACCU1 >> 1
  +I;               // ACCU1 <- ACCU1 + ACCU2
// x = (x & 0x33) + (x & 0xCC) >> 2;
  PUSH;             //
  AW B#16#33;       //
  TAK;              //
  AW B#16#CC;       //
  SRW 2;            //
  +I;               //
// x = (x & 0x0F) + (x & 0xF0) >> 4;
  PUSH;             //
  AW B#16#0F;       //
  TAK;              //
  AW B#16#F0;       //
  SRW 4;            //
  +I;               //
//-----------------
  T #OUTPUT;        //

P.S. В книге Генри Уорена «Алгоритмические трюки для программистов», 2014 г. приведен более оптимизированный вариант алгоритма бинарного поиска:

  x = x - ((x >> 1) & 0x55555555);
  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  x = (x + (x >> 4)) & 0x0F0F0F0F;
  x = x + (x >> 8);
  x = (x + (x >> 16)) & 0x0000003F;

Соответствующий ему код на STL:

FUNCTION FC10: VOID     
TITLE = "Подсчет кол-ва единичных бит"
AUTHOR:   Anakost       // 
FAMILY:   SOHO          //
NAME:     BitTotal      //  
VERSION:  1.0           //
VAR_INPUT            
  INPUT: DWORD;    
END_VAR
VAR_OUTPUT            
  OUTPUT: BYTE;
END_VAR
BEGIN
NETWORK
TITLE = Алгоритм бинарного поиска FastDWORD
  L #INPUT;
// x = x - ((x >> 1) & 0x55555555);
  PUSH;                 //
  SRD 1;                //
  AD DW#16#55555555;    //
  -D;                   //
// x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  PUSH;                 //
  SRD 2;                //
  AD DW#16#33333333;    //
  TAK;                  //
  AD DW#16#33333333;    //
  +D;                   //
// x = (x + (x >> 4)) & 0x0F0F0F0F;
  PUSH;                 //
  SRD 4;                //
  +D;                   //
  AD DW#16#0F0F0F0F;    //
// x = x + (x >> 8);
  PUSH;                 //
  SRD 8;                //
  +D;                   //
// x = (x + (x >> 16)) & 0x0000003F;
  PUSH;                 //
  SRD 16;               //
  +D;                   //
  AD DW#16#0000003F;    //
//-----------------
  T #OUTPUT;            //
 
END_FUNCTION

Источник: http://we.easyelectronics.ru/plc/simatic-step-7-stl-podschet-ustanovlennyh-bit.html

🔗 Simatic Step 7. STL. Подсчет установленных бит.

Оставьте комментарий

Войти

Зарегистрироваться

Сбросить пароль

Пожалуйста, введите ваше имя пользователя или эл. адрес, вы получите письмо со ссылкой для сброса пароля.

Прокрутить вверх