вычислить crc

rembo
Offline
Зарегистрирован: 14.11.2012

а как вычислить crc от результата получаемого с аналогового датчика?

maksim
Offline
Зарегистрирован: 12.02.2012

Никак.

Zapek@n
Offline
Зарегистрирован: 16.02.2012

А для общего развития можно поинтересоваться, а зачем?

rembo
Offline
Зарегистрирован: 14.11.2012

мне надо передать в программу данные в формате: 

4 байта – значение канала, целое число в формате PC

1 байт – контрольная сумма

maksim
Offline
Зарегистрирован: 12.02.2012

Так бы и написали, что CRC вам нужно вычислить для 4 байт передаваемой информации. А кокой должен быть CRC? Размером в один байт и меньше их вон сколько бывает:

 

CRC-1 x + 1 (используется в аппаратном контроле ошибок; также известен как бит чётности) 0x1 / 0x1 / 0x1
CRC-4-ITU x^4 + x + 1 (ITU G.704[10]) 0x3 / 0xC / 0x9
CRC-5-EPC x^5 + x^3 + 1 (Gen 2 RFID[11]) 0x09 / 0x12 / 0x14
CRC-5-ITU x^5 + x^4 + x^2 + 1 (ITU G.704[12]) 0x15 / 0x15 / 0x1A
CRC-5-USB x^5 + x^2 + 1 (USB token packets) 0x05 / 0x14 / 0x12
CRC-6-ITU x^6 + x + 1 (ITU G.704[13]) 0x03 / 0x30 / 0x21
CRC-7 x^7 + x^3 + 1 (системы телекоммуникации, ITU-T G.707[14]ITU-T G.832[15]MMCSD) 0x09 / 0x48 / 0x44
CRC-8-CCITT x^8 + x^2 + x + 1 (ATM HEC), ISDN Header Error Control and Cell Delineation ITU-T I.432.1 (02/99) 0x07 / 0xE0 / 0x83
CRC-8-Dallas/Maxim x^8 + x^5 + x^4 + 1 (1-Wire bus) 0x31 / 0x8C / 0x98
CRC-8 x^8 + x^7 + x^6 + x^4 + x^2 + 1 (ETSI EN 302 307[16], 5.1.4) 0xD5 / 0xAB / 0xEA[1]
CRC-8-SAE J1850 x^8 + x^4 + x^3 + x^2 + 1 0x1D / 0xB8 / 0x8E

 

rembo
Offline
Зарегистрирован: 14.11.2012

ну поидее то crc размером 1 байт.

maksim
Offline
Зарегистрирован: 12.02.2012

И? 
CRC-8-CCITT, CRC-8-Dallas/Maxim, CRC-8, CRC-8-SAE J1850 - все размером 1 байт.

rembo
Offline
Зарегистрирован: 14.11.2012

спасибо за дельный комментарий.

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Есть ли готовая функция для расчета CRC-1 ? А то в голову пришол только этот тупой код ....

byte val;

bool parity = !(bitRead(val,0)+bitRead(val,1)+bitRead(val,2)+bitRead(val,3)+bitRead(val,4)+bitRead(val,5)+bitRead(val,6)+bitRead(val,7))%2;

Вобщем нужна стандартная функция которая бы возвращала 1 если четное количество бит в байте и 0 если нечетное. складывать биты и делить их на 2 а потом инвертировать результат - не лучшая идея....

toc
Offline
Зарегистрирован: 09.02.2013

есть готовая функция crc32. Выдаёт 4 байта. Полученные от неё 4 байта можно сложить xor'ом и получить один байт. Гуглить arduino crc32.

Некоторые существующие способы передачи данных уже обеспечивают защиту от помех или искажения информации. Например, по радио с помощью модулей nrf24l01+.

maksim
Offline
Зарегистрирован: 12.02.2012

Если вычислять четность десятичного значения байта, то достаточно знать младший бит:

byte val;
bool parity = val & 1;

Если же именно побитово, то так:

 byte val;
 bool parity = 0;
 for(byte i; i < 8; i++) if(val&(1<<i))parity = !parity;

 

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Нужен 1 бит а не байт результирующий, вычислинный для байта. Искал что-то готовое ...

То что вы предложили тоже хорошо.

maksim
Offline
Зарегистрирован: 12.02.2012

