реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3  
Reply to this topicStart new topic
> CRC16 для modbus, не повторяйте ошибок
ReAl
сообщение Oct 17 2008, 21:33
Сообщение #31


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(demiurg_spb @ Oct 10 2008, 22:58) *
Подтвердите Ваши слова на практике:
0x01
0x6C
0x08
0xC6 - СrcL
0x0C - СrcH
В этом случае от перемены мест слагаемых (СrcL<->СrcH) сумма не меняется и никогда не равна 0.
Что-то мне кажется, что где-то вкралась ошибка.
buf2[] = { 0x01, 0x6C, 0x08, 0x0C, 0xC6 };
приведенным Вами же исходником (цитатой из модбаса?)
crc = crc16_1(buf2, sizeof(buf2));
даёт нулевую CRC.
Это если ещё и в поток давать инверсию от рассчитанной CRC, то тогда независимо от содержимого блока при правильной CRC рассчёт CRC для блока вместе с той инвертированной CRC даст константу, не равную нулю (т.е. проверять CRC от всего надо не на нуль, а на константу, 0x01B0 для приведенной crc16_1() ).


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Oct 18 2008, 05:48
Сообщение #32


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



crc16_1 - "неправильная" функция из доки на modbus, она даёт результат в big-endian формате.
Цитата(ReAl @ Oct 18 2008, 01:33) *
Это если ещё и в поток давать инверсию от рассчитанной CRC, то тогда независимо от содержимого блока при правильной CRC рассчёт CRC для блока вместе с той инвертированной CRC даст константу, не равную нулю (т.е. проверять CRC от всего надо не на нуль, а на константу, 0x01B0 для приведенной crc16_1() ).

Вы меня окончательно запутали что на что надо проверятьsmile.gif
Я хотел понять как получить 0 в данном конкретном случае и наконец понял.
В протоколе сказано, что приёмник должен посчитать CRC посылки без учёта последних двух байт и сравнить их с принятой crc, подсчитанной передатчиком (последние два байта посылки).

О инверсиях и нулях в данном мануале речи не ведётся.

Цитата(ReAl @ Oct 18 2008, 01:33) *
Что-то мне кажется, что где-то вкралась ошибка.

Сделал как Вы предлагаете: считать CRC для всей посылки.

Действительно было непонимание, а сайчас получилось, что CRC для всей последовательности байт (с учётом двух байт CRC) = 0.
Так даже проще, но несколько дольше, чем предлагается в описании протокола modbus,
т.к. длиннее на 2 байта.

ReAl, спасибо за помощь!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
ReAl
сообщение Oct 18 2008, 07:22
Сообщение #33


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(demiurg_spb @ Oct 18 2008, 08:48) *
crc16_1 - "неправильная" функция из доки на modbus, она даёт результат в big-endian формате.

Это ничего не меняет - я привёл уже последовательнсть байт, а нуль остаётся нулём и при перестановке байт.
big-endian-ность crc16_1() приводит только к тому, что в конце формирования буфера приходится написать
Код
    *ptr++ = (uint8_t)((crc) >> 8);
    *ptr = (uint8_t)crc;
а не
Код
    *ptr++ = (uint8_t)crc;
    *ptr = (uint8_t)((crc) >> 8);


Цитата(demiurg_spb @ Oct 18 2008, 08:48) *
Вы меня окончательно запутали что на что надо проверятьsmile.gif
Если бы в конце CRC "от crc16_1()" заносилась так:
Код
    *ptr++ = (uint8_t) ~((crc) >> 8);
    *ptr  = (uint8_t) ~crc;
и если бы на приёме прогонять через crc16_1() и данные, и контрольный код, как "в случае с нулём" выше, то результат выходил бы не всегда 0x0000, а всегда 0x01B0, что есть остатком от деления 0xFFFF на полином CRC (с учётом endian-ности crc16_1() ). Записывая в последние два байта инверсию CRC мы добавляем это к остатку от деления всего "полинома сообщения" на CRC и таким образом получаем (CRC ^ ~CRC) = 0xFFFF. Потом на приёме мы вместо сравнения полученной CRC с инверсией двух последних байт обрабатываем на два байта больше и получаем эту константу 0x01B0.

