CRC16

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
Оформи код соответствующим тэгом
Здравствуйте, не могу разобраться как реализовать в скетче расчет CRC16 по заданной функции.
Функции для вычисления CRC16:

#define _u8 unsigned char
#define _u16 unsigned short

_u16 crcTable [256];
//--------------------------------------------------------------------------------------------------------------------------
void MakeCRC16Table()
{
_u16 r;
int s, s1;
for(s = 0; s < 256; s++)
{
r = ((_u16)s)<<8;
for (s1 = 0; s1 < 8; s1++)
{
if (r&(1<<15))
r = (r<<1)^0x8005;
else
r = r<<1;
}
crcTable = r;
}
}
//--------------------------------------------------------------------------------------------------------------------------
_u16 GetCRC16(const _u8 *buf, _u16 len)
{
_u16 crc;
crc = 0xFFFF;
while (len--)
{
crc = crcTable [((crc>>8)^*buf++)&0xFF] ^ (crc<<8);
}
crc ^= 0xFFFF;
return crc;
}
имеем на входе
uint8_t data[] = {0x01, 0x64, 0x00, 0x00, 0x00, 0x06, 0x43, 0x4F, 0xC4, 0xD8, 0x5E, 0x01};
crc должно получиться
uint8_t data2[] = {0x9D 0x3C};
Помогите разобраться как это реализовать в скетче, буду признателен за помощь.
 

bort707

★★★★★★✩
21 Сен 2020
3,250
948
А что тут реализовывать, это же готовый код на Си, бери и пользуйся. Только в процедуре MakeCRC16Table, по-моему, ошибка.
 
  • Лойс +1
Реакции: poty

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
Ошибки там не может быть, так как функция скопирована из описания протокола, я не понимаю как именно пользоваться этой функцией, раньше с CRC не сталкивался. как именно в скетче имея массив data[] получить его crc?
 

poty

★★★★★★✩
19 Фев 2020
3,520
998
И тем не менее @bort707 прав. crcTable - это массив, обращаться к нему с использованием [].
Чтобы получить CRC нужно в функцию GetCRC16 передать первым параметром массив, а вторым - его длину. Функция возвратит 16 битное число, которое Вы должны самостоятельно разделить на байты и записать в Ваш массив.
 

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
Такой вариант не компилируется
uint16_t data2 = GetCRC16(data, sizeof(data));
наверное потому что длина не в том формате.
 

bort707

★★★★★★✩
21 Сен 2020
3,250
948
Ошибки там не может быть, так как функция скопирована из описания протокола
скорее всего ошиблись при копировании, потеряли скобки. Или ошибка в описании. Даже не ошибка, а скорее опечатка, так как ошибка совершенно очевидная.

Такой вариант не компилируется
покажите сообщение об ошибке компиляции .

вы ошибку то в функции исправили? Может на нее и ругается?
 
Изменено:

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
Покажите где скобки не хватает, я не врубаюсь? Сейчас компилятор не ругается , но выводит что то не то
uint16_t data2 = GetCRC16(data, sizeof(data));
Serial.println(data2, HEX);
 

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
да, опечатка видимо. В мануале так и есть.

В описании протокола есть рабочие примеры пакетов,
Формат пакета:



Заголовок 1 (4 байта)​
Тело пакета
Длина Тела пакета
(2 байта)
Максимум - 255
CRC16
Тела пакета
(2 байта)
Тип пакета
(1 байт)
Данные
(от 0 до 254 байт)

0x0C 0x00 0x9D 0x3C 0x01 0x64 0x00 0x00 0x00 0x06 0x43 0x4F 0xC4 0xD8 0x5E 0x01
Это рабочая команда, и нее следует, что CRC 0x9D 0x3C
 

bort707