И побитово еще так думаю можно:

byte val;
bool parity = 0;
for(byte i = 0; i < 8; i++) parity ^= val&(1<<i);

 

sva1509
Offline
Зарегистрирован: 07.12.2012

доброго времени суток !

попробуйте так :

bool crcbit(byte b)
{
byte i1 = 0;
        for(byte i2 = 0;i2 <8;i2++) {
              if (b & 1) i1++;
              b = b >> 1;
        } 
        if (i1 & 1) return(0); else return(1);
}

 

step962
Offline
Зарегистрирован: 23.05.2011

или вот так:

 #include <util/crc16.h>
 
 int sCRC;
 char b[]="Строка для которой необходимо вычислить контрольную сумму";

int getCRC(char *p) {
  int CRC;
  CRC=0;
  while(*p) {
    CRC=_crc16_update(CRC,*p); p++;
  }
  return CRC;
}
[...]
sCRC = getCRC(b);

 

maksim
Offline
Зарегистрирован: 12.02.2012

sva1509 пишет:

попробуйте так :

Не стоит, уже все придумано.

Бит чётности или контрольный разряд формируется при выполнении операции «Исключающее-ИЛИ» поразрядно. 

http://ru.wikipedia.org/wiki/%D0%91%D0%B8%D1%82_%D1%87%D1%91%D1%82%D0%BD%D0%BE%D1%81%D1%82%D0%B8

 

maksim
Offline
Зарегистрирован: 12.02.2012

step962 пишет:

или вот так:

Полезно, но CRC16 к биту четности отношения не имеет.

step962
Offline
Зарегистрирован: 23.05.2011

Название темы - "вычислить crc"

QQEVSKIY
Offline
Зарегистрирован: 12.02.2014

maksim пишет:

Так бы и написали, что CRC вам нужно вычислить для 4 байт передаваемой информации. А кокой должен быть CRC? Размером в один байт и меньше их вон сколько бывает:

 

как понять в таблице правый столбец, если можно с примером?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Прикольно... Бит четности и есть простейшая контрольная сумма,  усеченная до одного младшего бита. Складываете все данные, отщепляете от результата последний бит, он и будет простейшей контрольной суммой. Можно по другому , например подсчитать количество нечетных байт, и при нечетном их числе контрольный бит будет 1, в других случаях 0. Думаю можно придумать еще уйму способов расчета, например с использованием исключающего или.

Adno
Offline
Зарегистрирован: 21.09.2012

Функция из библиотеки Modbus

/*
CRC

INPUTS:
buf -> Array containing message to be sent to controller.
start -> Start of loop in crc counter, usually 0.
cnt -> Amount of bytes in message being sent to controller/
OUTPUTS:
temp -> Returns crc byte for message.
COMMENTS:
This routine calculates the crc high and low byte of a message.
Note that this crc is only used for Modbus, not Modbus+ etc.
****************************************************************************/

unsigned int crc(unsigned char *buf, unsigned char start,
unsigned char cnt)
{
unsigned char i, j;
unsigned temp, temp2, flag;

temp = 0xFFFF;

for (i = start; i < cnt; i++) {
temp = temp ^ buf[i];

for (j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp = temp >> 1;
if (flag)
temp = temp ^ 0xA001;
}
}

/* Reverse byte order. */
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;

return (temp);
}

QQEVSKIY
Offline
Зарегистрирован: 12.02.2014

так что за значения в правом столбце таблицы ?

Adno
Offline
Зарегистрирован: 21.09.2012

8 ? )

maksim
Offline
Зарегистрирован: 12.02.2012
ourlive
Offline
Зарегистрирован: 26.05.2012

Ничегошеньки я что то в этом не понял (ну тоесть понял только общий смысл и только).

Конкретно на примере покажите как посчитать crc-8 dallas, для конфигурации MLX90614-DCI (датчик температуры) в комментариях примера кода конфигурации запись:

//For PEC Calculation have a look at : http://smbus.org/faq/crc8Applet.htm
//In this case the PEC calculates from 250000 (=0x83)

По ссылке ошибка явы, не считается соответственно. Для установки параметров датчика в него нужно слать <адрес>, <младший байт данных>, <старший байт данных> и <контрольная сумма>, т.е. 4 байта всего. Как из указанных <25><00><00> получить <83> или аналогично <21><5B><4F><59>?

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

