vazz 0 2 апреля, 2011 Опубликовано 2 апреля, 2011 · Жалоба Правильный алгоритм в спецификации ModBus привден. И даже функция на языке Си имеется. эт оттуда и таблицы и функция (просто на асм переделанная) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 3 апреля, 2011 Опубликовано 3 апреля, 2011 (изменено) · Жалоба Короче переделал я алгоритм расчета crc из табличного в стандартный с тем же полиномом A001 ; +-------------------------------------------------------------------------+ ; | подпрограмма проверки контрольной суммы CRC16 | ; | | ; |temp1,temp10 - кол-во байт для подсчета, temp8,temp6 - начальный адрес 1го байта| ; | выход: temp3 - младший байт CRC16, temp2 - старший байт CRC16 | ; +-------------------------------------------------------------------------+ checkCRC16: ldi temp2,0xFF ;загружаем начальное значение CRC (МБ) ldi temp3,0xFF ;загружаем начальное значение CRC (СБ) ldi temp4,0x01 ;загружаем значение полинома ldi temp5,0xA0 add temp6,temp1 ;прибавляем к нач.адресу кол-во байт adc temp8,temp10 mov temp7,temp6 ;копируем результат в temp7,temp9 mov temp9,temp8 loopCalcCRC16: mov temp6,temp7 ;копируем результат в temp6,temp8 mov temp8,temp9 sub temp6,temp1 ;в temp6,temp8 остается адрес текущего байта принятого фрэйма sbc temp8,temp10 mov ZH,temp8 mov ZL,temp6 ld temp6,Z ;в temp6 остается значение байта eor temp2,temp6 ;ксорим значение байта со значением CRC (МБ) ldi temp6,8 loopXORbyte: sbrc temp2,0 ;проверяем младший бит CRC (МБ) jmp MB_CRCL_1 jmp MB_CRCL_0 MB_CRCL_1: clc ;сдвигаем вправо весь CRC ror temp3 ror temp2 eor temp2,temp4 ;ксорим значение CRC с полиномом eor temp3,temp5 jmp skip_MB_CRCL_0 MB_CRCL_0: clc ;сдвигаем вправо весь CRC ror temp3 ror temp2 skip_MB_CRCL_0: dec temp6 brne loopXORbyte subi temp1,1 ;уменьшаем счетчик байт sbci temp10,0 cpi temp1,0 brne loopCalcCRC16 cpi temp10,0 brne loopCalcCRC16 ;и проверяем достиг ли он 0 ret Этот код полностью повторяет С# код пользователя Linore с форума http://programmersforum.ru/showthread.php?t=82812&page=2 Правильность посчитанной суммы проверял программкой СRC Find (Подбор полинома) неизвестного автора, там можно ввести hex-пакет длиной больше 256 и получившуюся контрольную сумму, затем эта программка просчитывает все полиномы от 0x0000 до 0xFFFF, так вот для пакета: 3E0101010B00004801005AFFFF02005FFFFF030062FFFF04004DFFFF050062FFFF06007CFFFF0700 6BFFFF08008AFFFF090062FFFF0A0079FFFF0B007BFFFF0C007FFFFF0D0056FFFF0E006AFFFF0F00 7DFFFF10007EFFFF110045FFFF120065FFFF130073FFFF14005FFFFF15005AFFFF160068FFFF1700 76 FFFF180076FFFF190057FFFF1A006BFFFF1B0061FFFF1C0069FFFF1D0039FFFF1E0072FFFF1F0058 FFFF200044FFFF210039FFFF220033FFFF230060FFFF240032FFFF25005FFFFF260048FFFF27005C FF FF280057FFFF290047FFFF2A0040FFFF2B003BFFFF2C0049FFFF2D0034FFFF2E0052FFFF2F0035FF FF300035FFFF310033FFFF320041FFFF33004EFFFF340033FFFF350025FFFF36002DFFFF370007FF FF 38002FFFFF390026FFFF3A0024FFFF3B0006FFFF3C0032FFFF3D0034FFFF3E0029FFFF3F0032FFFF 40003DFFFF41004CFFFF42000BFFFF43005CFFFF440036FFFF450055FFFF46002CFFFF470058FFFF 480019FFFF мой модуль выдал crc16 = 0x403F, программка CRC Find при вычислении полинома выдала что совпал полином 0xA001 Программка для работы с портами IODump, которой я пользуюсь похоже считает crc16 корректно только для пакетов длиной не больше 256 и считает она тоже с полиномом 0xA001, например для этого же пакета она считает crc16 = 0x1604 и при проверке через прогу CRC Find ни с одним полиномом не совпадает. Вот такие дела собственно. Кстати предыдущий способ (табличный) тоже корректно работал, все правильно считает, все дело было в кривой программке для работы с портами((( Изменено 3 апреля, 2011 пользователем vazz Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ukpyr 0 3 апреля, 2011 Опубликовано 3 апреля, 2011 (изменено) · Жалоба freemodbus.berlios.de - готовый модуль.имхо сделано весьма неоптимально, тем более для АВР. Зачем-то включили настройку посл.порта в инициализацию, в результате пришлось лепить порты под все архитектуры. CRC считают для всего фрейма, тогда как можно обновлять прямо в прерывании приема/передачи для каждого байта. vazz попробуйте такую функцию: #define CRC16_MODBUS_INIT 0xffff #define CRC16_MODBUS_POLY 0xa001 U16 crc16_modbus_upd(U8 data, U16 crc_prev) { U8 flag_xor; crc_prev ^= data; for (U8 cnt_bits = 8; cnt_bits; cnt_bits--) { flag_xor = crc_prev & 1; crc_prev >>= 1; if (flag_xor) crc_prev ^= CRC16_MODBUS_POLY; } } Изменено 3 апреля, 2011 пользователем ukpyr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 3 апреля, 2011 Опубликовано 3 апреля, 2011 · Жалоба vazz попробуйте такую функцию: #define CRC16_MODBUS_INIT 0xffff #define CRC16_MODBUS_POLY 0xa001 U16 crc16_modbus_upd(U8 data, U16 crc_prev) { U8 flag_xor; crc_prev ^= data; for (U8 cnt_bits = 8; cnt_bits; cnt_bits--) { flag_xor = crc_prev & 1; crc_prev >>= 1; if (flag_xor) crc_prev ^= CRC16_MODBUS_POLY; } } благодарю, но обе функции которые я испытал работают замечательно, изначально моя ошибка была в том что ориентировался на свою программку для работы с портами как на эталон подсчета crc, оказалось все работало у меня изначально, зря паниковал, зато разобрался во всех этих заморочках досконально, эт плюс. ТУТ ОКАЗЫВАЕТСЯ ЕСТЬ ТЭГИ "CODE", а я блин понапихал тут кодов без соответствующего оформления..)) sorry Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
A_D 15 17 августа, 2014 Опубликовано 17 августа, 2014 · Жалоба Добрый день! Думаю правильно будет спросить в этой теме, а не создавать новую по схожему вопросу что обсуждалось выше. Ситуация: Для проверки работоспособности, есть простая плата на atmega32 , кварц внешний 16МГц. Кабель UART TTL-232R-3V3 (собран на FT232), взял исходники freeModbus , чуть подредактировал (пишу на Atmel Studio 6.1), скомпилировалось все прекрасно. Залил в МК, запустил утилиту modpoll.exe с параметрами: modpoll.exe -m rtu -a 10 -r 1000 -c 5 -t 3 -b 38400 -d 8 -p even COM3 pause>nul МК находит, читает с него регистры и все вроде бы хорошо. но, беру любую другую программу для работы с ModBus RTU и ничего не коннектиться. типа ошибка связи. Вот остановился сейчас на этом http://modbustool.codeplex.com ибо наименее безглюченная при запуске и работе. Но связи так и не добился. Что это может быть ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
A_D 15 17 августа, 2014 Опубликовано 17 августа, 2014 · Жалоба Немного разобрался с тем, почему при чтении выдавало ошибку #2. Подсказку нашел в соседней ветке http://electronix.ru/forum/index.php?showt...86005&st=15 так вот,там как я понял было дело в прошивке - надо было увеличивать на 1 (к примеру 1001) адрес к примеру Input регистра, и тогда он читался по адресу 1000 извне. у меня схожая ситуация, но противоположно надо делать получается... кто нибудь сталкивался с таким ? получается мастер на ПК по версии Modbus'a новее, чем в МК ? Пример реализации для AVR брал отсюда http://robot-develop.org/archives/125 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lagman 1 19 августа, 2014 Опубликовано 19 августа, 2014 · Жалоба Скорей всего это особенность вашего мастера, в программе запрос идет по 999 ячейке как и указано пользователем. Есть программа modbus poll в ней можно задавать "protocol style addresses. BASE 0" или "PLC style addresses. Base 1" http://www.modbustools.com/base.asp Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться