|
AVR Modbus RTU, Поможите) |
|
|
|
Aug 2 2010, 05:12
|

Частый гость
 
Группа: Участник
Сообщений: 189
Регистрация: 21-01-10
Пользователь №: 54 971

|
В общем с AVRами дружу недавно, столкнулся с острой необходимостью использования протокола Modbus RTU (т.к. оборудование уже используют на многих объектах и нужно общение приборов с новыми прошивками работающими по тому же принципу). В общем, надеюсь, найдутся добрые люди, которые смогут мне простому смертному помочь в освоении этого протокола на базе ATMega16. Собственно готовых кодов не нужно, мне б полностью принцип понять применительно к моей задаче. Я кое чего нашел от прежнего программиста, вот все что есть:
------------------------------- Протокол передачи данных ModBus RTU. Функция для передачи данных: 04 - «read input registers». Запрашивать 14 регистров начиная с нулевого. Каждый регистр – двухбайтное слово. Обращаю внимание, что в протоколе ModBus все слова передаются старшим байтом вперед. Были случаи что попадалась документация с разными таблицами CRC и разными полиномами. Ниже приведу свои таблицы. Порядок передаваемых данных:
1. Значение A 2. Значение B 3. Значение C 4. Значение D 5. Значение E 6. Значение F 7. Значение G 8. Значение H 9. Значение I 10.Значение J 11.Значение K 12.Значение L 13.Значение M 14.Значение N
Запись параметров - 16 (10 Hex) Preset Multiple Registers Порядок передаваемых данных:
1. Значение I 2. Значение J 3. Значение K 4. Значение L 5. Значение M 6. Значение N
const unsigned char CRCHi[] = { 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};
const unsigned char CRCLo[] = { 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};
Надеюсь на помощь!
--------------------
Не так страшна автоматизация, как её малюют.
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 14)
|
Aug 2 2010, 05:47
|

Частый гость
 
Группа: Участник
Сообщений: 189
Регистрация: 21-01-10
Пользователь №: 54 971

|
Вопросов много.. За ссылку конечно спасибо, но видимо пока я там ничего понять не смогу. Про модбас знаю только что слово такое есть, узнать бы принцип протокола именно RTU (для моей задачи, глобально протокол осваивать нет необходимости пока). Также как высчитывать CRC16? (как я понял его нужно высчитывать используя две таблицы, которые приведены выше), т.е. полный алгоритм подсчета что с чем складывать куда что сдвигать и при каких условиях. Какие временные интервалы выдерживать при посылках/ожиданиях ответа. Пока только умею атмегой посылать/принимать байты с заданной скоростью без какого либо протокола..) Вобщем, у меня есть формат посылки, которую нужно отправить в прибор, в ответ на которую прибор должен прислать все необходимые данные.. Видимо аццкая жара которая неделю влияет на мозги (белок то сворачивается) и мне б "на пальцах для тупых" основные принципы протокола (по каким правилам что передавать и когда чего принимать) и принцип подсчета црц16 исходя из приведенных таблиц
--------------------
Не так страшна автоматизация, как её малюют.
|
|
|
|
|
Aug 2 2010, 06:02
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Если тупо на пальцах именно про RTU, то основная фишка там - это таймаут 3.5 символа по приёму пакета. То есть, если между двумя любыми байтами разрыв больше, то это считается концом пакета. В freemodbus это реализовано с помощью таймера. По приёму каждого символа заводится таймер на 3.5 символа вперёд, а символ кладётся в буфер. Если сработал таймер, значит имеем тайм-аут и соответственно конец пакета. Вызывается обработчик, который анализирует целостность пакета (CRC, заголовок, код команды, длина пакета) и выставляет соответствующие флаги, которые затем обрабатываются функцией eMBpoll(), которая, в свою очередь, вызывает CallBack-функции для обработки команд. Вычисление CRC производится в функции usMBCRC16 (./RTU/mbcrc.c)
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Aug 2 2010, 06:09
|
Местный
  
Группа: Свой
Сообщений: 264
Регистрация: 16-07-05
Из: г. Уфа
Пользователь №: 6 851

|
Почитайте это и вот это. Контрольная сумма считается так: Код static __flash unsigned char aucCRCHi[] = { 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 };
static __flash unsigned char aucCRCLo[] = { 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 };
unsigned int usMBCRC16(unsigned char * pucFrame, unsigned int usLen ) { unsigned char ucCRCHi = 0xFF; unsigned char ucCRCLo = 0xFF; int iIndex;
while( usLen-- ) { iIndex = ucCRCLo ^ *( pucFrame++ ); ucCRCLo = ucCRCHi ^ (aucCRCHi[iIndex] ); ucCRCHi = ( aucCRCLo[iIndex] ); } return ucCRCHi << 8 | ucCRCLo; }
--------------------
|
|
|
|
|
Aug 2 2010, 06:43
|