Зубер
Offline
Зарегистрирован: 07.03.2014

Алгоритм расчета взят из описания modbus  (CRC для modbus RTU и  LRC для modbus ASCII):

----------URL MODBUS---------

1.3.1.CRC-16 (Cyclic Redundancy Check)

Сообщение (только биты данных, без учета старт/стоповых бит и бит четности)
рассматриваются как одно последовательное двоичное число, у которого старший значащий
бит(MSB) передается первым. Сообщение умножается на Х16 (сдвигается влево на 16 бит), а
затем делится на Х16+Х15+Х2+1, выражаемое как двоичное число (11000000000000101). Целая
часть результата игнорируется, а 16-ти битный остаток (предварительно
инициализированный единицами для предотвращения случая, когда все сообщение состоит
из нулей) добавляется к сообщению (старшим битом вперед) как два байта контрольной
суммы. Полученное сообщение, включающее CRC, затем в приемнике делится на тот же
полином (Х16+Х15+Х2+1). Если ошибок не было, остаток от деления должен получится
нулевым.(Приемное устройство может рассчитать CRC и сравнить ее с переданной). Вся
арифметика выполняется по модулю 2 (без переноса).
Устройство, используемое для подготовки данных для передачи, посылает условно
самый правый (LSB) бит каждого символа первым. При расчете CRC, первый передаваемый
бит, определен как MSB делимого. Так как арифметика не использует перенос, для удобства
расчета CRC можно предположить, что MSB расположен справа. Поэтому порядок бит при
расчете полинома должен быть реверсивным. MSB полинома опускается, так как он влияет
только на делитель, а не на остаток. В результате получается 1010 0000 0000 0001 (А001Н).
Заметьте, что эта реверсивность порядка бит, в любом случае, не влияет на интерпретацию
или порядок бит байт данных при вычислении CRC.

Пошаговая процедура расчета CRC-16 представлена ниже:

1. Загрузить 16-ти разрядный регистр числом FFFFH.
2. Выполнить операцию XOR над первым байтом данных и старшим байтом
регистра.
Поместить результат в регистр.
3. Сдвинуть регистр на один разряд вправо.
4. Если выдвинутый вправо бит единица, выполнить операцию XOR между
регистром и полиномом 1010 0000 0000 0001 (А001Н).
5. Если выдвинутый бит ноль, вернуться в шагу 3.
6. Повторять шаги 3 и 4 до тех пор, пока не будут выполнены 8 сдвигов регистра.
7. Выполнить операцию XOR над следующим байтом данных и регистром.
8. Повторять шаги 3-7 до тех пор, пока не будут выполнена операция XOR над
всеми байтами данных и регистром.
9. Содержимое регистра представляет собой два байта CRC и добавляется к
исходному сообщению старшим битом вперед.

Таблица 2

Пример расчета CRC для сообщения - чтение статуса SL с номером 02
16-ти разрядный регистр MSB Флаг

Исключающее
ИЛИ
1111 1111 1111 1111
02 0000 0010
1111 1111 1111 1101
Сдвиг 1 0111 1111 1111 1110 1
Полином 1010 0000 0000 0001
1101 1111 1111 1111
Сдвиг 2 0110 1111 1111 1111 1
Полином 1010 0000 0000 0001
1100 1111 1111 1110
Сдвиг 3 0110 0111 1111 1111
Сдвиг 4 0011 0011 1111 1111 1
Полином 1010 0000 0000 0001
1001 0011 1111 1110
Сдвиг 5 0100 1001 1111 1111
16-ти разрядный регистр MSB Флаг
Сдвиг 6 0010 0100 1111 1111 1
Полином 1010 0000 0000 0001
1000 0100 1111 1110
Сдвиг 7 0100 0010 0111 1111
Сдвиг 8 0010 0001 0011 1111 1
Полином 1010 0000 0000 0001
1000 0001 0011 1110
07 0000 0111
1000 0001 0011 1001
Сдвиг 1 0100 0000 1001 1100 1
Полином 1010 0000 0000 0001
1110 0000 1001 1101
Сдвиг 2 0111 0000 0100 1110 1
Полином 1010 0000 0000 0001
1101 0000 0100 1111
Сдвиг 3 0110 1000 0010 0111 1
Полином 1010 0000 0000 0001
1100 1000 0010 0110
Сдвиг 4 0110 0100 0001 0011
Сдвиг 5 0011 0010 0000 1001 1
Полином 1010 0000 0000 0001
1001 0010 0000 1000
Сдвиг 6 0100 1001 0000 0100
Сдвиг 7 0010 0100 1000 0010
Сдвиг 8 0001 0010 0100 0001
HEX 12 HEX 41

