PDA

Просмотр полной версии : Modbus RTU CRC16 полином A001h



vojt
17.01.2010, 02:52
Доброе время суток!
Помогите разобраться с контрольной суммой. Я планирую использовать библиотеку UNM. Для того чтобы послать запрос с контрольной суммой нужно ее сначала вычислить . В документации есть пример на Си:

CRC – код циклического контроля
Контрольная сумма (CRC16) представляет собой циклический проверочный код на основе полинома A001h. Передающее устройство формирует контрольную сумму для всех байт передаваемого сообщения. Принимающее устройство аналогичным образом формирует контрольную сумму для всех байт принятого сообщения и сравнивает ее с контрольной суммой, принятой от передающего устройства. При несовпадении сформированной и принятой контрольных сумм генерируется сообщение об ошибке.
Поле контрольной суммы занимает два байта. Контрольная сумма в сообщении передается младшим байтом вперед.
Контрольная сумма формируется по следующему алгоритму:
1) загрузка CRC регистра (16 бит) единицами (FFFFh);
2) исключающее ИЛИ с первыми 8 битами байта сообщения и содержимым CRC регистра;
3) сдвиг результата на один бит вправо;
4) если сдвигаемый бит = 1, исключающее ИЛИ содержимого регистра со значением A001h;
5) если сдвигаемый бит = 0, повторить шаг 3;
6) повторять шаги 3, 4, 5, пока не будут выполнены 8 сдвигов;
7) исключающее ИЛИ со следующими 8 битами байта сообщения и содержимым CRC регистра;
8) повторять шаги 3 – 7, пока все байты сообщения не будут обработаны;
9) конечное содержимое регистра будет содержать контрольную сумму.

Пример программы CRC генерации кода с использованием языка С. Функция берет
два аргумента:
Unsigned char* data <- a pointer to the message buffer
Unsigned char length <- the quantity of bytes in the message buffer

The function returns the CRC value as a type of unsigned integer.
Unsigned int crc_chk(unsigned char* data, unsigned char length)
{int j;
unsigned int reg_crc=0xFFFF;
while(length--)
{
reg_crc ^= *data++;
for(j=0;j<8;j++)
{
if(reg_crc & 0х01) reg_crc=(reg_crc>>1) ^ 0xA001; // LSB(b0)=1
else reg_crc=reg_crc>>1;
}
}
return reg_crc;
}

Может у кого есть пример вычисления СRC16 на ST ?

Jeck
17.01.2010, 21:13
FUNCTION_BLOCK CRC
(*Процедура подсчета CRC*)
(*
(C) by Jeck 2009
*)


VAR_INPUT
INPUT:ARRAY [0..1023] OF BYTE; (*входной буфер*)
sz: DWORD;(*длина буфера*)
END_VAR
VAR_OUTPUT
CRC16: WORD;
END_VAR
VAR
B: INT;
N: INT;
C: BOOL;
END_VAR

________________________________


CRC16:=16#FFFF;
B:=0;
N:=0;
REPEAT
CRC16:= CRC16 XOR BYTE_TO_WORD(INPUT[B]);
N:=0;
REPEAT
C:=CRC16.0;
CRC16:=SHR(CRC16,1);
IF C THEN
CRC16:= CRC16 XOR 16#A001;
END_IF
N:=N+1;
UNTIL
N>7
END_REPEAT
B:=B+1;
UNTIL
B>sz
END_REPEAT

vojt
24.01.2010, 17:16
Спасибо всем за помощь! В первом примере удалось немного понять нюансы между Си и ST но полностю работоспособность этого примера я так и не проверил. А второй пример Jecka мне кажется проще и практически работает без проблем, вычисленная контрольная сума совпадает с примерами посылок в тех.док. Правда CRC16 выводится в виде десятичного значения и я калькуляторм перевел в шестнадцатиричный, а фактически мне нужно выделить младший и старший байт и прикрепить в конце посылки младшим байтом вперед. Пока есть другое задание и не хватает времени, но завершить эту задачу обязательно надо.

Jeck
24.01.2010, 17:20
Crc16_l.0:=crc16.0;
Crc16_l.1:=crc16.1;
Crc16_l.2:=crc16.2;
Crc16_l.3:=crc16.3;
Crc16_l.4:=crc16.4;
Crc16_l.5:=crc16.5;
Crc16_l.6:=crc16.6;
Crc16_l.7:=crc16.7;

Crc16_h.0:=crc16.8;
Crc16_h.1:=crc16.9;
Crc16_h.2:=crc16.10;
Crc16_h.3:=crc16.11;
Crc16_h.4:=crc16.12;
Crc16_h.5:=crc16.13;
Crc16_h.6:=crc16.14;
Crc16_h.7:=crc16.15;


