Перейти к содержанию
    

Ещё один метод расчёта CRC16

Статья на хабре: Простой и эффективный расчёт Modbus CRC16 в ПЛК и МК без побитового сдвига и таблиц

Я добавил в комментариях к статье реализацию на c# для полинома 0xA001, который используется в Modbus.

Тема на форуме dxdy: Ещё один способ расчёта CRC16

Там я добавил исходник на c# для полинома 0x1021. Для него алгоритм расчёта немного отличается. Есть небольшие комментарии с описанием как это работает.

Думается, что здесь более подходящее место для этой темы.

Без таблицы, без сдвигов (для 0x1021, c#):

public static byte[] Crc16( byte[] bytes )
{
    int hi = 0xFF, lo = 0xFF;

    foreach ( var b in bytes )
    {
        var t = ( byte ) ( lo ^ b );

        lo = hi; 
        hi = t;

        if ( ( hi & 0x80 ) != 0 ) { hi ^= 0x08; lo ^= 0x10; }
        if ( ( hi & 0x40 ) != 0 ) { hi ^= 0x04; lo ^= 0x08; }
        if ( ( hi & 0x20 ) != 0 ) { hi ^= 0x02; lo ^= 0x04; }
        if ( ( hi & 0x10 ) != 0 ) { hi ^= 0x01; lo ^= 0x02; }
        if ( ( hi & 0x08 ) != 0 ) { hi ^= 0x00; lo ^= 0x81; }
        if ( ( hi & 0x04 ) != 0 ) { hi ^= 0x80; lo ^= 0x40; }
        if ( ( hi & 0x02 ) != 0 ) { hi ^= 0x40; lo ^= 0x20; }
        if ( ( hi & 0x01 ) != 0 ) { hi ^= 0x20; lo ^= 0x10; }
    }

    return new [] { ( byte ) lo, ( byte ) hi };
}


 

Изменено пользователем uni
Сделал акценты :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А результаты сравнения по скорости на какой-нибудь архитектуре типа Cortex-Mx будут?

На мой взгляд, этот способ не быстрее табличного. И, возможно, даже не быстрее алгоритма на сдвигах.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

шо то мне подсказывает, что это таже таблица, только постоянно вычисляемая.

Да и что за фобия по сдвигам, этож не порт (морской) и контейнеры.

  if ( ( hi & 0x80 ) != 0 ) { hi ^= 0x08; lo ^= 0x10; }

если уж работаем с битами, то более оптимальная запись будет

  if ( hi & 0x80 ) { hi ^= 0x08; lo ^= 0x10; }

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это я для c# в таком виде написал. На C там короче можно сделать, думается. Я просто следовал описанию автора в статье на хабре, чтобы код был узнаваем. Сравнить можно, табличные есть в сети. Я себе для avr8 архитектуры хотел. Для неё сделаю сравнение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, uni said:

Это я для c# в таком виде написал. На C там короче можно сделать, думается. Я просто следовал описанию автора в статье на хабре, чтобы код был узнаваем. Сравнить можно, табличные есть в сети. Я себе для avr8 архитектуры хотел. Для неё сделаю сравнение.

:biggrin: здесь для узнавамости лучше использовать C(++) & ASM

В большинстве микроконтроллеров присутствует аппаратный узел расчета CRC, в различных вариантах настроек/полиномов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, в Arduino я аппаратного crc не нашёл. А так, люблю перфекционизм :) Кому-то может пригодится, пусть не для мк современного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, uni said:

Ну, в Arduino я аппаратного crc не нашёл. А так, люблю перфекционизм :) Кому-то может пригодится, пусть не для мк современного.

Ну, да, алгоритм интересный, хотя за многие годы у меня CRC ни разу не оказалась "виновной" в снижении/затыке по быстродействию. Время просчета объема данных всегда жестко определено. С перфекционизмом сложно. Ему надо искать правильное применение. Например если уж надо считать CRC из C# - вызывать готовые системные вызовы API или низкоуровневый оптимизированный код из своего DLL (на C/ASM).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 minutes ago, uni said:

Статья на хабре

Этот алгоритм приводили здесь на форуме ещё десять лет назад: OutputLogic.

Он описан на Verilog'е, но сути это не меняет..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Смешно. Не удивительно, что тут этот алгоритм не описан. Там, правда, есть варианты под названием "оптимизированный". А то, что ноги из железа растут, это и так понятно.
Себе для avr такты посчитаю, если таблицу победит, то вырежу её нафик :) глаза мозолит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 minutes ago, uni said:

Себе для avr такты посчитаю, если таблицу победит, то вырежу её нафик :) глаза мозолит.

Операция if() крайне затратна для процессоров с длинным конвейером. Но для avr это, конечно, не проблема.. ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, k155la3 said:

если уж работаем с битами, то более оптимальная запись будет


  if ( hi & 0x80 ) { hi ^= 0x08; lo ^= 0x10; }

 

"более оптимальная"?

Так это кому как удобнее читать свои исходиники, для компилятора без разницы ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я там c# подчеркнул на всякий случай, т.к. народ начал ошибки выдавать за оптимизацию. В c# такая "оптимизация" не катит, поэтому так и написано. Мне быстрее код на c# проверить, чем под C собирать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

36 минут назад, blackfin сказал:

Операция if() крайне затратна для процессоров с длинным конвейером. Но для avr это, конечно, не проблема.. ;)

Учитывая количество команд в цикле, эти условные переходы сожрут все, как казалось бы, сэкономленные такты.

Да и время выполнения цикла здесь зависит от самого набора данных... Короче, не выигрывает тот код табличный расчет:smile:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот все говорят о некой оптимальности этого архаичного CRC16, однако, никто не уточняет о каком потоке данных идет речь? Сколько кБ в сек?

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему же не уточняет? Нужно лишь пройти по первой ссылке. Там ясно написано: для ПЛК и МК. Если заглянуть в статью, то указывается конкретно 0xA001 полином, который используется в Modbus протоколе. Всё ясно как день :)
Мне лично хочется посмотреть ассемблерный листинг для архитектуры AVR8 в 4-х случаях: для полиномов 0xA001 и 0x1021 в случае нахождения таблицы во флеш или в ОЗУ. Думается разница будет :)
Применение: avr и modbus, avr и simintech (0x1021 используется там в отладочном протоколе).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...