Простая реализация Модбас-стека на MSP430. Часть первая: Modbus (RTU)

Простая реализация Модбас-стека на MSP430. Часть первая: Modbus (RTU). Часть вторая здесь
А потом пришла третья часть — с подчищеной библиотекой.

Что бы там ни говорили о «старости» Модбаса, он является очень хорошим и заслуженно популярным протоколом в системах промышленной автоматизации. Поэтому полезно иметь возможность использовать Модбас в МК-девайсах, согласных на скромную роль Слейва. Для такого Слейва я и написал Модбас стек. И хотя мой МК — это достаточно новый и еще не очень популярный ФРАМ-камешек из семейства MSP430FR57xx, программу можно портировать и на другие МК.
Хорошо известна библиотека от Кристиана Вольтера, которую я раньше использовал для проекта на Атмеге168. Тем, кто действительно понимает Си, она может оказаться оптимальной. Я программирую примитивно и все время работы с этой библиотекой ощущал себя туземцем, которому дали мобилку, а он только и умеет, что нажать в ней одну кнопку и ответить на вызов. А потом пришло время для MSP430 — а в библиотеке Вольтера как раз для этих МК варианта нет. Ну, и слава Богу. Ленивым толчок в зад, чтобы сами чьой-то делали.
Еще поделюсь вот этой ссылкой. Она, оказывается, лежала у меня давно, но нашел ее только сейчас, когда начал писать эту заметку. Там есть весьма неплохие реализации (в том числе и Мастера!), спокойное обсуждение… Почитайте. Меня подкупило использование структуры для хранения всех переменных стека — это открывает возможность легко плодить несколько слейвов, если в МК есть более одного УАРТа. Такой же подход я видел в примере от уважаемого коллеги reptile, который как-то прислал мне свою реализацию.
Но я сделал по-своему. Просто подошел с чистого листа, озабоченный именно простотой и понятностью (хотя бы для меня!) реализации.

1. Протокол Модбас

Несколько слов о том, что собой представляет этот Модбас. Кто знаком с протоколом — читайте с п.2. Я изложу все очень нестрого, уделяя внимание простоте и краткости.
Замечу. что я опираюсь на "Руководство по имплементации Модбаса в последовательных каналах передачи данных", а также "Спецификацию приложений, работающих по Модбасу". Я только что был поражен также обилием инфо на русском, дав Гуглю запрос «Введение в Модбас протокол» :) Что там кому понравится — смотрите сами.

Протокол достаточно прост. Он описывает обмен между устройствами, причем реализована система «Мастер-Слейв» (Ведущий-Ведомый, Главный-Подчиненный, Начальник-Дурак). Обмен всегда начинает Мастер: он делает запрос, Слейв отвечает. Нет запроса — нет ответа. Это раз.
Второе: обычно на запрос должен быть ответ. Исключение — широковещательный запрос, но это пока забудем. То есть, если Мастер даже не запросил данные, а наоборот — пихнул их Слейву, то все равно Слейв по получению должен отписаться, мол, все гут, командир, запрос от тебя получен, данные принял, столько-то байт. Не будет такого ответа — Мастер выждет таймаут и посчитает, что Слейв недопонял. Может начать  повторами долбить, может вычеркнуть Слейва из числа живущих, может еще чего — стандарт не оговаривает.
Третье: я рассматриваю только один режим работы Модбаса — Modbus RTU. Есть еще и другие режимы, но при работе по RS-232 или RS-485 именно Modbus RTU должен быть в каждом устройстве, как обязательный. Он и является самым популярным.

Итак, запрос-ответ. В ходе такого акта общения данные либо тудЫ, либо сюдЫ. Что за данные? Да простые, цифровые коды. Либо это отдельные биты информации (в далекие времена им отвечали обмотки реле, катушки, потому по-аглицки до сих пор их называют Coils), либо 16-разрядные слова, несущие информацию из т.н. регистров. Как катушки, так и регистры имеют свои адреса, номера. В стандарте много сделано, чтобы запутать православных, но скажу просто: адрес — двухбайтное число. От 0 до сами знаете…
Какова структура запроса и ответа? Общая структура передаваемого от Мастера запроса такова (каждая строка — это один символ):

Адрес
Код функции
Данные
Данные

Данные
Контролька CRC, младший байт
Контролька CRC, старший байт

В Modbus RTU разделителем сообщений (фреймов, содержащих запросы и ответы) является тишина на линии в течение не менее 3,5 символов. С учетом того, что стандартный символ передается УАРТом 11-ю битами, получаем длительность этого периода ( называют его t3.5), равную 38,5 периодов бодрейта. Например, для 9600 бод — 4,01 мс (38,5/9600). Для скоростей от 38400 и выше рекомендовано использовать фиксированную длительность 1,75 мс.
Красивая картинка по этому поводу — на странице 13/44 вышеупомянутого Руководства (пункт 2.5.1.1):

Весь фрейм должен передаваться как непрерывный поток символов. Если обнаружен разрыв между символами длительностью более 1,5 времени передачи одного символа (считаем: 1,5*11=16,5 периодов бодрейта, выше 38400 бод - фиксировано 0,75 мс), то приемник должен поставить «черную метку» и похерить принимаемый фрейм. Обращаю внимание, не надо при этом лихорадочно искать во входном потоке начало следующего фрейма. Можно просто принимать символы дальше, ожидая стандартного признака окончания — паузы t3.5. И лишь потом, начиная парсинг, следует проверить наличие флага «Плохой фрейм» — и похерить принятое сообщение.
Вот иллюстрация

Замечу, что я постучался рогами, пока не понял, что измерять нужно время от окончания предыдущего символа, до начала следующего. Это вовсе не одно и то же, что измерять время между прерываниями по принятому в УАРТ символу! Можно легко вляпаться в ситуацию, когда забракуем вполне годный фрейм.
Далее. Ответ на запрос дается в тех, и только в тех случаях, если команда принята, фрейм не битый (контролька CRC в порядке) и адрес в запросе именно наш. В ответе повторяется первый байт (адрес), а поле кода функции — либо тот же код, либо в него добавлен бит 128 (0х80). Последнее — если обнаружена та или иная ошибка (Exception). Примерами таких ошибок являются: ошибочный код функции, ошибочный номер регистра, недопустимые значения в поле данных… Пока не будем о плохом.
Функции. Они кодируются 7 битами, поэтому придумано их много. Но для нас, простолюдинов, достаточно знать 2 основные:
03 — читать регистры (блок регистров, идущих подряд в адресном поле)
16 — записать регистры (тоже блок регистров)
Есть еще чтение и запись битов, но тут уж почитайте сами. Я пакую биты в регистры, потому вполне хорошо себя чувствую даже с двумя функциями. Вот их и рассмотрим.
Чтение регистров — чтение непрерывного блока регистров с начального номера (адреса), указанное количество. Запрос:
Адрес
03 (код функции)
Начальный номер регистра (старший байт)
Начальный номер регистра (младший байт)
Количество регистров в блоке (старший байт)
Количество регистров в блоке (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт


Ответ от Слейва:
Адрес
03 (код функции)
Количество байт — значений регистров (2N)
Значение регистра с начальным номером (старший байт)
Значение регистра с начальным номером (младший байт)

Значение последнего регистра (старший байт)
Значение последнего регистра (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт


Несмотря на то, что количество регистров передается двумя байтами, допустимое значение этого параметра — от 1 до 125. Поэтому в ответе число байт 2N (которое вдвое больше числа регистров), передается одним байтом. Что-то они там недопили, когда придумывали эту команду…
Иллюстрация (здесь не показаны ни байт адреса. ни 2 байта контрольной суммы):


Запись в регистры — симметрично команде 03. Тоже блок регистров.
Адрес
16 или 0х10 (код функции)
Начальный номер регистра (старший байт)
Начальный номер регистра (младший байт)
Количество регистров в блоке (старший байт)
Количество регистров в блоке (младший байт)
Количество байт - значений регистров (2N)
Значение регистра с начальным номером (старший байт)
Значение регистра с начальным номером (младший байт)

Значение последнего регистра (старший байт)
Значение последнего регистра (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт

Ответ от Слейва:
Адрес
16 (код функции)
Начальный номер регистра (старший байт)
Начальный номер регистра (младший байт)
Количество регистров в блоке (старший байт)
Количество регистров в блоке (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт


не знаю, с какого бодуна, но здесь максимальное число регистров — 123. Почему не одинаково с командой 03 — х.з.
Иллюстрация:


Вот и все. Вы знаете теперь достаточно об этом протоколе, чтобы рассмотреть программную реализацию работы Слейва.

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

— имеем на борту: буфер для размещения принятых и отправляемых фреймов. Его размер — максимум 256 байт. Если хотите работать с числом регистров, существенно меньшим 252, то можете и буфер ограничить. Все равно при приеме проверяем, не переполнился ли буфер;
— ждем первого символа (от Мастера) и по нему начинаем принимать фрейм. Как вариант — сразу фильтруем, наш ли адрес и можем не принимать все что дальше. Но ждать завершающий период тишины t3.5 все равно придется;
— каждый раз, когда символ принят, запускаем таймер для того, чтобы отловить событие: прошло уже t1.5 или t3.5;
— если возникло событие «прошло уже t1.5», а потом пришло начало следующего импульса — фиксируем печальный приговор: «Данный фрейм фтопку», но продолжаем принимать до конца, ибо что ж делать, конец-то должен быть, чтобы было новое начало :)
— если возникло событие «прошло уже t3.5», то заканчиваем принимать фрейм, разбираем его и наполняем (тот же) буфер ответом.
— забрасываем первый байт в буфер передатчика УАРТ, не забыв развернуть драйвер шины RS-485 на передачу;
— когда весь ответ выползет, развернем драйвер шины на прием. В принципе, теперь мы должны отстучать часиками тот же t3.5, но я ставлю программу на прием новых запросов сразу же. Все равно Мастер дождется паузы, потом рассмотрит ответ Слейва, а уж потом что-то может спрашивать.

Как все это реализовано у меня — расскажу во второй части. Сначала посмотрим, как вы покритикуете вступление, подправим все это дело, а к тому времени и программу опишу.
  • +11
  • 07 ноября 2013, 15:00
  • drvlas

Комментарии (43)

RSS свернуть / развернуть
А сколько должен ждать мастер, чтобы сделать вывод, что слейв гепнувся не отвечает?
0
Это не единственная «проблема». Но я беру это слово в кавычки по простой причине: это фича. В выбранной идеологии (Мастер-Слейв) это вполне ожидаемое свойство системы. И с такой «проблемой» работает огромное количество девайсов — в условиях жутких промышленныйх условий.
Подобным же образом можно закинуть Модбасу невозможность от Слейва как-то маякнуть Мастеру о своих событиях. Но мы принимаем именно такой Модбас, какой есть.
0
Я имею ввиду следующее:
— мастер отсилает данные;
— слейв по паузе 3.5 понимает, что это конец посылки
Меня интересует, с какого момента мастер должен начинать отсчитывать таймаут? По окончании свей паузы?
Т.е. после конца посылки ему нужно подождать 3.5+3.5, а затем он делает вывод, что слейв не ответил. Так?
0
Нет, таймауты Мастера не такие малые, чтобы думать о единицах миллисекунд. Когда Мастре запустит таймаут — решает разработчик. По идее — от конца своей посылки. Конечно, разработчик Мастера должен учесть, что 3,5 символа нужно дать Слейву просто для принятия решения.
0
Формально — сколько разработчик решит. Стандарт не оговаривает. Из практического опыта: нет смысла делать большой таймаут. Ибо проще повторить запрос. Особенно это имеет значение в системах с несколькими Слейвами. Тогда лучше по-быстрячку «списать» текущее обращение в утиль, прокрутить остальных Слейвов, а потом попробовать снова обратиться к тому, на котором сбойнуло.
Если это сбой, то следующее обращение будет гут — и все покатится.
То есть, реально таймаут выбирается по самому медленному Слейву (самый его медленный ответ при полной исправности), чуть больше. И все. Если же один «тормоз», а остальные — шустряки, а ждать (в случае сбоя) долго нельзя, то надо думать об изменении топологии. Например, у меня в одном из проектов было до десятка девайсов, практически все откликаются мгновенно, а один — 50 мс. Система запущена, но больше я так не сделаю — я выделю отдельный канал для тугодума.
+1
на конец линии вешаю активную заглушку, которая условно всегда работает и всегда однозначно ответит на запрос. таким образом имеем возможность проверки линии.
+1
Спасибо за статью. Протокол MODBUS не такой уж и древний (в сравнении, например, c TCP/IP) так что хоронить его, думаю, рано :)

В Сообществе есть много примеров реализации протокола со стороны salve устройств, но нет описания применения «полного цикла» (SCADA система + контролируемые устройства). А именно в связке со SCADA, ИМХО, основной плюс использования MODBUS.

Посему вопрос — есть ли удобные и, одновременно, бесплатные SCADA-системы? Те реализации которые я видел (типа Free SCADA ) выглядят, честно говоря, очень убого по сравнению с коммерческими аналогами. А коммерческие аналоги имеют внушительный ценник, что делает их применение нецелесообразным для небольших решений.
0
На вскидку (ибо много не знаю): МастерСКАДА. У меня есть бесплатная версия до 32 тегов — вполне неплохая. Но много не расскажу, т.к. у меня с Модбасом работает ПЛК, а не ПК.
0
В Сообществе есть много примеров реализации протокола со стороны salve устройств
Ой ли? Я просмотрел — очень даже мало. Вижу заметки от коллег GYUR22, uni, Yanichar (очень понравилось) и khomin. В основномЮ речь идет о freemodbus и ее портировании.
Об МСП430 ничего не видно. Так что надеюсь этот пробел восполнить. И именно простой библиотекой, понятной таким хлопцам от сохи, как я.
0
Ой ли? Я просмотрел — очень даже мало.

Коллега, я не хотел сказать, что ваша статья лишняя, ибо тема MODBUS уже полностью раскрыта другими участниками. MODBUS'а много не бывает :)

Я просто хотел сказать, что есть много статей посвященных реализации данного протокола на стороне устройства. И очень мало сказано о том, чем примечателен этот протокол. Каковы плюсы его применения по сравнению с «самописным» проколом поверх RS232 /RS485 .
0
я не хотел сказать, что ваша статья лишняя

Да, я как-то резковато начал защищаться :)
По поводу того, что надо раскрывать преимущества Модбаса — да, согласен полностью! Сам возобновил эмбеддерство как раз тогда, когда стала задача: приколхозить наш выпускавшийся уже несколько лет модуль к нормальному промышленному контроллеру. Который (контроллер) знать не знал, что за самодельный протокол мы изобрели. Так и пошло. Разработал управляющую часть модуля на атмеле, прописал туда модбас, а дальше уже и думать забыл о самопальщине…
Но мне кажется, что тут важно не только показать перимущества Модбаса — и даже не столько это. На мой взгляд, народ пугается именно реализации протокола Модбас в простеньких МК с объемом памяти 4-16К. И свою задачу я сейчас вижу как раз в том, чтобы показать: Модбас суть простой в реализации протокол. И люди потянутся :)
0
народ пугается именно реализации протокола Модбас в простеньких МК с объемом памяти 4-16К.

Ну, не знаю, может Вы и правы. Но мои отношения с MODBUS сложились несколько иначе.

В жизни каждого программиста наступает момент когда он понимает, что пора зазывать изобретать велосипеды и использовать стандартизированные решения. Когда эта участь постигла и меня — я начал поиск подходящего протокола, и первым кандидатом был MODBUS. Вдумчиво изучив спецификацию, я понял что реализация относительно не сложная. Только вот на «верхнем» уровне мне протокол тогда не понравился. Куча функций, регистры обычные, регистры флагов и т. д. Как-то это все выглядело слишком навернуто и усложнено для простого обмена данными между устройствами в шине.

А потом мне показали SCADA и PLC. И только тогда я прозрел, насколько это гибкий, удобный и продуманный протокол.

Мое мнение — многие боятся не реализации протокола, а просто не до конца понимают зачем он им нужен. Из сухой спецификации его преимущества не очевидны.
0
Давай посотрудничаем. Ты напиши о том, какой это классный протокол (я могу мою мазню и убрать — или пусть послужит для тебя черновиком), а я опишу свою реализацию. Тем более, что (как всегда) попытка причесать и сделать библиотеку понятной и удобной для использования существенно повысила ее качество. Я сейчас роюсь, с каждой компиляцией мне нравится все больше. Могу тебе прислать для приватного резюме. А выкладывать на публику не хочу спешить.
Сейчас вот решаю вопрос, как ее таки научиться юзать из разных проектов Студии…
0
я могу мою мазню и убрать — или пусть послужит для тебя черновиком

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

Касательно показать преимущества — я над этим подумываю. Есть идея сделать пару простых тестовых устройств (не касаясь реализации самих устройств), завязать это все на SCADA и показать как это все просто и удобно конфигурируется и работает. Но, в любом случае, быстро у меня это не получится: нужно найти адекватную и бесплатную SCADA, разобраться с ней самому, затем подумать как подать материал (куча скриншотов будет выглядеть уныло, возможно, в данном случае, понятнее будет показать все на видео). Главное найти на это время и не утратить к тому времени энтузиазм :)
0
У меня напарник неделю назад начал осматривать бесплатную скаду www.rapidscada.ru/
посмотрите может понравиться…
0
Сейчас вот решаю вопрос, как ее таки научиться юзать из разных проектов Студии…


А c чем именно у Вас с этим возникают сложности? Скомпилировать статическую библиотеку (я ниже видел, что вы хотите «запихнуть» код в библиотеку) это не проблема. Но я, честно говоря, не особо вижу смысл в статических библиотеках для МК. Может просто оставить *.c и *.h файлы и пусть каждый добавляет их в свой проект? Можно абстрагироваться от нижнего уровня через интерфейс. Или проблемы именно с AtmelStudio (я использую «голый» AVRGCC с другим IDE)?
0
Я же работаю сейчас с другой Студией: CCS для MSP430. И вариант «каждый добавляет их в свой проект» — вполне катит. Но я решил обсудить этот вопрос отдельно на форуме. Ибо для меня «статическая библиотека» — не совсем понятно. Это что, собранная линкером в абсолютных адресах? Мне такое не нравится. Или все же линкеру отдаются объектные файлы?
КАРОЧИ, приглашаю вот сюда.
0
Я же работаю сейчас с другой Студией: CCS для MSP430

Да, что-то я торможу, забыл, что речь идет о MSP430. С CCS для MSP430 я Вам не помогу, ибо с ним не работал.
Но идея статических библиотек везде приблизительно одна — это некая сборка из объектных файлов. В GCC это просто архив (натурально, архив) из объектных файлов. Адреса, соответственно, там не абсолютные, они становятся абсолютными на этапе линковки (как и обычно). Собственно говоря, линкеру абсолютно все равно откуда появился объектный файл — был скомпилирован из исходников или «извлечен» из библиотеки. Но, повторюсь, я не знаю тонкостей CCS для MSP430.
0
Хм, я правильно понимаю, что Code Composer Studio в качестве компилятора использует GCC? Там стандартный набор утилит (GCC toolchain)?
0
Да нет, там написано, что компилятор TI v.4.1.7. не похоже на GCC
0
Из коммерческих использовал трейсмод — сомневаюсь, что он лучше хоть одной бесплатной. Писали его настолько криворукие уебаны, что я даже не знаю, как они смогли на работу устроиться. Там например каждая следующая версия почти гарантированно не поддерживает проекты из предыдущих, можно создать объект с ошибкой, который уже не получится из проекта удалить, очень многие протоколы реализованы на уровне «лишь бы не падало», и косяки возникают при любой нештатной ситуации. Модуль ввода выдаёт ошибку «обрыв датчика», а трейсмоду до балды, он с соседнего канала данные берёт и показывает.

Модбас там, кстати, тоже есть, но только для какого-то ограниченного набора контроллеров.
0
t3.5
требование абсурдное, т.к. в USB/BT/Ethernet/WiFi не выдерживается.
я аппаратных СОМ-ов уже лет 5 не видел.
0
Ну, коллега, не могу согласиться. Обычный какой-то модуль на МК, часто-густо без всякой RTOS, работает Слейвом. И что мешает ему ловить «тишину» длительностью 1,75 мс? Ничего. Зато ответы на запросы получаются (как я приводил пример) очень быстрыми — через 2 мс уже пошел колбасить. И это не мой модуль такой уникальный. Я юзаю ОВЕНовские модули, частотники от Митсубиши — все отвечают шустренько. Во всяком случае, именно панель оператора ИП320 со своим ответом через 50 мс выглядит У.Г.
0
требование абсурдное, т.к. в USB/BT/Ethernet/WiFi не выдерживается.

Для MODBUS поверх TCP/IP есть отдельная спецификация. В данном случае, идет разговор о “modbus over serial line”.

аппаратных СОМ-ов уже лет 5 не видел.

Я тоже. Но это не говорит о том, что RS232 перестали использовать. Просто, для современных ПК, этот интерфейс не востребован. Но в промышленной автоматике, поверьте, RS232 и RS485 до сих пор используется «в полный рост».
0
В принципе, теперь мы должны отстучать часиками тот же t3.5, но я ставлю программу на прием новых запросов сразу же. Все равно Мастер дождется паузы, потом рассмотрит ответ Слейва, а уж потом что-то может спрашивать.
На мой взгляд, это не совсем правильно. Скорее делать надо так:
1) В режиме ожидания постоянно принимать символы и мониторить паузы между ними.
2) Если принят символ и пауза между ним и предыдущим превышает 3.5t — это начало фрейма. Начинаем принимать (переход к п.3, как вариант — поскольку принятый байт является адресом, то можно сразу же его проверить и если не совпадает — вернуться к п.1). Если пауза меньше — игнорируем и возвращаемся к п.1.
3) В режиме приема — складываем в буфер приема, выставляя таймауты 1.5t и 3.5t. Если сработал первый — символ битый, валимся в п.1 и ждем новый фрейм, если 3.5t — фрейм принят, обрабатываем. Также можно сразу же парсить фрейм и определять конец фрейма по содержимому (AFAIK, они все либо имеют фиксированный размер, либо инфу о собственном размере в составе данных).
4) Обработав фрейм — выплевываем ответ и возвращаемся к п.1.
Т.е. ключевое отличие — ловить паузы в 3.5 символа как маркер для переключения в режим приема фрейма.
0
  • avatar
  • Vga
  • 08 ноября 2013, 04:35
Скорее делать надо так
… Да, пора уже выкладывать программу, ибо мои многословные объяснения плохочитабельны.
Я и делаю примерно так, как ты пишешь. Если говорить о «ключевом слове» — именно так. Каждый принятый байт (по его окончанию) запускает таймер на предмет ожидания конца фрейма. По ходу дела, если начал приниматься следующий байт (задействовано соответствующее прерывание УАРТа) — проверяю, а как там себя чувствует таймер — не натикал ли он t1.5? Если не натикал — принимаю дальше. Если натикал — тоже принимаю дальше, только флажок подниму. Ну, когда до парсинга дойдет, флажок проверится самым первым...
Адрес сразу не проверяю. Считаю, что прием всего фрейма отличается от неприема (но с тем же постоянным контролем t3.5) настолько мало, что нет смысла яростно отрицать работу с чужим фреймом. Пусть себе качается. Когда кончит — мы его быстро вычислим и не станем дальше обрабатывать.
В общем, вчера собрал проект с чистым Модбасом и с нихуйом больше. Компилируется. Ща его проверю, не выплеснул ли с водой ребеночка, да и начну описывать словесами. Постараюсь коротко :)
0
Вот кусок отработки прерывания: прерывание по первому принятому биту (не путать с прерыванием по принятому байту):
case 0x06:				// Vector 6: UCSTTIFG, 1-st bit of a new char detected

		ResetTimer();							// Timer reset, just to show: no silence
		if( STATE_RCVE == MBState) {
			if( TA1R > Nt15_code) {				// t1.5 from the last 02 interrupt!
				ER_frame_bad = EV_HAPPEND;		// This error will be processed later
			}
			break;								// Nothing more to do in RECEIVE state
		}										// In ALL other states 1-st bit turns us to RECEIVING
		MBState = STATE_RCVE;					// Change State of MBMachine immediately!
		MBIndx = 0;								// "Clear" buffer
		ER_frame_bad = EV_NOEVENT;				// New buffer, no old events
		DriverToReceive();						// RS-485 driver - to receive mode
		break;

То есть, я просто сравниваю состояние счетчика с кодом, соответствующим t1.5:
TA1R > Nt15_code
Это кагбэ и не флаг. А вот если оказывается, что счетчик таки добежал уже до 1,5 символьного времени с момента окончания предыдущего символа, то ставлю флаг ER_frame_bad.
А флаг t3.5 таки есть — он ставится в прерывании от таймера.
0
только к 1.5 добавить «чуть чуть» на прием остальных бит
Добавить длительность 1 символа. То есть, сравнивать не с t1.5, а с t2.5. Именно это и есть время между приемами двух символов, которое отвечает 1,5 символам паузы.
Ну да. Можно. Но в МСП430 есть прерывание, вход-выход в него занимает несколько микросекунд… На фоне сотен микросекунд не жалко :)
Хотя… Да, для атмеги, например, нужно придумывать — ибо в ней не предусмотрено прерывание по началу приема символа. Ну, не знаю, может и есть смысл прерываться только по приему байта — и прерываний меньше, и переносимость на атмегу появится.
Я ввел прерывание по стартбиту потому, что логика красиво упростилась… Но тогда вообще каша в голове была. Теперь надо посмотреть на уже работающую программу. Может и не сложно будет рихтануть, опуститься до уровня атмеги :)
0
жду вторую часть
сам недавно разбирался и от терминов мозги опухли
никак не мог понять, при чем тут катушки и какие-то регистры с адресами

все можно было бы намного упростить
если я доделаю панель управления станком, то напишу тоже про модбас
0
сам недавно разбирался и от терминов мозги опухли
комиксов не нашлось?
бида-пичалька…
+2
жду вторую часть
Та, понимаешь, хочется как лучше… Из живого проекта вырезаю понемногу «чиста модбас». С учетом того, что еще и далеко не всем интересно будет МСП430, убираю по максимуму ссылки на специфические хедеры, связанные с этим семейством. В результате даже такие вещи вставляю в свои хедеры (х.з.почему stdint.h у меня брался из мсп-ной driverlib, но я пока с этой студией CCS плохо разобрался):
typedef   signed char    int8_t;
    typedef unsigned char   uint8_t;
    typedef          int    int16_t;
    typedef unsigned int   uint16_t;

КАРОЧИ, дурью маюсь. Но самое страшное — после такого бешенного обрезания теперь трудно проверить, остался ли проект рабочим. То есть, продолжает ли нормально работать с Мастером. Вот этому теперь посвящу немного времени. «Слепой» отладке по вторичным признакам.
0
у меня вот с типизацией напряги были когда с веховскими девайсами работал. ну что они курили, когда тип представляет что то типа
unsigned int i; //Значение
byte d; //количество знаков после запятой
byte m; //множитель