Но это так, к слову, просто тут было упомянуто, что в некоторых случаях в поток заносится не CRC, а инверсия, ну так в этом случае в конце будет не 0 :-).


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Oct 18 2008, 07:33
Сообщение #34


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(ReAl @ Oct 18 2008, 11:22) *
Но это так, к слову, просто тут было упомянуто, что в некоторых случаях в поток заносится не CRC, а инверсия, ну так в этом случае в конце будет не 0 :-).

Как я понял, случаи бывают разныеsmile.gif
Осталось только узнать в чём практическая польза этого трюка?


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 18 2008, 10:40
Сообщение #35


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(demiurg_spb @ Oct 18 2008, 10:33) *
Осталось только узнать в чём практическая польза этого трюка?
Принят ошибочный пакет, состоящий из одних нулей. Без применения инверсии CRC сойдется и придется делать дополнительную проверку на ноль содержимого всего пакета для отлова именно этого конкретного случая, а при использовании инверсии проверка не даст ожидаемую константу и пакет будет отброшен уже на стадии проверки CRC.

Польза от инициализации начального значения отличной от нуля константой: Если таки действительно пакет из одних нулей может присутствовать в обмене, то в случае инициализации нулем потеря части этих нулей или вкрапление лишних из-за ошибок синхронизации никак не отразится на CRC. В случае инициализации константой CRC уже не сойдется.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
singlskv
сообщение Oct 18 2008, 20:02
Сообщение #36


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(demiurg_spb @ Oct 10 2008, 23:58) *
Подтвердите Ваши слова на практике:

Цитата
Вы меня окончательно запутали что на что надо проверять
Я хотел понять как получить 0 в данном конкретном случае и наконец понял.
В протоколе сказано, что приёмник должен посчитать CRC посылки без учёта последних двух байт и сравнить их с принятой crc, подсчитанной передатчиком (последние два байта посылки).

Чего-то Вы в итоге похоже сами напутали.

Возьмем последовательность вот от сюда:
http://www.simplymodbus.ca/FC15.htm
и возмем такой код:
Код
#include <util/crc16.h>

/* Типа пример!

Force Multiple Coils (FC=15)

Request

This command is writing the contents of a series of 10 discrete coils from #20 to #29
to the slave device with address 17.

11 0F 0013 000A 02 CD01 BF0B

11: The Slave Address (17 = 11 hex)
0F: The Function Code (Force Multiple Coil, 15 = 0F hex)
0013: The Data Address of the first coil. (coil# 20 - 1 = 19 = 13 hex)
000A: The number of coils to written (10 = 0A hex)
02: The number of data bytes to follow (10 Coils / 8 bits per byte = 2 bytes)
CD: Coils 20 - 27 (1100 1101)  
01: Coils 27 - 29 (0000 0001)  
BF0B: The CRC (cyclic redundancy check) for error checking.
*/

unsigned char buff[11] = {
  0x11, 0x0F, 0x00, 0x13, 0x00, 0x0A, 0x02, 0xCD, 0x01, 0xBF, 0x0B
};

volatile unsigned short CRC = 0xFFFF;
volatile unsigned short CRC1;

int main(void)
{
  unsigned char i;

  for (i = 0; i < 9; i++)
  {
    CRC = _crc16_update(CRC, buff[i]);
  }
  
  CRC1 = CRC;

  asm("nop");    // <-------- вот здесь CRC1 == 0x0BBF

  CRC = _crc16_update(CRC, buff[9]);
  CRC = _crc16_update(CRC, buff[10]);

  asm("nop");   // <--------- вот здесь CRC == 0

  while (1);
  return 0;
}

То есть при формировании пакета с CRC мы должны сначала положить CRCLo == 0xBF,
затем CRCHi == 0x0B.
Полный CRC пакета дает 0.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Oct 19 2008, 09:39
Сообщение #37


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(singlskv @ Oct 19 2008, 00:02) *
Чего-то Вы в итоге похоже сами напутали.
То есть при формировании пакета с CRC мы должны сначала положить CRCLo == 0xBF,
затем CRCHi == 0x0B.
Полный CRC пакета дает 0.

Всё правильно. Я уже со всем разобрался.
Спасибо.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th June 2025 - 01:36
Рейтинг@Mail.ru


Страница сгенерированна за 0.01434 секунд с 7
ELECTRONIX ©2004-2016