расчет контрольный суммы CRC modbus

Тема в разделе "Микроконтроллеры AVR", создана пользователем Yerabdi, 22 май 2018.

  1. Yerabdi

    Yerabdi Гик

    Здравствуйте всем как можно рассчитать контрольную сумму в модбас протоколе, заранее спасибо
     
  2. Igor68

    Igor68 Гуру

    Код (C++):
    //контрольная сумма по подсчёту
    #if (_tCRC_MRTU == 0)
    __inline u_int16_t MRTU_CRC(u_int8_t* data, ushort len)
    {
            ushort res_CRC = 0xFFFF;
            ushort count = 0;
            u_int8_t count_crc;
            u_int8_t dt;
            while(count < len)
            {
                    //
                    count_crc = 0;
                    dt = (u_int8_t)(data[count]);
                    res_CRC ^= (ushort)(dt);
                    //
                    while(count_crc < 8)
                    {
                            if((res_CRC & 0x0001) < 1)
                            {
                                    res_CRC = (res_CRC >> 1) & 0x7FFF;
                            }
                            else
                            {
                                    res_CRC = (res_CRC >> 1) & 0x7FFF;
                                    res_CRC ^= 0xA001;
                            };
                            count_crc++;
                    };
                    count++;
            }
            return (res_CRC);
    }
    #else
    __inline u_int16_t MRTU_CRC(u_int8_t *data, ushort len)
    {
        u_int8_t uchCRCHi = 0xFF;
        u_int8_t uchCRCLo = 0xFF;
        u_int16_t uIndex ;
        while(len--)
        {
            uIndex = uchCRCHi ^ *data++ ;
            uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
            uchCRCLo = auchCRCLo[uIndex] ;
        }
        return (((u_int16_t)(uchCRCLo) << 8) | (u_int16_t)(uchCRCHi));
    }
    #endif
    Если определено:
    #define _tCRC_MRTU 1
    то будет применён табличный метод с применением следующих таблиц:
    Код (C++):
    #if (_tCRC_MRTU > 0)
    /* Table of CRC values for high–order byte*/
    const u_int8_t auchCRCHi[] = {
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
    0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    0x40
    };

    /* Table of CRC values for low–order byte*/
    const u_int8_t auchCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
    0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
    0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
    0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
    0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
    0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
    0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
    0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
    0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
    0x40
    };
    #endif
    А иначе будет пересчёт простой математикой. С таблицами быстрее.
    Это для Modbus RTU
     
  3. Yerabdi

    Yerabdi Гик

     
  4. Yerabdi

    Yerabdi Гик

    Получается сверху код который ведет расчет по таблице, если это так можете более подробно описать принцип работы кода. Я пишу в атмел-студио а там пишется на Си.С уважением Yerabdi!
     
  5. Igor68

    Igor68 Гуру

    Там на Си и реализовано! функция оформлена как __inline... можете и просто так оформить (без этого слова) Разбор с таблицей не вёл (списал, как говорят). Гораздо раньше по инструкциям Modbus RTU делал простой подсчёт. Можете использовать, как есть.
    u_int16_t MRTU_CRC(u_int8_t *data, ushort len)
    *data - ссылка на массив,
    len - размер части массива, которую надо подсчитать.
    Испытано с приборами OWEN и Advantech... порты ввода-вывода, счётчиками, частотным преобразователем ПЧВ3(овен), измерителем температуры...
    Для посылки после пмассива для подсчёта ставлю контрольную сумму и посылаю в прибор. При приёме ответа подсчитываю весь массив, кроме последних двух... потому как они контрольная сумма. Ну это я так делал.
     
  6. Igor68

    Igor68 Гуру

  7. Yerabdi

    Yerabdi Гик

    Спасибо большое буду изучать, протокол хоть старый но актуальен для производственных контроллерам
     
  8. Yerabdi

    Yerabdi Гик

    Гораздо раньше вы делали простой подсчет, u_int16_t MRTU_CRC(u_int8_t *data, ushort len)
    *data - ссылка на массив,len - размер части массива, которую надо подсчитать. Получается вы не использовали таблицу или как ?
     
  9. parovoZZ

    parovoZZ Гуру

    Находишь сайт ПЛК НИЛ АП. У них на сайте находишь ПЛК на атмега. Для них там же можно скачать кучу библиотек, в том числе и Modbus RTU. Там с комментариями, с пояснительной запиской.

    Си - он и в Африке Си. На Си можно и в блокноте писать.
     
  10. Igor68

    Igor68 Гуру

    Как ранее говорил таблицы в этом файле... ну или заголовочном. Их добавил позже вместе с обновлённой функцией. А выбор варианта применения при компиляции выбирал этим:
    Код (C++):
    #if (_tCRC_MRTU == 0)
    ...без таблиц
    #else
    ...с таблицами
    #endif
     
    при этом в заголовке (или в начале файла) установив:
    Код (C++):
    #define _tCRC_MRTU   1
    если хочу откомпилить с таблицами или
    Код (C++):
    #define _tCRC_MRTU  0
    это если без таблиц.
     
  11. Yerabdi

    Yerabdi Гик

    ,
    MRTU_CRC(u_int8_t *data, ushort len) *data - это динамический массив данных который приходить в usart , ushort len - значение откуда берется
     
  12. Igor68

    Igor68 Гуру

    Вот к примеру (на пальцах):
    Код (C++):
    void func(void)
    {
        uint8_t    buf[16] = {0}; //буфер для запроса
        uint16_t  crc; //контрольная сумма
        //заполняем
        buf[0] = 0x01; //адрес устройства
        buf[1] = 0x03; //код команды(чтение регистров)
        buf[2] = 0x00; //старший байт адреса начального регистра
        buf[3] = 0x10; //младший байт адреса начального регистра
        buf[4] = 0x00; //старший байт количества регистров для чтения
        buf[5] = 0x02; //младший байт количества регистров для чтения
        crc = MRTU_CRC(&buf[0], 6); //считаем сумму - считаем сумму по заполненому
        buf[6] = (crc >> 8) & 0xFF; //сташий байт crc
        buf[7] = crc & 0xFF; //младший байт crc
       ... //данные готовы для посылки - всесте с контрольной суммой 8 байт
       ...//посылаем и т.п.
    }
       
    Простите но уже и не знаю что ещё расписать... и на каком языке.
     
  13. Yerabdi

    Yerabdi Гик

    Спасибо вам за ваше терпение и за ваш совет. Буду изучать и читать более подробно
     
    Igor68 нравится это.
  14. Yerabdi

    Yerabdi Гик

    Спасибо все заработала контрольную сумму считает и отправляет правильно связь с атмегой-328 по RS485 протоколу работает. Теперь хочу входящие данные с компьютера сохранит в массиве и обработать для оправки сообщении