Передаваемое сообщение с контрольной суммой CRC-16

(При передаче сообщение выдвигается вправо)
12 41 07 02
0001 0010 0100 0001 0000 0111 0000 0010

Последний бит Порядок передачи Первый бит

-----------------
1.3.2. LRC(1.3.2. LRC(Longitudinal Redundancy Check)

Контрольная сумма в режиме ASCII это LRC. Контрольная сумма - это 8-ми разрядное
число, передаваемое как два ASCII символа (hex). Контрольная сумма образуется путем
конвертирования всех hex символов в двоичные числа, сложением этих чисел без учета
переноса, и вычислением дополнительного кода полученного числа. В приемнике LRC
заново рассчитывается и сравнивается с полученным LRC. При вычислении LRC двоеточие,
CR, LF и любой другой не-ASCII символ отбрасывается.

Таблица 3

Пример расчета LRC для сообщения - чтение первых 8-ми булевых ячеек SL с
номером 02

Адрес 0 2 0000 0010
Функция 0 1 0000 0001

Адрес первой ячейки (HIGH) 0 0 0000 0000

Адрес первой ячейки(LOW) 0 0 0000 0000

Число ячеек(HIGH) 0 0 0000 0000

Число ячеек(LOW) 0 8 + 0000 1000
0000 1011

Инверсия
1111 0100
+1 1
1111 0101
Контрольная сумма F 5 F 5
Приемное устройство складывает все
байты данных, включая LRC. Сумма может
превышать 8 бит, в расчет принимаются
только младшие 8 бит.

ОК
К.сумма
Сумма
0000
0000
0000
0000
0000
0000
1111
0000
0010
0001
0000
0000
0000
1000
0101
0000

Как было отмечено в введении, протокол описывает правила связи между MS и SL.

Протокол Modbus разбит по типу коммуникаций, используемых в промышленных сетях. В
общем, интерпретация полей в сообщении идентична для режимов передачи ASCII и
RTU.(См. рис. 1-4 и 1-5).

Главное отличие заключается в типе проверки контрольной суммы,
выполняемой над сообщением, и которое в два раза больше в режиме ASCII. Вместо
передачи 80ми разрядного двоичного символа, посылается эквивалент в виде пары 7-ми
разрядных ASCII (0-9,A-F) символов.

ourlive
Offline
Зарегистрирован: 26.05.2012

Спасибо конечно, но такой пример вкуривать дольше и сложнее, чем первоисточники на аглицком вычитать. crc-16 как бы в два раза длиннее crc-8, единственное что из него понятно: что то нужно инвертировать и куда то двигать.

"Пример расчета CRC для сообщения - чтение статуса SL с номером 02 16-ти разрядный регистр MSB Флаг" на этом я умер, извините... Разрушенное форматирование таблиц не облегчает понимания.

Зубер
Offline
Зарегистрирован: 07.03.2014

ourlive пишет:
Спасибо конечно, но такой пример вкуривать дольше и сложнее, чем первоисточники на аглицком вычитать. crc-16 как бы в два раза длиннее crc-8, единственное что из него понятно: что то нужно инвертировать и куда то двигать.

Разрушенное форматирование таблиц не облегчает понимания.

http://elektrokip.narod.ru/19.doc

 

maksim
Offline
Зарегистрирован: 12.02.2012

ourlive пишет:

Ничегошеньки я что то в этом не понял (ну тоесть понял только общий смысл и только).

Конкретно на примере покажите как посчитать crc-8 dallas, для конфигурации MLX90614-DCI (датчик температуры) в комментариях примера кода конфигурации запись:

//For PEC Calculation have a look at : http://smbus.org/faq/crc8Applet.htm
//In this case the PEC calculates from 250000 (=0x83)

По ссылке ошибка явы, не считается соответственно. Для установки параметров датчика в него нужно слать <адрес>, <младший байт данных>, <старший байт данных> и <контрольная сумма>, т.е. 4 байта всего. Как из указанных <25><00><00> получить <83> или аналогично <21><5B><4F><59>?

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

Если вы пользуетесь библиотекой 1-Wire, то в ней уже это реализовано, причем двумя способами.

   побыстрее:

// This table comes from Dallas sample code where it is freely reusable,
// though Copyright (C) 2000 Dallas Semiconductor Corporation
static const uint8_t PROGMEM dscrc_table[] = {
      0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
    157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,
     35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,
    190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
     70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,
    219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,
    101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,
    248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,
    140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
     17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
    175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
     50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
    202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,
     87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
    233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
    116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};

//
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers.  (note: this might better be done without to
// table, it would probably be smaller and certainly fast enough
// compared to all those delayMicrosecond() calls.  But I got
// confused, so I use this table from the examples.)
//
uint8_t OneWire::crc8( uint8_t *addr, uint8_t len)
{
	uint8_t crc = 0;

	while (len--) {
		crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
	}
	return crc;
}

   и помедленнее:

// Compute a Dallas Semiconductor 8 bit CRC directly.
// this is much slower, but much smaller, than the lookup table.
//
uint8_t OneWire::crc8( uint8_t *addr, uint8_t len)
{
	uint8_t crc = 0;
	
	while (len--) {
		uint8_t inbyte = *addr++;
		for (uint8_t i = 8; i; i--) {
			uint8_t mix = (crc ^ inbyte) & 0x01;
			crc >>= 1;
			if (mix) crc ^= 0x8C;
			inbyte >>= 1;
		}
	}
	return crc;
}

 

QQEVSKIY
Offline
Зарегистрирован: 12.02.2014

maksim пишет:
Если вы пользуетесь библиотекой 1-Wire, то в ней уже это реализовано, причем двумя способами.

 

для СRC-16 есть такое же ?

maksim
Offline
Зарегистрирован: 12.02.2012

Да, но только один вариант - помедленнее:

bool OneWire::check_crc16(uint8_t* input, uint16_t len, uint8_t* inverted_crc)
{
    uint16_t crc = ~crc16(input, len);
    return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
}

uint16_t OneWire::crc16(uint8_t* input, uint16_t len)
{
    static const uint8_t oddparity[16] =
        { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
    uint16_t crc = 0;    // Starting seed is zero.

    for (uint16_t i = 0 ; i < len ; i++) {
      // Even though we're just copying a byte from the input,
      // we'll be doing 16-bit computation with it.
      uint16_t cdata = input[i];
      cdata = (cdata ^ (crc & 0xff)) & 0xff;
      crc >>= 8;

      if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
          crc ^= 0xC001;

      cdata <<= 6;
      crc ^= cdata;
      cdata <<= 1;
      crc ^= cdata;
    }
    return crc;
}

 

ourlive
Offline
Зарегистрирован: 26.05.2012

maksim: Не 1-wire, указанный датчик цепляется по i2c и прилагаемую библиотеку. Запись осуществляется EEPROM датчика всего один раз под конкретное использование (переписывать можно, но без надобности). Т.е. для этого прилагался отдельный скетч. Собираю вот это. Но с попыткой подробно разобраться как оно работает. Затык возник с теорией. Потому и прошу показать не код, не книжные примеры, а конкретный расчёт на конкретных данных.

---

добавлю, перебрал кучу калькуляторов, но не один из них не выдаёт ожидаемые данные уже вписанные в образцовый скетч из примера. Скетч приводить не буду, длинная лента с побайтовой записью обзазца: <записать в указанные ячейки нули>, <записань в указанные ячейки новые данные>, <прочитать новые данные из eeprom и сверить их с ожидаемыми>.

В результате то конечно можно всё это и через стандартную 1-wire библиотеку делать, но готовая библиотека понимания "как оно работает" не даёт.

QQEVSKIY
Offline
Зарегистрирован: 12.02.2014

maksim пишет:
Да, но только один вариант - помедленнее:

а в чем вкратце суть короткого варианта - таблица с перебором каких-то значений?

сколько должно быть комбинаций для CRC-8 (больше 256 и повторяются ?) CRC-16 и как определяется это количество?