реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> CRC16(ModBus) на С для ATmega128, помогите разобраться
sf9
сообщение Sep 17 2008, 07:38
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 35
Регистрация: 30-10-07
Из: Москва
Пользователь №: 31 896



Всем доброе время суток!
Прошу помочь мне разобраться в С коде.Сам только недавно начал осваивать.
нужно реализовать CRC16 для ModBus.
Я знаю,что есть куча готовых реализаций.Простым(последовательным) и табличным способом.
Но хочу реализовать сам.
У меня проблема в том,что для вычисления CRC нужно смотреть на состояние младшого бита. Если "1" - то выполнять XOR,если нет,то крутить дальше.

Вот мой код:

int crc16 (unsigned char a) // a - 8-bit data for calculation CRC
{
unsigned int reg, tmp;
int i;

reg = 0xFFFF; // step1: initial loading of 16-bit register
reg ^= (unsigned int)a; // step2: a XOR reg

for(i = 0;i<8;i++) //step3: 8-iteration to calculate CRC
{
reg >>= 1;
tmp = reg;
tmp <<= 15;
if(tmp == 0x8000) reg ^= 0xA001; // checking: if LSB = "1" reg=reg^0xA001
}
return reg;
}

проверку я выолняю поразрядным сдвигом 16-битного reg влево, и, если там "1",то xor.

ниже преведена другая реализация CRC16 и она работет корректно!!!!

int crc16 (unsigned char a)
{
unsigned int reg;
unsigned char i, tmp;

reg = 0xFFFF;
reg ^= (unsigned int)a;
for(i = 0;i<8;i++)
{
tmp = (unsigned char)(reg&0x0001);
reg >>= 1;
if(tmp) reg ^= 0xA001;
}
return reg;
}

Поясните,что не так в первой реализачии. smile3046.gif
Go to the top of the page
 
+Quote Post
Sat360
сообщение Sep 17 2008, 07:46
Сообщение #2


Участник
*

Группа: Свой
Сообщений: 26
Регистрация: 26-02-08
Из: Томск
Пользователь №: 35 391



В первой реализации регистр сдвигается ДО анализа бита. Следовательно, младший бит теряется.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 17 2008, 07:55
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



В работающей программе сначала запоминается младший бит, потом делается сдвиг вправо (при этом в сдвинутом числе этот бит уже потерян). Вы же сначала сдвигаете вправо, потом делаете проверку. Т.е. проверяете не младший, а следующий бит. Ваш сдвиг влево на 15 разрядов не нужен:
Код
    tmp <<= 15;
    if(tmp == 0x8000)
эквивалентно
    if(tmp & 1)
Этот код более красиво можно записать так:
Код
int crc16 (uinsigned int crc, unsigned char a)         // a - 8-bit data for calculation CRC
{
            int i;
    
    crc ^= (unsigned int)a;    // step2: a XOR reg
    
    for(i = 0;i<8;i++)           //step3: 8-iteration to calculate CRC  
    {
        if(crc & 1)
        {
            crc >>= 1; reg ^= 0xA001;
        }
        else
        {
            crc >>= 1;
        }
    }
    return crc;
}
Обратите внимание, что 0xFFFF заносится в crc один раз перед обсчетом всего массива.

P.S. В форме ввода сообщения есть кнопочка для оформления кода. Она обозначена символом "#". Используйте ее, пожалуйста, при публикации кода. Иначе портится форматирование и ваш исходник становится трудночитаемым.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
sf9
сообщение Sep 17 2008, 08:30
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 35
Регистрация: 30-10-07
Из: Москва
Пользователь №: 31 896



СПАСИБО ОГРОМНОЕ!!! a14.gif
Я понял,просто дело в том,что я не соблюдал порядок выполнения кода.
Свой корявый вариант я подправил:
Код
int crc16 (unsigned char a)
{
    unsigned int reg,tmp;
    unsigned int i;
    
    reg = 0xFFFF;                 
    reg ^= (unsigned int)a;    
    
    for(i = 0;i<8;i++)
    {
        tmp = reg;
        reg >>= 1;        
        if((tmp <<=15)==0x8000) reg ^= 0xA001;
    }
    return reg;
}