Частый гость
 
Группа: Участник
Сообщений: 189
Регистрация: 21-01-10
Пользователь №: 54 971

|
Цитата(war4one @ Aug 2 2010, 09:09)  Почитайте это и вот это. Контрольная сумма считается так: Благодарю за пример, сегодня уже находил что-то подобное, я пишу на ассемблере пока только, с Си имею дело только когда чего-нить в visual-среде под винду пишу (ну это боловство пока только). В начале я как понимаю мы объявляем переменные а дальше крах мозга...)))) я заранее пршу прощения, так стыдно.....))) ну и собсно исходя из того, что я пишу на машинном уровне мне б понять как соотносится принятый байт со значениями в этих таблицах и как в итоге получается этот несчастный црц.. я не зря "на пальцах для тупых" попросил, но я не безнадежен....)) в последний раз я так мучался когда не знал с чего начать контроллеры осваивать))) ну вот освоил 51, AVR, хочу еще ARM, но тут без Си никак (последнее - енто лирическое отступление, мона пропустить). Вобщем, в идеале, я принимаю все байты посылки, считаю црц, если он правильный то проверяю 1й байт, если он совпадает с адресом прибора, то по функции выдаю ответ с данными, если во время приема возникла тишина в 3,5 байта (исходя из скорости) то полученные данные считаю полностью принятой посылкой (ну и дальше сначала как описал), правильно глаголю? осталос только с этими таблицами разобраться на машинном уровне..
--------------------
Не так страшна автоматизация, как её малюют.
|
|
|
|
|
Aug 2 2010, 08:50
|

Частый гость
 
Группа: Участник
Сообщений: 189
Регистрация: 21-01-10
Пользователь №: 54 971

|
Цитата(MrYuran @ Aug 2 2010, 10:57)  Возвращаем старший и младший байт CRC в виде 16-разрядного слова Вот спасибо хорошо положите на камод.. Епт, все оказывается не так сложно. Спасибо добрый человек за разжовывание..)) на бумажке посчитал по этому методу (через таблички) и все получается, ну пока для посылки всего из одного байта посчитал)) Только после подсчета получается какбы итоговое значение младшего байта CRC ставится старшим байтом, а старшее итоговое ставится младшим, круто блин
--------------------
Не так страшна автоматизация, как её малюют.
|
|
|
|
|
Aug 5 2010, 08:40
|

Частый гость
 
Группа: Участник
Сообщений: 189
Регистрация: 21-01-10
Пользователь №: 54 971

|
на железе сегодня полностью отладил прием 8ми байт (1й - адрес, 2й - функция 3й4й - начальный адрес регистров, 5й6й - кол-во регистров, 7й8й - CRC16), CRC16 считает, при скорости 57600 выжидаю 70мс (3.5/57.6 = 60.8мс, но я решил для верности немножко с запасом) после приема очередного байта, если время прошло считаю как новый фрэйм, также сделал что если приходит больше 8ми байт в одном фрэйме, то каждый 9тый воспринимается как начало нового 8ми байтого фрэйма, короче радости полные штаны))
--------------------
Не так страшна автоматизация, как её малюют.
|
|
|
|
|
Aug 5 2010, 10:14
|

Частый гость
 
Группа: Участник
Сообщений: 189
Регистрация: 21-01-10
Пользователь №: 54 971

|
Цитата(MrYuran @ Aug 5 2010, 11:51)  Это неправильно, в RTU должен быть разрыв 3,5 символа. Если его нет, то это будет ошибка формата фрейма. сделал, теперь молчит если больше 8ми байт. У меня вопрос созрел по самому модбасу. Вобщем как я и говорил у меня ни исходников предыдущей версии прошивки нету ни связи с тем программистом который ее создавал. Так вот, значит посылаю я прибору со старой прошивкой строку: 01 04 00 00 00 01 31 CA а он мне в ответ 01 04 08 00 00 00 00 00 00 FF FF 25 BD Возникает у меня как минимум 2 вопроса 1. Что за 08 и откуда оно берется? Эт явно что-то с модбасом связано 2. Почему так много данных выдает (пускай они даже 00 00), судя по всему он выдает четыре 2хбайтных параметра 00 00 00 00 00 00 FF FF, хотя я в исходящей посылке даю прибору инструкцию на передачу всего одного слова данных начиная с 00 00 адреса. Я предполагал, что ответ будет примерно таким: 01 04 xx xx CRC16 Поможите люди опытныя..)
--------------------
Не так страшна автоматизация, как её малюют.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|