Для какого протокола считаете?

vojt
24.01.2010, 19:49
Спасибо! Ход мысли понял. Так я получаю двоичный код, который уже проще обработать.
<Для какого протокола считаете?>
Протокол Modbus RTU или я не правильно понял вопрос?

Jeck
24.01.2010, 19:52
а зачем тогда Unm? стандартный модуль чем не устроил?

vojt
24.01.2010, 20:07
< а зачем тогда Unm? стандартный модуль чем не устроил?>
Честно говоря, я просто еще и не пробовал, а подходящих примеров пока не нашел. А через UNM у меня есть небольшой опыт подключения вессового индикатора СAS CI-5010A к ПЛК-150IM по протоколу Modbus Ascii, хотя думаю, что это не единственный способ, но связь у меня получилась и не плохо работает.

Jeck
24.01.2010, 20:09
vojt, примеров валом. в полезностях.

vojt
24.01.2010, 20:23
А какой стандартный модуль можно применить? И как там вычислять контрольную суму?

vojt
24.01.2010, 20:53
Сформулирую по другому вопрос. В стандартном протоколе Modbus RTU контрольная сума CRC16 вычисляется по такому же алгоритму и с таким же полиномом А001h?

Jeck
24.01.2010, 21:24
Модбас - мастер. он сам считает

vojt
25.01.2010, 00:24
[Модбас - мастер. он сам считает]
То есть в конфигурации нужно выбрать Modbus(Master) - Universal modbus devise , и с помощью выходных регистров задать переменные, которые нужно передать, а с помощью входных - переменные, которые нужно принять, а Modbus(Master) - Universal modbus devise автоматически будет создавать CRC16 , такую как нужно для выходной посылки и соответственно анализировать принятую CRC16?

Jeck
25.01.2010, 00:37
vojt, да, именно так.
________________________
зы откройте, пожалуста,
"Конфигурирование
области ввода/вывода ПЛК1хх
Руководство пользователя " с диска.
там все описано.

vojt
25.01.2010, 00:50
В том и дело, что в "Конфигурирование области ввода/вывода ПЛК1хх
Руководство пользователя " ничего не сказано о CRC для Modbus(Master).

Jeck
25.01.2010, 00:54
vojt, да она вам и не нужна! что вы в нее уперлись. модуль сам сформирует посылку, сам подсчитает, сам проверит ответ. все. вы настроили модуль и работаете с регистрами и незабиваете себе голову подробностями, че он там делает и зачем.
зы посмотрите примеры - подключение панели 320 по модбас в полезностях

vojt
25.01.2010, 01:03
Jeck, да, может быть, я действительно слишком ухожу в детали. Сейчас просто нет железа под рукой. Позже попытаюсь практически это осуществить и возможно возникнут еще вопросы.Тем не мене спасибо за совет!

kolpak
22.11.2010, 17:24
а какой стандартный модуль можно применить?

Александр Приходько
24.11.2010, 10:32
Модулем является среда программирования. Настройка протокола обмена заключается в конкурировании области PLC_Configuration.

Вам поможет раздел Форум-ПЛК-Примеры программ и полезности.

Александр Приходько
24.11.2010, 16:59
А если интересно как вообще работает протокол модбас, можно зайти в примеры и посмотреть готовый пример:
http://www.owen.ru/forum/showpost.php?p=48013&postcount=63

vavanpop
22.03.2017, 13:23
вот кому интересно функция на паскале подсчета CRC16 для ModBus:

function CRC16(Msg: string) :Word;
var
i, j :Integer;
begin
Result := $FFFF;
for i := 1 to Length(Msg)
do
begin
Result := Ord(Msg[i]) xor Result;
for j := 1 to 8
do
begin
if (Result and 1) = 1
then
Result := (Result shr 1) xor $A001
else
Result := Result shr 1;
end;
end;
end;

пример формирования посылки для запроса состояний дискретных входов на ModBus RTU для прибора с адресом 16:

Msg := #$10#$03#$00#$33#$00#$01;

Msg := Msg + Chr(Lo(CRC16(Msg))) + Chr(Hi(CRC16(Msg)));

отправляем посылку в порт и получаем ответ.

Павел_Хабаровск
19.05.2021, 15:23
Здравствуйте, товарищи специалисты!
Требуется помощь по подключению устройства Modbus с проверкой контрольной суммы.
Находимся в командировке на второй ветке БАМа, Новый Ургал.
Имеется система водоподготовки с экипировочными колонками на тепловозы.
В данных колонках имеются платы ввода/вывода на микроконтроллере STM (вх.-пуск/стоп, вых.-индикация).
Общаться с платами нужно запросом с контрольной суммой. Ранее с формированием такой связи не сталкивался. (Привычно конечно стандартным решением задания адреса и регистра)
Нужен пример для ПЛК110.60М v2 (или др.) Испробовал на примерах с форума, не выходит. Не всё значит понятно.
Понятен принцип, следующий:
1. Используем библиотеку работы с портом.
2. Составляем запрос в байтах
3. Открываем порт
4. Посылаем байтовый запрос
5. Закрываемся и слушаем ответ
6. Принимаем данные и оцениваем значение.
Производитель описывает запрос из 6 байт.
За основу брал пример с форума, где описан опрос МВВ аналоговых сигналов из 8 байтов.
Из примера снимал 2 байта, указал адрес, запрос состояний, контрольную сумм, порт(1 или 2 пробовал), скорость 19200.
Смущает длина запроса 8 байт, в описании ведь 6, поменял на 6. Ошибка отсутствия связи №81 так и не уходит не уходит.
ST код смотрел, в основном всё понятно
Кто может откликнуться, навести на цель?
Мне бы зацепиться по адресу с платой, а дальше сам.

melky
19.05.2021, 16:39
Павел_Хабаровск после формирования запроса нужно посчитать CRC, прилепить ее к запросу и отправить. Не смотрел по коду, что там за CRC, если строго такая же как у Modbus, то при приеме ответа кидаем его целиком в расчет CRC и должны получить 0, если другой расчет, то посылать только ответ, вычислять CRC и сравнивать с полученной.

Павел_Хабаровск
20.05.2021, 03:05
Сейчас проблема что в ответе ничего нет, всё по 0. Порт правильный на контрольном 485 преобразователе индикатор мигает.
Проверил полярность, перебирал адреса и регистры, ответа в буфере нет. Единственное что смущает в описании протокола 6 байт а в примере 8. И ещё в описании посылки адрес состоит из 2 байт. Не пойму, ведь его можно задать одним байтом.
Программа без расчёта CRC.
Устройство просто не отвечает. Преобразователем на шине через Serial Port Monitor отправил число, Codesys увидел.

По CRC начинаю что-то подозревать. Получается производитель зашил программную обработку контрольной суммы в МК. Алгоритм вычисления по своему коду. Достаточно лишь раз её вычислить и вставлять в код запроса.

#define __swap_nibbles(x) ((x>>4)|(x<<4))
unsigned short crc16Calc(unsigned char *buffer, int n)
{
unsigned int i;
unsigned char crc1,crc2,tmp;
crc1 = crc2 = 0xff;
for(i = 0;i < n;i++)
{
crc2^=buffer[i];

tmp = __swap_nibbles(crc2)&0x0f^crc2;
crc2 = crc1;
crc1 = tmp;
tmp = __swap_nibbles(tmp)&0xf0;
crc2 ^= tmp;
tmp = (tmp<<1)^crc1;
crc1 >>= 3;
crc2 = crc2^crc1;
crc1 = tmp;
}
return crc2+(crc1<<8);
}

Так вот эта CRC вычисляется от всего пакета? всегда будет разной? Или постоянные числа на последних двух байтах можно вставить и при ответе CRC будет постоянной?
Смотрю в код, кто-то же писал со знанием дела. Сам не пойму как его интерпретировать. Вставляю в онлайн компилятор C, ошибки есть.
https://www.onlinegdb.com/online_csharp_compiler