А если с Вашими комментариями получилось расчудесно:
Код
        if((tmp <<=15)==0x8000) reg ^= 0xA001;
меняем на
        if(tmp&1) reg ^= 0xA001;


И ещё хотел бы узнать,как можно напрямую обращаться к биту в байте на языке С?
??

Сообщение отредактировал sf9 - Sep 17 2008, 08:31
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 17 2008, 08:52
Сообщение #5


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



А меня вот последнее время поперло по-другому CRC16 для модбаса считать. Оптимизированно под IAR AVR (чтобы все в регистрах было)
Код
__z UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i64, UREG i128, UREG i1, UREG i192);

UREG CRC16(UINT8 *puchMsg, UREG usDataLen, UREG write )
{
  return CRC16stage2(0xFF,0xFF,usDataLen,write,puchMsg,64,128,1,192);
}

#pragma optimize=no_inline
__z UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i64, UREG i128, UREG i1, UREG i192)
{
  do
  {
    UINT8 parity;
    UINT16 tmp16;
    parity=(uchCRCLo ^= *puchMsg++);
    uchCRCLo=uchCRCHi;
    tmp16=__multiply_unsigned(parity,i64);
    uchCRCHi=tmp16>>8;
    uchCRCLo^=tmp16;
    tmp16=__multiply_unsigned(parity,i128);
    uchCRCHi^=tmp16>>8;
    uchCRCLo^=tmp16;
    parity^=__swap_nibbles(parity);
    parity^=parity>>1;
    if (!(parity & 4)) parity--;
    if (!(parity&1))
    {
      uchCRCLo^=i1;
      uchCRCHi^=i192;
    }
  }
  while(--l);
  if (write)
  {
    *puchMsg++=uchCRCLo;
    *puchMsg++=uchCRCHi;
  }
  else
  {
    UREG k;
    if ((k=*puchMsg++-uchCRCLo)) return k;
    return *puchMsg++-uchCRCHi;
  }
  return 0;  
}


и результат
Код
        RSEG CODE:CODE:NOROOT(1)
//   74 UREG CRC16(UINT8 *puchMsg, UREG usDataLen, UREG write )
CRC16:
//   75 {
        MOVW    R31:R30, R17:R16
//   76   return CRC16stage2(0xFF,0xFF,usDataLen,write,puchMsg,64,128,1,192);
        LDI     R23, 192
        LDI     R22, 1
        LDI     R21, 128
        LDI     R20, 64
        LDI     R17, 255
        LDI     R16, 255
        REQUIRE CRC16stage2
       ;               // Fall through to label CRC16stage2
//   77 }
//   78
//   79 #pragma optimize=no_inline

        RSEG CODE:CODE:NOROOT(1)
//   80 __z UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i64, UREG i128, UREG i1, UREG i192)
CRC16stage2:
//   81 {
        ST      -Y, R24
        MOV     R3, R16
        MOV     R2, R17
        MOV     R24, R22
//   82   do
//   83   {
//   84     UINT8 parity;
//   85     UINT16 tmp16;
//   86     parity=(uchCRCLo ^= *puchMsg++);
??CRC16stage2_0:
        LD      R16, Z+
        EOR     R3, R16
        MOV     R22, R3
//   87     uchCRCLo=uchCRCHi;
        MOV     R3, R2
//   88     tmp16=__multiply_unsigned(parity,i64);
        MUL     R22, R20
//   89     uchCRCHi=tmp16>>8;
        MOV     R2, R1
//   90     uchCRCLo^=tmp16;
        EOR     R3, R0
//   91     tmp16=__multiply_unsigned(parity,i128);
        MUL     R22, R21
//   92     uchCRCHi^=tmp16>>8;
        EOR     R2, R1
//   93     uchCRCLo^=tmp16;
        EOR     R3, R0
//   94     parity^=__swap_nibbles(parity);
        MOV     R16, R22
        SWAP    R16
        EOR     R22, R16
//   95     parity^=parity>>1;
        MOV     R16, R22
        LSR     R16
        EOR     R22, R16
//   96     if (!(parity & 4)) parity--;
        BST     R22, 2
        BRTS    ??CRC16stage2_1
        DEC     R22
//   97     if (!(parity&1))
??CRC16stage2_1:
        BST     R22, 0
        BRTS    ??CRC16stage2_2
//   98     {
//   99       uchCRCLo^=i1;
        EOR     R3, R24
//  100       uchCRCHi^=i192;
        EOR     R2, R23
//  101     }
//  102   }
//  103   while(--l);
??CRC16stage2_2:
        DEC     R18
        BRNE    ??CRC16stage2_0
//  104   if (write)
        TST     R19
        BREQ    ??CRC16stage2_3
//  105   {
//  106     *puchMsg++=uchCRCLo;
        ST      Z+, R3
//  107     *puchMsg++=uchCRCHi;
        ST      Z, R2
//  108   }
//  109   else
//  110   {
//  111     UREG k;
//  112     if ((k=*puchMsg++-uchCRCLo)) return k;
//  113     return *puchMsg++-uchCRCHi;
//  114   }
//  115   return 0;  
        LDI     R16, 0
        RJMP    ??CRC16stage2_4
??CRC16stage2_3:
        LD      R16, Z+
        SUB     R16, R3
        BRNE    ??CRC16stage2_4
        LD      R16, Z
        SUB     R16, R2
??CRC16stage2_4:
        LD      R24, Y+
        RET
//  116 }


Итого - 29 тактов на байт. И без всяких таблиц.

Кстати, вариант
Код
__x UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i64, UREG i128, UREG i1, UREG i192);

__x UREG CRC16(UINT8 *puchMsg, UREG usDataLen, UREG write )
{
  return CRC16stage2(0xFF,0xFF,usDataLen,write,puchMsg,64,128,1,192);
}

#pragma optimize=no_inline
__x UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i64, UREG i128, UREG i1, UREG i192)
...

сохранит 1 байт CSTACK, но может ухудшить верхний код.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sf9
сообщение Sep 17 2008, 09:15
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 35
Регистрация: 30-10-07
Из: Москва
Пользователь №: 31 896



Кстати,в компиляторах и САПРах для МСs как можно подсчитать кол-во тактов,оптимизацию и пр.?
В частности,AVRstudio???????


Сообщение отредактировал sf9 - Sep 17 2008, 09:16
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 17 2008, 09:29
Сообщение #7


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Никак. Только ручками. Ну или в симуляторе выполнить код и посмотреть.

А вот "подсчитать оптимизацию" - это Вы что имели в виду?


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sf9
сообщение Sep 17 2008, 09:43
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 35
Регистрация: 30-10-07
Из: Москва
Пользователь №: 31 896



Цитата(Rst7 @ Sep 17 2008, 13:29) *
Никак. Только ручками. Ну или в симуляторе выполнить код и посмотреть.

А вот "подсчитать оптимизацию" - это Вы что имели в виду?


Согласен,некорректно выразился.
Хотел спросить следующее:"Есть ли настройки в компиляторах или САПРах для МК,которые позволяют оптимизировать проект в той или иной области - памяти программ или данных?"
Или всё же только ручками?
smile3046.gif
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 17 2008, 09:50
Сообщение #9


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Есть ли настройки в компиляторах или САПРах для МК,которые позволяют оптимизировать проект


Ну обычно говорят не САПР, а среда разработки. Но то не суть.

