Расчёт crc8

Тема в разделе "Микроконтроллеры AVR", создана пользователем a1000, 26 янв 2021.

  1. a1000

    a1000 Гуру

    Если кто знает помогите разобраться.
    Решил разобраться как считается CRC для датчика DS18B20. Согласно теории, по команде BE мы получаем из памяти датчика 9 байт, последний из которых и есть CRC, который расчитывается по образующему полиному X ^ 8 + X ^ 5 + X ^ 4 + 1. Если записать полином в шеснадцатеричном виде то это будет 0х31.
    Подключаю датчик и получаю следующую последовательность байтов
    0х92 0х01 0х4B 0x46 0x7F 0xFF 0x0C 0x10 0xB5
    Открываю онлайн калькулятор
    https://crccalc.com/
    Заганяю первые 8 байт и в строке CRC-8 / MAXIM получаем искомые 0xB5 (полином 0х31). Копал в интернете как осуществляется данная магия. Смог освоить только табличный метод. Результаты ручного расчёта совпали с полученными.
    Помогите вникнуть в магию процесса. Берём первый байт 0х92. В десятичном исчислении это 146. В таблице
    0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
    0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
    0x9D, 0xC3, 0x21, 0x7F, 0xFC, 0xA2, 0x40, 0x1E,
    0x5F, 0x01, 0xE3, 0xBD, 0x3E, 0x60, 0x82, 0xDC,
    0x23, 0x7D, 0x9F, 0xC1, 0x42, 0x1C, 0xFE, 0xA0,
    0xE1, 0xBF, 0x5D, 0x03, 0x80, 0xDE, 0x3C, 0x62,
    0xBE, 0xE0, 0x02, 0x5C, 0xDF, 0x81, 0x63, 0x3D,
    0x7C, 0x22, 0xC0, 0x9E, 0x1D, 0x43, 0xA1, 0xFF,
    0x46, 0x18, 0xFA, 0xA4, 0x27, 0x79, 0x9B, 0xC5,
    0x84, 0xDA, 0x38, 0x66, 0xE5, 0xBB, 0x59, 0x07,
    0xDB, 0x85, 0x67, 0x39, 0xBA, 0xE4, 0x06, 0x58,
    0x19, 0x47, 0xA5, 0xFB, 0x78, 0x26, 0xC4, 0x9A,
    0x65, 0x3B, 0xD9, 0x87, 0x04, 0x5A, 0xB8, 0xE6,
    0xA7, 0xF9, 0x1B, 0x45, 0xC6, 0x98, 0x7A, 0x24,
    0xF8, 0xA6, 0x44, 0x1A, 0x99, 0xC7, 0x25, 0x7B,
    0x3A, 0x64, 0x86, 0xD8, 0x5B, 0x05, 0xE7, 0xB9,
    0x8C, 0xD2, 0x30, 0x6E, 0xED, 0xB3, 0x51, 0x0F,
    0x4E, 0x10, 0xF2, 0xAC, 0x2F, 0x71, 0x93, 0xCD,
    0x11, 0x4F, 0xAD, 0xF3, 0x70, 0x2E, 0xCC, 0x92,
    0xD3, 0x8D, 0x6F, 0x31, 0xB2, 0xEC, 0x0E, 0x50,
    0xAF, 0xF1, 0x13, 0x4D, 0xCE, 0x90, 0x72, 0x2C,
    0x6D, 0x33, 0xD1, 0x8F, 0x0C, 0x52, 0xB0, 0xEE,
    0x32, 0x6C, 0x8E, 0xD0, 0x53, 0x0D, 0xEF, 0xB1,
    0xF0, 0xAE, 0x4C, 0x12, 0x91, 0xCF, 0x2D, 0x73,
    0xCA, 0x94, 0x76, 0x28, 0xAB, 0xF5, 0x17, 0x49,
    0x08, 0x56, 0xB4, 0xEA, 0x69, 0x37, 0xD5, 0x8B,
    0x57, 0x09, 0xEB, 0xB5, 0x36, 0x68, 0x8A, 0xD4,
    0x95, 0xCB, 0x29, 0x77, 0xF4, 0xAA, 0x48, 0x16,
    0xE9, 0xB7, 0x55, 0x0B, 0x88, 0xD6, 0x34, 0x6A,
    0x2B, 0x75, 0x97, 0xC9, 0x4A, 0x14, 0xF6, 0xA8,
    0x74, 0x2A, 0xC8, 0x96, 0x15, 0x4B, 0xA9, 0xF7,
    0xB6, 0xE8, 0x0A, 0x54, 0xD7, 0x89, 0x6B, 0x35
    на позиции 146 стоит 0xAD, ввожу в калькулятор 0х92 и получаю тот-же результат. Растолкуйте тупому, как из 0х92 и 0х31 получить 0хAD?
     
  2. ИгорьК

    ИгорьК Гуру

    В библиотеке OneWire есть функция расчёта crc. Я бы посмотрел исходник.
     
  3. Код (C++):

        size_t i;
        unsigned char data[] = {0x92, 0x01, 0x4B, 0x46, 0x7F, 0xFF, 0x0C, 0x10};
        unsigned char crcT = 0;
        for (i = 0; i < sizeof(data); i++) {
            crcT = tab[data[i] ^ crcT];
        }
        printf("crcT 0x%02X\n", crcT);

        unsigned short crc8 = 0;
        for (i = 0; i < sizeof(data); i++) {
            crc8 = crc8 ^ data[i];
            size_t n;
            for (n = 0; n < 8; n++) {
                if (crc8 & 0x01) {
                    crc8 = crc8 >> 1;
                    crc8 = crc8 ^ 0x8c; // 0x31=00110001b в зазеркалье он уже 10001100b=0x8c
                } else {
                    crc8 = crc8 >> 1;
                }
            }
        }
        printf("crc8 0x%02X\n", crc8);
     
    результат расчета табличный и через константу 0x31 одинаковый получился
    Код (Text):

    crcT 0xB5
    crc8 0xB5
     
    У Максима есть скромный пример расчета
     
    Последнее редактирование: 27 янв 2021
    a1000 нравится это.
  4. a1000

    a1000 Гуру

    В исходнике табличный метод. На просторах интернета нарыл такой код
    Код (C++):
    /*
      Name  : CRC-8
      Poly  : 0x31    x^8 + x^5 + x^4 + 1
      Init  : 0xFF
      Revert: false
      XorOut: 0x00
      Check : 0xF7 ("123456789")
      MaxLen: 15 байт(127 бит) - обнаружение
        одинарных, двойных, тройных и всех нечетных ошибок
    */

    unsigned char Crc8(unsigned char *pcBlock, unsigned int len)
    {
        unsigned char crc = 0xFF;
        unsigned int i;

        while (len--)
        {
            crc ^= *pcBlock++;

            for (i = 0; i < 8; i++)
                crc = crc & 0x80 ? (crc << 1) ^ 0x31 : crc << 1;
        }

        return crc;
    }
    Как я понял алгоритм следующий.
    Берём байт и смотрим на старший бит.
    Если бит равен 1 - сдвигаем его влево и делаем сложение по модулю 2 с полиномом (0х31)
    Если бит равен 0 - только слвигаем влево.
    Повторяем 8 раз.
    Проделал эту байду вручную с 0х92
    10010010 - исходное число
    проход 1 (старший бит - 1)
    00100100 - сдвиг вправо
    00010101 - XOR c 0x31
    проход 2 (старший бит - 0)
    00101010 - сдвиг влево
    проход 3 (старший бит - 0)
    01010100 - сдвиг влево
    проход 4 (старший бит - 0)
    10101000 - сдвиг влево
    проход 5 (старший бит - 1)
    01010000 - сдвиг влево
    01100001 - XOR c 0x31
    проход 6 (старший бит - 0)
    11000010 - сдвиг влево
    проход 7 (старший бит - 1)
    10000100 - сдвиг влево
    10110101 - XOR c 0x31
    проход 8 (старший бит - 1)
    01101010 - сдвиг влево
    01011011 - XOR c 0x31
    Вместо ожидаемого 0хAD получил 0х5B. Кто нибудь пробовал это осилить?
     
  5. a1000

    a1000 Гуру

    [​IMG][​IMG]
    Всё наоборот. Спасибо, проверил вручную, сошлось.