★★★★★★✩
21 Сен 2020
3,250
948
Разве crc должна быть в начале пакета? Контрольная сумма всегда самы последние байты, в вашем случае 0x5E 0x01. И еще не забывайте, что crc считается НЕ ВКЛЮЧАЯ байтов самой суммы.
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,910
618
45
@Dmitry1988, Ну, если это именно для этого написанного варианта, то ок.
Но знайте, что у CRC16 есть с дюжину различных алгоритмов, и нет гарантии что этот подойдет к другому используемому CRC встроенной библиотеки (или аппаратной реализации) на другом устройстве (ESP, STM и т.п.). Тогда придется переносить этот алгоритм на другое устройство для совместимости.
 

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
Тут crc идет 3 и 4 байтом

@Геннадий П, В том то и проблема, что есть удобная библиотека Crc16.h но то что она выдает не подходит для этого протокола. Поэтому нужно реализовать именно эту функцию
 

bort707

★★★★★★✩
21 Сен 2020
3,250
948
Тут crc идет 3 и 4 байтом
ок,
Вопрос - что именно вы передавали в функцию как массив дата?
Передавать нужно только часть пакета начиная с пятого байта, так как в описании написано, CRC считается только от тела пакета

И еще, обратите внимание на порядок байт, crc в этом примере не 0x9D 0x3C, а 0x3C 0x9D
 

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
@bort707, да, так и есть с пятого байта

я думаю проблема в синтаксисе или формате данных, так как
uint16_t data2 = GetCRC16(data, sizeof(data));
Serial.println(data2, HEX);
выдает FFFF
 

bort707

★★★★★★✩
21 Сен 2020
3,250
948
@Dmitry1988, взял ваш код - для этого примера у меня выдало 0x3C 0x9D, ищите ошибку у себя.
Вы таблицу-то не забыли предварительно вычислить?
 

Dmitry1988

✩✩✩✩✩✩✩
13 Апр 2022
8
0
@bort707, таблицу я не вычислял, не знаю как. поделитесь кодом, пожалуйста и закроем тему
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,910
618
45
Либо GetCRC16() чуть модифицировать, вставить в начале функции:
C++:
if (!tableMaked) {
    MakeCRC16Table();
    tableMaked = 1;
}
И вначале кода:
_u8 tableMaked;

Тогда при первом вызове GetCRC16() будет происходить вычисление таблицы.
 

Deeily

✩✩✩✩✩✩✩
27 Июл 2022
1
1
Большое спасибо, тоже столкнулся с такой же проблемой. Ответ нашел только тут.
Прикрепляю готовый код для ардуино для сопроблемников:)

C++:
// C++ code
//

#define u8 unsigned char
#define u16 unsigned short

u16 crcTable [256];
byte message[] = {0x03, 0x01};    //тело пакета для вычисления crc16

void MakeCRC16Table()
{
u16 r;
int s, s1;
for(s = 0; s < 256; s++)
{
r = ((u16)s)<<8;
for (s1 = 0; s1 < 8; s1++)
{
if (r&(1<<15))
r = (r<<1)^0x8005;
else
r = r<<1;
}
crcTable[s] = r;
}
}

u16 GetCRC16(const u8 *buf, u16 len)
{
u16 crc;
crc = 0xFFFF;
while (len--)
{
crc = crcTable [((crc>>8)^*buf++)&0xFF] ^ (crc<<8);
}
crc ^= 0xFFFF;
return crc;
}

void setup()
{
  MakeCRC16Table();
  Serial.begin(115200);
}

void loop()
{
Serial.println (GetCRC16(message,sizeof(message)),HEX);  //получаем CRC16 в виде hex
}
 
  • Лойс +1
Реакции: Almost

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,458
988
59
Марий-Эл
Вот калькулятор CRC. Как видим, нужно 5 параметров для подсчёта CRC.
Многие протоколы использующие подсчёт CRC имеют жёстко зашитый Образующий многочлен, Начальное и Конечное Значение и инвертирование.
Что бы посчитать CRC правильно, нужно знать какие константы используются в данном протоколе.
Так что задача не совсем тривиальна.
 

Вложения