У всех вменяемых компиляторов есть возможность настройки уровня и типа оптимизации. Как для всего проекта, так и для отдельных функций (например в моем примере #pragma optimize=no_inline - это для того, чтобы функция никогда не включалась во внутрь другой).

Кроме того, зная особенности поведения компилятора, можно помочь ему руками - написав соответствующий код, но тут только опыт поможет wink.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sf9
сообщение Sep 17 2008, 10:04
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 35
Регистрация: 30-10-07
Из: Москва
Пользователь №: 31 896



07.gif
Спасибо большое!
Побрёл я наращивать головные мышцы.И извилины развивать.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Sep 17 2008, 10:29
Сообщение #11


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Rst7 @ Sep 17 2008, 11:52) *
А меня вот последнее время поперло по-другому CRC16 для модбаса считать. Оптимизированно под IAR AVR (чтобы все в регистрах было)
У avr-gcc в util/crc16.h есть под несколько разных полиномов такие быстрые алгоритмы в виде асм-вставок для добавления к crc одного байта, хорошо вставляются внутрь своего цикла.
А у альтеры апнота была на тему fast crc calculation, где разрисовано красиво откуда ноги растут у такой оптимизации и по той апноте можно сделать для любого полинома.



Цитата(ReAl @ Sep 17 2008, 13:07) *
У avr-gcc в util/crc16.h есть под несколько разных полиномов такие быстрые алгоритмы в виде асм-вставок для добавления к crc одного байта, хорошо вставляются внутрь своего цикла.
Хм.. там сдвиги не умножением сделаны, а впрямую, но всё равно в зависимости от полинома уже находящийся в регистре байт добавляется к находящейся на регистрах CRC за 17..25 тактов в зависимости от полинома. В цикле будет плюс загрузка очередного байта и организация цикла, в итоге по времени выйдет на приблизительно то же, что и с умножением. Но будет работать и на мелких кристаллах.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
singlskv
сообщение Sep 17 2008, 17:43
Сообщение #12


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(ReAl @ Sep 17 2008, 14:29) *
У avr-gcc в util/crc16.h есть под несколько разных полиномов такие быстрые алгоритмы в виде асм-вставок для добавления к crc одного байта, хорошо вставляются внутрь своего цикла.
Хм.. там сдвиги не умножением сделаны, а впрямую, но всё равно в зависимости от полинома уже находящийся в регистре байт добавляется к находящейся на регистрах CRC за 17..25 тактов в зависимости от полинома.

+1 Оптимальнее чем в avr-gcc для crc16 и не сделать, поэтому всегда пользуюсь встроенным...
Go to the top of the page
 
+Quote Post
sf9
сообщение Sep 18 2008, 09:52
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 35
Регистрация: 30-10-07
Из: Москва
Пользователь №: 31 896



По поводу crc16.h абсолютно согласен,вчера проверял,тестировал,всё работает быстрее,чем другие реализации. Ну и,естественно,удобно. wink.gif
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 18 2008, 11:42
Сообщение #14


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
+1 Оптимальнее чем в avr-gcc для crc16 и не сделать


Не кажи "гоп" wink.gif

Код
__z UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i128,UREG i1, UREG i192);

UREG CRC16(UINT8 *puchMsg, UREG usDataLen, UREG write )
{
  return CRC16stage2(0xFF,0xFF,usDataLen,write,puchMsg,128,1,192);
}

#pragma optimize=no_inline
__z UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i128, UREG i1, UREG i192)
{
  do
  {
    UINT8 parity;
    UINT16 tmp16;
    parity=*puchMsg++;
    parity^=uchCRCLo;
    uchCRCLo=uchCRCHi;
    tmp16=__multiply_unsigned(parity,i128);
    uchCRCHi=tmp16>>8;
    uchCRCLo^=tmp16;
    tmp16>>=1;
    uchCRCHi^=tmp16>>8;
    uchCRCLo^=tmp16;
    parity^=tmp16>>8;
    parity^=parity>>1;
    parity^=__swap_nibbles(parity);
    if (parity&1)
    {
      uchCRCLo^=i1;
      uchCRCHi^=i192;
    }
  }
  while(--l);
  if (write)
  {
    *puchMsg++=uchCRCLo;
    *puchMsg++=uchCRCHi;
  }
  else
  {
    UREG k;
    if ((k=*puchMsg++-uchCRCLo)) return k;
    return *puchMsg++-uchCRCHi;
  }
  return 0;  
}


Код
        RSEG CODE:CODE:NOROOT(1)