при этом множитель всегда должен быть 1, 10 или 100, но при этом значение 0 или 99 ошибкой не будет.
по идее в самом девайсе интерфейс реализован в виде перемещения десятичной точки. при этом выбирается или десятичная точка или множитель x10/x100. и точку и множитель поставить не удастся. при этом через modbus ни кто этого сделать не мешает.
0
Ну, там тоже люди. Пришел практикант из индии
Я намучился, когда склеил freemodbus со своим проектом. Разные определения одной сущности иногда создавали проблемы. Тоже еще, одна из причин (для меня) написать с нуля. Теперь как-то принял для себя вот эту uintХХ_t форму — и уже ее придерживаюсь везде.
0
Теперь как-то принял для себя вот эту uintХХ_t форму — и уже ее придерживаюсь везде.
Это-то правильно, но вот определять stdint-типы в своих хедерах не следует. Они должны предоставляться компилятором.
0
«Слушай. я по глазам вижу, ты хороший человек!»
Помоги разобраться.
Я же говорю: некоторые (если не большинство) примочки техасской Студии я не понимаю. например, какого хера она не берет тот хедер stdint.h из инклудной директории
c:\ti\ccsv5\ccs_base\msp430\include\
— а хочет из имеющейся у меня «локальной» директории с driverlib. Саму driverlib, равно как и ее директорию я держу в основном проекте, а вот для нашего учебного примера — вырезал. тут компилятор и начал зудеть. Ну, я разобрался, чего ему не хватает — и накидал дефайнов. Понимаю, что не очень красиво...
Беда в том, что со Студией мало кто работает. На техасском форуме тоже довольно вяло.
0
Понятия не имею, я CCS даже не ставил. Проверь пути к инклюдам в настройках студии/компилятора/проекта. И проверь, может ты случайно вместо #include <stdint.h> подключил #include "stdint.h"?
0
Да я уже вижу, что вполне естественная «сверблячка» поскорее выкласть библиотеку — зло. Сейчас сижу и тихонько рефакторю… Нашел уже одну ощибку, которая проявилась бы при попытке изменить бодрейт от моего дефолтного 38400. Перетаскиваю, чищу, комментирую… Потом таки разберусь и с инклудами. А то что ж это… Не солидно :)
И еще. Хочу все же закинуть это в виде динамической (?) либы, чтобы натурально не таскать из проекта в проект. В старые времена у меня так и было — куча драйверных. математических и еще х.з. каких функций укладывалась в отдельные директории и в мейкфайле организовывались правильные зависимости. Но с этой новой Студией я слегка растерялся, мягко говоря. Потому — надо будет еще разобраться.
Приношу свои извинения уважаемым коллегам за (теперь уже очевидно) преждевременную публикацию первой части. Вторая — сырая…
0
stdbool.h:

typedef int	bool, _Bool;

На восьмибитном контроллере, ага. Никому нельзя верить.
0
А про расширение этого протокола ELAM нет желания написать? :).
В нём увеличено количество адресуемых устройств до 2047, плюс ещё к ним же 247 модбас устройств на ту же линию можно подцепить, т.е. совместимость по адресации полная. Добавлены какие то новые функции. Хотя и в модбасе можно свои функции реализовать.
0
А про расширение этого протокола ELAM нет желания написать?
Чтобы самому понять? Разве что…
Посмотрел, что это такое. Вполне логичное расширение. Но мне хватает и адресов, и функций. Скажу более того: весь смысл данной моей публикации состоит в том, чтобы популяризировать простой Модбас среди эмбеддеров. Показать, что за дополнительный килобайт флеша можно получить очень проверенный и широко применяемый интерфейс — и не натягивать всякие и2С и эспиаи на несвойственные им задачи (не говоря уже о самопальных велосипедах). Так что дополнения к Модбасу (не снимающие его главный «недостаток», запрос-ответный принцип работы) — скорее идеологическая провокация :)
0
Спасибо за статью, но вот не совсем понял что такое «Контролька CRC»? как формируется содержимое? и откуда берется?
0
Ладно, за жаргон отвечу. Но суть CRC пояснять не буду — читай Вики, читай описание Модбаса.
Так вот, принятая в стандарте терминология: подсчет CRC по сообщению дает то, что и называют CRC. А вот CRC, записанную передающей стороной в сообщение, называют контрольной суммой (я назвал контролькой).
Из этого следует, что принятое сообщение содержит ранее посчитанную CRC, записанную в конце в виде контрольной суммы, а принимающая сторона должна произвести расчет по сообщению и сравнить с (находящейся в последних 2-х байтах) контрольной суммой. Но прикол в том, что, если включить последние 2 байта в расчет CRC, то результатом, при отсутствии ошибок, будет 0.
В общем, я не скажу лучше, чем стандарт :)
0
С CRC вроде разобрался но вот не пойму почему полином CRC 16 IBM начинается с 2 в 16 степени это ведь уже за пределами 16 бит
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.