main.cs(10,0): error CS1525: Unexpected symbol `unsigned' (какой-то неожиданный символ)
Compilation failed: 2 error(s), 0 warnings

Павел_Хабаровск
20.05.2021, 08:49
Так, так... Использовал 1 пример с библиотекой SysLibCom с опросом МВА8 с адресом 64. Всё работает. При смене адреса тишина. Получается CRC выводится от байт данных до CRC?

Павел_Хабаровск
20.05.2021, 11:33
Товарищи! Стеснюсь просить.
Может есть у кого конфигурация посылки с проверкой контроля чётности.
Пару примеров нашёл. В одном известная CRC без контроля (МВА8 работает), во втором многочленные связи - перетягиваю пример, не растёт кокос. И всё на ST.
А командировочка тикает, тут делом заниматься надо. Короче завис до востребования. Дома папку встретят с бородой.

Павел_Хабаровск
20.05.2021, 12:18
Да не чётности, суммы конечно. Смеркается, допускаю ошибки.

Newcomer
20.05.2021, 12:21
Товарищи! Стеснюсь просить.
Может есть у кого конфигурация посылки с проверкой контроля чётности.
Пару примеров нашёл. В одном известная CRC без контроля (МВА8 работает), во втором многочленные связи - перетягиваю пример, не растёт кокос. И всё на ST.
А командировочка тикает, тут делом заниматься надо. Короче завис до востребования. Дома папку встретят с бородой.

Протокол Modbus RTU ? Надо попробовать опросить это устройство посредством OPC - сервера, тогда появится ясность с протоколом обмена.

Павел_Хабаровск
20.05.2021, 12:45
Обобщаю информацию.
Есть пример ниже, по нему связываюсь с МВА8, адрес 64. Расчёта CRC нет, т.к. вставлен известный.
Нужна конфигурация с расчётом CRC и посылкой, хотя бы посмотреть что работает с разными адресами.
Но это только надежда на победный исход.
Главной задачей требуется перевести код расчёта контрольной суммы с C# на ST. (А может подойдёт из библиотеки)
И тогда наверняка, вдруг запляшут облака!..

Павел_Хабаровск
20.05.2021, 13:17
Спасибо что не оставили без внимания...
Готов за вознаграждение поручить создать пример для опроса устройства (вообще там 15шт)
Ребята! Мне просто не хватает знаний для программирования данного момента. Ранее не сталкивался.
Всю остальную водоподготовку сделал, там стандартные овеновские МВВ.
С этим протоколом застрял.
Учимся по ходу движения. В данном случае нужен учитель с указкой.
15 плат по 7вх. 4 вых. Хотя бы на одной пример решить.

Newcomer
20.05.2021, 13:19
Послал в личку пример.

capzap
20.05.2021, 13:19
Готов за вознаграждение поручить создать пример для опроса устройства (вообще там 15шт)
https://owen.ru/forum/showthread.php?t=13584 не благодарите

Newcomer
20.05.2021, 13:24
Спасибо что не оставили без внимания...
Готов за вознаграждение поручить создать пример для опроса устройства (вообще там 15шт)
Ребята! Мне просто не хватает знаний для программирования данного момента. Ранее не сталкивался.
Всю остальную водоподготовку сделал, там стандартные овеновские МВВ.
С этим протоколом застрял.
Учимся по ходу движения. В данном случае нужен учитель с указкой.
15 плат по 7вх. 4 вых. Хотя бы на одной пример решить.

Зачем тебе считать КС если modbus.lib это сама делает. Тебе надо убедиться, что твое устройство работает по протоколу Modbus RTU.

Newcomer
20.05.2021, 13:26
)) ему ж на st надо. Сказали уже - modbus.lib, хоть за ради только crc

Перевести код с C на ST можно без проблем.

melky
20.05.2021, 13:32
Судя по коду расчета там CRC не Modbus

Newcomer
20.05.2021, 13:37
У этого устройства нестандартный протокол. modbus.lib тут не поможет. Надо пользоваться SysLibCom.

melky
20.05.2021, 13:46
Вот на C# код для расчета CRC Modbus, видно что хоть и на C или на чем там у вас, отличается


public static ushort CRC16_Modbus(byte[] msg)
{
const ushort polinom = 0xa001;
ushort code = 0xffff;

for (int i = 0, size = msg.Length; i < size; ++i)
{
code ^= (ushort)(msg[i] << 8);

for (uint j = 0; j < 8; ++j)
{
code >>= 1;
if ((code & 0x01) != 0) code ^= polinom;
}
}
return code;
}

Павел_Хабаровск
20.05.2021, 13:57
В любом случае, благодарю.

Зачем тебе считать КС если modbus.lib это сама делает. Тебе надо убедиться, что твое устройство работает по протоколу Modbus RTU.
Согласен про modbus.lib. А вот чтобы убедится что устройство работает надо запрос сделать с КС (верно?)(у меня их два на столе).
Capzap, товарищ! (Обратился бы по имени, так всё-таки правильней). Я понял ваш посыл - добиваться своим умом и трудом. Каждый должен быть на своём месте и оттачивать мастерство. Честно, того же мнения. В этом и есть смысл развития...
Эх, сейчас бы машину декомпрессии времени, разобрался бы детальней с задачей.
Ну да ладно. Ухожу на повторный круг образования. По результату сообщу.

Newcomer
20.05.2021, 14:05
В любом случае, благодарю.

Согласен про modbus.lib. А вот чтобы убедится что устройство работает надо запрос сделать с КС (верно?)(у меня их два на столе).
Capzap, товарищ! (Обратился бы по имени, так всё-таки правильней). Я понял ваш посыл - добиваться своим умом и трудом. Каждый должен быть на своём месте и оттачивать мастерство. Честно, того же мнения. В этом и есть смысл развития...
Эх, сейчас бы машину декомпрессии времени, разобрался бы детальней с задачей.
Ну да ладно. Ухожу на повторный круг образования. По результату сообщу.

modbus.lib тебе не нужна. Надо пользоваться SysLibCom и самому считать и отправлять КС. При приеме пакета-отклика то же надо будет считать КС.

Павел_Хабаровск
21.05.2021, 10:46
Продолжаем разбор.
Как правильно получить контрольную сумму, для модбас? Тренируюсь на МВА.
55225

Думал прогнать через проверку CRC и добавить недостающие байты, но ноля не получается.
55226

Добавил байты
55227

Нет ноля.
55228

Обыкновенно CRC_GEN вычисляет контрольную сумму, которая присоединеняется к оригинальному сообщению. Если теперь снова вычислить контрольную сумму сообщения вместе с присоединенной к нему контрольной суммой, то в результате получится 0.

capzap
21.05.2021, 10:55
Продолжаем разбор.
Как правильно получить контрольную сумму, для модбас? Тренируюсь на МВА.
55219

Думал прогнать через проверку CRC и добавить недостающие байты, но ноля не получается.
55220

Добавил байты
55221

Нет ноля.
55222

ссылку можно на документ, где написано что контрольная сумма должна быть равна нулю

Павел_Хабаровск
21.05.2021, 12:11
Разобрался с получением КС в десятичном формате. Как перевести в 16#?
218 перевожу в HEX получается DA а в запросе должно 16#8B
55233

capzap
21.05.2021, 12:16
Разобрался с получением КС в десятичном формате. Как перевести в 16#?
218 перевожу в HEX получается DA а в запросе должно 16#8B
55233

а как же здравый смысл? 55234

Павел_Хабаровск
21.05.2021, 12:36
Да, такие же цифры. Но в КС младший байт из примера обозначен 8B.
Вот и думаю как получили.
Ладно там в примере запрос в шестнадцатеричном формате нужен для смещения точки. Т.к. предстоит считывать дискреты, то это можно опустить.
А здравый смысл преобладает в спокойном состоянии.
Затяжные сюрпризы с протоколом производителя, без опыта организации связки, да в командировке заставляют размозжить мозги. Состояние полёта в на орбиту.

capzap
21.05.2021, 13:13
Да, такие же цифры. Но в КС младший байт из примера обозначен 8B.
Вот и думаю как получили.
Ладно там в примере запрос в шестнадцатеричном формате нужен для смещения точки. Т.к. предстоит считывать дискреты, то это можно опустить.
А здравый смысл преобладает в спокойном состоянии.
Затяжные сюрпризы с протоколом производителя, без опыта организации связки, да в командировке заставляют размозжить мозги. Состояние полёта в на орбиту.
какой пример?
Начните с чего нибудь внятного, например https://ru.wikipedia.org/wiki/Modbus раздел примеры, даны три различных посылки с ними и разбирайтесь
ЗЫ У меня вот всё сходится во вложении

melky
21.05.2021, 13:18
Павел_Хабаровск, если полный ответ вместе с CRC при проверке не получает 0 то это не Modbus, это только фишка CRC именно Modbus протокола, пока мне не попадались другие протоколы, где был бы ноль при расчете с учетом CRC

Напишите строку в HEX при ответе прибора, любую, интересно посмотреть что там за контрольная сумма.

capzap на счет документа не скажу. Но сам расчет CRC Modbus имеет данную фишку. Если в расчет CRC закинуть весь ответ вместе с полученной CRC то новая CRC будет равна 0. Всегда.

то есть посылаем 8 байт, посчитали и прилепили согласно протокола еще 2 байта и потом в расчет кинем все 10 байт то получим новую CRC=0

А, про 0 указано в документе на протокол, который выкладывал Павел. Но по коду там не похоже на расчет Modbus.

И кстати >> это не ROR а SHIFT, выталкиваемые биты замещаются нулями. А, или я не понял, вот эта конструкция ROL ? ((x>>4)|(x<<4))

melky
22.05.2021, 15:46
SHR и SHL соотв. так это и есть shift вправо или влево с выталкиванием битов. то есть >> или <<

((x>>4)|(x<<4)) - а эта комбинация действительно ROL или ROR на 4 всего байта, переставление полубайт, обозванное инверсией.

melky
22.05.2021, 16:43
ну да, на 4 бита всего байта. перестановка полубайт (дословно, не инверсия как выразился).

з.ы. буду знать как ROL и ROR делать :)