//   74 UREG CRC16(UINT8 *puchMsg, UREG usDataLen, UREG write )
CRC16:
//   75 {
        MOVW    R31:R30, R17:R16
//   76   return CRC16stage2(0xFF,0xFF,usDataLen,write,puchMsg,128,1,192);
        LDI     R22, 192
        LDI     R21, 1
        LDI     R20, 128
        LDI     R17, 255
        LDI     R16, 255
        REQUIRE CRC16stage2
       ;               // Fall through to label CRC16stage2
//   77 }
//   78
//   79 #pragma optimize=no_inline

        RSEG CODE:CODE:NOROOT(1)
//   80 __z UREG CRC16stage2(UINT8 uchCRCLo, UINT8 uchCRCHi, UREG l, UREG write, UINT8 *puchMsg, UREG i128, UREG i1, UREG i192)
CRC16stage2:
//   81 {
        MOV     R2, R16
        MOV     R23, R17
//   82   do
//   83   {
//   84     UINT8 parity;
//   85     UINT16 tmp16;
//   86     parity=*puchMsg++;
??CRC16stage2_0:
        LD      R3, Z+
//   87     parity^=uchCRCLo;
        EOR     R3, R2
//   88     uchCRCLo=uchCRCHi;
        MOV     R2, R23
//   89     tmp16=__multiply_unsigned(parity,i128);
        MUL     R3, R20
//   90     uchCRCHi=tmp16>>8;
        MOV     R23, R1
//   91     uchCRCLo^=tmp16;
        EOR     R2, R0
//   92     tmp16>>=1;
        LSR     R1
        ROR     R0
        EOR     R23, R1
//   93     uchCRCHi^=tmp16>>8;
//   94     uchCRCLo^=tmp16;
        EOR     R2, R0
//   95     parity^=tmp16>>8;
        EOR     R3, R1
//   96     parity^=parity>>1;
        MOV     R16, R3
        LSR     R16
        EOR     R3, R16
//   97     parity^=__swap_nibbles(parity);
        MOV     R16, R3
        SWAP    R16
        EOR     R3, R16
//   98     if (parity&1)
        BST     R3, 0
        BRTC    ??CRC16stage2_1
//   99     {
//  100       uchCRCLo^=i1;
        EOR     R2, R21
//  101       uchCRCHi^=i192;
        EOR     R23, R22
//  102     }
//  103   }
//  104   while(--l);
??CRC16stage2_1:
        DEC     R18
        BRNE    ??CRC16stage2_0
//  105   if (write)
        TST     R19
        BREQ    ??CRC16stage2_2
//  106   {
//  107     *puchMsg++=uchCRCLo;
        ST      Z+, R2
//  108     *puchMsg++=uchCRCHi;
        ST      Z, R23
//  109   }
//  110   else
//  111   {
//  112     UREG k;
//  113     if ((k=*puchMsg++-uchCRCLo)) return k;
//  114     return *puchMsg++-uchCRCHi;
//  115   }
//  116   return 0;  
        LDI     R16, 0
        RET
??CRC16stage2_2:
        LD      R16, Z+
        SUB     R16, R2
        BRNE    ??CRC16stage2_3
        LD      R16, Z
        SUB     R16, R23
??CRC16stage2_3:
        RET
//  117 }


20.5 тактов против 23 на собственно расчет следующего значения CRC16.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
singlskv
сообщение Sep 18 2008, 20:25
Сообщение #15


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Rst7 @ Sep 18 2008, 15:42) *
Не кажи "гоп" wink.gif
Ok, согласен
умножение здесь рулит...
Только в любом случае в предыдущем варианте было хуже чем в winavr...
Ну и еще, этот вариант просто непременим в winavr, поэтому никогда и не задумывался
об улучшении с 23 тактов...

а в чистом асм возможно 1-2 такта можно было-бы еще выиграть, но нужно много думать...
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 18:59
Рейтинг@Mail.ru


Страница сгенерированна за 0.01515 секунд с 7
ELECTRONIX ©2004-2016