Simatic Step 7. STL. Реверс бит — АСУ ТП: сообщество инженеров

Simatic Step 7. STL. Реверс бит

Под операцией реверса битов понимается отображение содержимого регистра относительно середины слова, т.е. отображение битов в слове в обратном порядке.
В языке Simatic STL такой команды нет, имеющиеся CAW, CAD реверсируют байты в слове и двойном слове, т.е. преобразуют между форматами little-endian и big-endian. В стандартной библиотеке подобной функции так же нет. Для реализации был выбран алгоритм реверсирования на основе бинарного обмена из книги Генри Уорена «Алгоритмические трюки для программистов», 2014 г.

Его реализация на С для DWORD выглядит так:

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

Это тот же алгоритм бинарного поиска (применялся для подсчета единичных бит), в котором операции сложения заменены на операции обмена. Его реализация на STL при расчетах использует только внутренние регистры:

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

Алгоритм довольно быстрый, но используя вышеупомянутую команду CAD его можно значительно упростить и убыстрить. Достаточно только отреверсить отдельные байты, т.е. две последние строчки алгоритма будут не нужны.

NETWORK
TITLE = Алгоритм бинарного обмена FastDWORD
  L #INPUT;
// x = (x & 0x55555555) <<  1 | (x & 0xAAAAAAAA) >>  1;
  PUSH;                         // копия ACCU1 в ACCU2
  AD DW#16#55555555;            // ACCU1 and 0x55555555
  SLD 1;                        // ACCU1 << 1
  TAK;                          // ACCU1 <-> ACCU2
  AD DW#16#AAAAAAAA;            // ACCU1 and 0xAAAAAAAA
  SRD 1;                        // ACCU1 >> 1
  OD;                           // ACCU1 <- ACCU1 or ACCU2
// x = (x & 0x33333333) <<  2 | (x & 0xCCCCCCCC) >>  2;
  PUSH;                         //
  AD DW#16#33333333;            //
  SLD 2;                        //
  TAK;                          //
  AD DW#16#CCCCCCCC;            //
  SRD 2;                        //
  OD;                           //
// x = (x & 0x0F0F0F0F) <<  4 | (x & 0xF0F0F0F0) >>  4;
  PUSH;                         //
  AD DW#16#0F0F0F0F;            //
  SLD 4;                        //
  TAK;                          //
  AD DW#16#F0F0F0F0;            //
  SRD 4;                        //
  OD;                           //
//-----------------------
  CAD;                          // реверс байтов в DWORD
//-----------------------
  T #OUTPUT;                    //

Реверс битов для WORD:

VAR_INPUT            
  INPUT: WORD;    
END_VAR
...
NETWORK
TITLE = Алгоритм бинарного обмена WORD
  L #INPUT;
  PUSH;
  SRW 1;
  AW W#16#5555;
  TAK;
  SLW 1;
  AW W#16#AAAA;
  OW;
  PUSH;
  SRW 2;
  AW W#16#3333;
  TAK;
  SLW 2;
  AW W#16#CCCC;
  OW;
  PUSH;
  SRW 4;
  AW W#16#0F0F;
  TAK;
  SLW 4;
  AW W#16#F0F0;
  OW;
  CAW;
  T #OUTPUT;

Реверс битов для BYTE:

VAR_INPUT            
  INPUT: BYTE;    
END_VAR
...
NETWORK
TITLE = Алгоритм бинарного обмена BYTE
  L #INPUT;
  PUSH;
  SRW 1;
  AW B#16#55;
  TAK;
  SLW 1;
  AW B#16#AA;
  OW;
  PUSH;
  SRW 2;
  AW B#16#33;
  TAK;
  SLW 2;
  AW B#16#CC;
  OW;
  PUSH;
  SRW 4;
  AW B#16#0F;
  TAK;
  SLW 4;
  AW B#16#F0;
  OW;
  T #OUTPUT;

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

🔗 Simatic Step 7. STL. Реверс бит

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

Войти

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

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

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

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