Робот - как разделить прерывания?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Имеем:

1. Arduino Uno R3.

2. Два ведущих колеса с энкодерами.

3. Приемник для IR-пульта.

4. Прочую периферию не существенную для данного вопроса.

Насколько я понимаю, наиболее прямой способ работы с энкодерами - посадить каждый из них на свое аппаратное прерывание. И IR канал связи также требует своего прерывания.

Т.е. потребность в аппаратных прерываниях - 3 штуки, а в наличии только 2 штуки.

Имеется ли изящный способ выйти из этого положения?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

andriano, есть ещё масса прерываний PCINT, правда они не умеют FALLING или RISING, срабатывают в обоих случаях. А вот прерывание компаратора -умеет. Но в любом случае всё это не имеет готовых ардуиновских функций, тут нужно самому писать в конфигурационные регистры.. :)

inspiritus
Offline
Зарегистрирован: 17.12.2012

Вам нужен контроллер прерываний- устройство, которое при приходе уровня заданной полярности, или фронта/среза сигнала на один, или несколько входов, генерировать заданный уровень, или фронт/срез синала на выходной линии , заведенной на вход прерывания процессора, одновременно запоминая в регистре-защелке состояния всех входных линий для последующего программного опроса из обработчика прерываний на предмет : кто квакал.

это можно сотворить в устройство той, или иной сложности ( в зависимости от задачи) с помощью дискретной логики.

в самом простом случае заводите оба энкодера и что то третье ( и можно четвертое:) на входы мк и входы  чеготто вроде 155ле2 ( 4или-не) , а ее выход соответственно на вход прерывания. Процессы небыстрые, должно успевать при приходе сигнала на вход прерывания уйти в обработчик и быыыстренько опросить входы мк на предмет: кто квакал.

я такую штуку городил для клавиатуры на резисторах от дисплейного шильда. Потом правда стал ловить только одну кнопку , самую близкую к минусу как кнопку перехода в меню ( переход в прерывание-выставление флага-выход из прерывания, при наличии флага в начале следующего лупа проваливаемся в меню). Потом вообще от этой клавы отказался навсегда.

логическое развитие независимого контроллера прерываний - контроллер приоритетных прерываний. Кстати интересная задачка для сотворения на отдельном процессоре для включения в ардурины. Шильд контроллера приоритетных прерываний ( хехе).

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

inspiritus, о чём вы говорите, какой контроллер прерываний? У 328 меги почти на каждой ноге прерывание.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Не все умеют работать за пределами опубликованных библиотек и возможностей IDE. Воткнуть древний четырнадцатиног может оказаться проще, чем копаться в доках и продвинутых методах обращения к ЧИИТЕРСКИМ возможностям 328-й меги.

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

, и я получил, что хотел. Для себя же любимого , не для продажи. Да и ног ( на каждой из которых интеррапт сидит) иногда катастрофически нехватает: дисплейчик, клава, (4х5 без и2с) , и вот осталось пяток ног для датчиков и исполнителей :(

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

 

inspiritus, насчет завести оба энкодера на одно прерывание, а IR-приемник оставить на другом, я думал. Но решение это для меня неочевидно. В первую очередь, я как-то не представляю, как определить, кто именно квакнул. Фактически с каждого энкодера идет по две серии импульсов близких к меандру сдвинутых на четверть периода. Если от одной ноги энкодера мы получили импульс (прерывание), то опросив другую ногу, мы узнаем направление вращения. Т.е. допустим, прерывание срабатывает по фронту. Если в этот момент на втором контакте датчика 0, значит, крутимся в одну сторону, если 1, значит - в другую. Если мы сложим сигналы от энкодеров, то, получив, скажем, что (после фронта, вызвавшего прерывание) на первом энкодере 1 и 0, а на втором 1 и 1, как понять, который из них вызвал прерывание?

Потом, если использовать единственную ИЛИ-не, то из двух фронтов будет проходить только первый. Второй  при логичесвкой "1" на другом останется незамеченным.

И еще, насколько я помню, у ТТЛ-логики уровни довольн несимметричны: гарантированный "0" - от 0 до 0.4 В, гарантированная "1" - от 2.4 до 5 В, а порог где-то 1.3 В. Т.е. на уровень 2.0 В ТТЛ должна трактораять как "1", а KMOП - как "0".

Да и жрет ТТЛ логтка прилично. Я уже размышлял о том, чтобы поставить на энкодеры реверсивные счетчики, и с них через сдвиговые регистры считывать информацию, на что-то мне такое решение не нравится как уж слишком аппаратное, т.е. не относящееся к изящным.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

dimax пишет:
У 328 меги почти на каждой ноге прерывание.
Ну и что?

В первом посте определенно указано - Uno.

Замена Uno на Мегу никак не может считаться изящным решением.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

andriano, вы не поняли :) "328 мега" это модель микроконтроллера, на котором собран в частности Ардуино Уно.  Изучите даташит, в частности раздел про прерывания PCINT, получите сразу около 20 аппаратных прерываний.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Спасибо, действительно не понял.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Аппаратное и есть изящное. Вы просто не умеете их готовить :)

155 для примера, поставьте что придется :)

прерыванием Вы ловите сам факт какого то события. Какое оно именно узнаете , опрашивая ноги мк, куда эти энкодеры и что то еще заведено.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

inspiritus пишет:
Аппаратное и есть изящное. Вы просто не умеете их готовить :)

155 для примера, поставьте что придется :)

прерыванием Вы ловите сам факт какого то события. Какое оно именно узнаете , опрашивая ноги мк, куда эти энкодеры и что то еще заведено.

Согласен, что аппаратное - изящное. Здесь, правда, тоже есть некоторые непонятки: сразу из нескольких источников следует, что процедура delay препятствует нормальному прохождению прерываний - последние теряются. Ну да ладно - с этим будем разбираться потом.

Вернемся к нашим баранам, т.е к тому, как ловить два события на одно прерывание.

Как в нормальном случае выглядит работа с энкодером:

- левый энкодер подключаем к ногам 2 и 4, устанавливаем INT 0,

- правый энкодер подключаем к ногам 3 и 5, устанавливаем INT 1.

В процессе работы:

- если пришло INT 0, опрашиваем 4 ногу: если "0" - движемся вперед, если "1" - назад.

- если пришло INT 1, опрашиваем 5 ногу: если "0" - движемся вперед, если "1" - назад.

Теперь, допустим, освобождаем INT 0 от энкодера (для IR), и сигналы, которые раньше были подключены к 2 и 3 объединяем при помощи НЕ-ИЛИ, пролучаем:

При таком схемном решении мы будем ловить прерывания только от левого колеса (если настраиваем на передний фронт энкодеров и, соответственно, задний после инверсии) при движении вперед и только от правого - при движении назад.

Или я что-то не понял со схемой?

inspiritus
Offline
Зарегистрирован: 17.12.2012

4 и 5 остаются, с 2 и 3 сняли , объединили по или и завели на 3 

По приходу прерывания на 3 опрашиваете состояние 4 и 5 в обработчике и делаете выводы о движении энкодера, все остальное время выполняете основной loop. 

Есди генераторов событий много , то каждый заведен на простой вход для опроса состояния и на объединение по или для генерации единого прерывания.

в качестве входа для экономии ног можно использовать какойнить расширитель i2c

эта конфигурация справедлива для медленных процессов, при которых мк успевает с приходом прерывания уйтина обработчик и опросить порты. Это время можно посчитать или измерить ( выставить какойнить выход, сбросить его и посмотреть осциллографом) . Для более быстрых нужно событие инициатор прерывания ловить триггером-защелкой, состояние которого можно будет опросить независимо от пропадания сигнала-инициатора и после опроса сбросить программно.

возможно в применении для энкодеров OR не прокатит посмотрите на XOR,  можно попробовать применить схему на 74LS74 и паре триггеров шмидта, что то вроде этого , если сигнал с энкодеров чистый, триггеры шмидта и RC цепочки на входе можно не применять

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Начнем с конца.

XOR тоже не подходит: нам нужно отследить передние фронты сигналов с обоих колес. Передний фронт левого колеса превращается в передний фронт после XOR, передний правого - в задний, после чего то же самое происходит с задними фронтами. Т.е. XOR не обеспечивает передний (или задний) фронт сигнала на передний куаждого из смешиваемых и, кроме того, реагирует на задние фронты, чтонам не нужно.

Что касается 74LS74, по даташиту я что-то не понял, какую логическую функцию она реализует и, кроме того, вроде, 5 нога - это выход Q.

Т.е. что она будет выдавать, я нарисовать не могу.

 

Но давайте допустим, что нам все-таки удастся найти функцию, которая обеспечиват повторение на своем выходе переднего фронта каждого из сигналов и не реагирует на задние.

Цитата:
4 и 5 остаются, с 2 и 3 сняли , объединили по или и завели на 3 

По приходу прерывания на 3 опрашиваете состояние 4 и 5 в обработчике и делаете выводы о движении энкодера,

Давайте для определенности посадим то, что сняли с 2 и 3 на 6 и 7 соответственно. И по приходу прерывания считываем все с 4 по 7. Мы знаем, что раз прерывание настроено на передний фронт, то с контакта, заведенного на прерывание соответствующего колеса (6 или 7) мы обязательно получим 1 по колесу, вызвавшему прерывание.

Давайте перечислим все комбинации:

4 5 6 7 - контакты

0 0 0 0 - невозможная комбинация, либо 6 либо 7 должно быть 1

0 0 0 1 - правое колесо вращается вперед

0 0 1 0 - левое колесо вращается вперед

0 0 1 1 - мы не можем определить, с какого колеса пришло прерывание

0 1 0 0 - невозможная комбинация, либо 6 либо 7 должно быть 1

0 1 0 1 - правое колесо вращается назад

0 1 1 0 - левое колесо вращается назад

0 1 1 1 - мы не можем определить, с какого колеса пришло прерывание

1 0 0 0 - невозможная комбинация, либо 6 либо 7 должно быть 1

1 0 0 1 - правое колесо вращается вперед

1 0 1 0 - левое колесо вращается вперед

1 0 1 1 - мы не можем определить, с какого колеса пришло прерывание

1 1 0 0 - невозможная комбинация, либо 6 либо 7 должно быть 1

1 1 0 1 - правое колесо вращается назад

1 1 1 0 - левое колесо вращается назад

1 1 1 1 - мы не можем определить, с какого колеса пришло прерывание

 

Итого, мы не можем классифицировать треть возможных комбинаций (4 из 12, остальные 4 невозможны).

inspiritus
Offline
Зарегистрирован: 17.12.2012

Там д-триггер, насколько я помню, пишет/переписывает... 

заведите на прерывания по ксору по одному каналу энкодеров, в обработчике можно попеременно менять после фоллинга на райзинг, главное отловить факт изменения, остальное программно.

в конце концов можно одновибраторами формировать короткий импульс от каждого среза и завести их монтажным или на инт, или от фронта и объединить открытыми коллекторами , как разновидность монтажного или, неважно, кто к земле притянул, важно, что был ноль. Импульс должен быть достаточно коротким, чтобы пренебречь вероятностью их одновременного формировпния. Или пограммно опрашивать все возможные первопричины. 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Если я правильно понял алгоритм,

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

- прерывание по любому изменению любого их ЧЕТЫРЕХ сигналов (не важно, передний или задний фронт),

- сравниваем с предыдущим, выясняем, что именно и как изменилось,

- определяем, интересует ли нас то, что произошло,

- если интересует, отражаем это изменение (например, увеличиваем/уменьшаем счетчик для нужного колеса),

- если не интересует - игнорируем,

- запоминаем текущее состояние для анализа в следующем прерывании.

Что-то получается многовато прерываний: вместо по одному по переднему фронту одного сигнала по каждому колесу - по обоим фронтам всех четырех сигналов - в 4 раза больше.

Кроме того, нельзя гарантировать, что сигналы от разных колес не придут одновременно.

 

PS. Пока не заставил работать энкодеры: пока они предпочитают выдавать в основном нули. Но, вроде, есть подстроечники. Пришлось разобрать тележку, чтобы до них добраться. Завтра буду пробовать.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Inspiritus привет!

Меня зовут Евгений, в электроннике с 1974 с программированием то же дружу но не так чтобсупер профи... Занимаюсь желдор моделизмом. Есть макет, вся система светоблокировки, управления стрелками и поворотным кругом реализована на 155 серии. Ну вроде бы как работае, но достали помехи по земле, а тут еще Семинар в нашем клубе состоялся в Ноябре - ну и загорелся Ардуиной.  Пока читаю и собираю мысли в кучу. Однако возник достаточно серьезный СИСТЕМНЫЙ вопрос. У меня 12 светофоров, 8 контрольных участков контролирующие проход локомотива (однозначно надо обрабытывать внешнее прерывание (думаю типа PCINT вполне применимо). Поставить светофор в красный, а предыдущий участок открыть (зеленый). Затем  19 стрелок, от  положения которых зависят состояния выходных светофоров. Они управлялись ~16В (солиноидные- один из источников помех!!!) Хочу перевести на серво и управлять от статических ТУМБЛЕРОВ, поскольку менять на кнопки не очень хочется, да наглядность потеряю, в каком состоянии стрелка стоит.

Итак вырисовывается 8 прерываний от конр участков (геркон - на локомотивах неодимовые магниты стоят) время порядка 5-10мс (!), 19 PCINT от тумблеров и еще надо 19 выходов для управления сервами этих самых стрелок, ну и еще как минимум 12 выходов для управления исполнительными реле (отключение рельсы на контр участке + установка светофора). Итого 58 входов!!! Из них 27 внешние прерывания. И никак не могу понять как это минимизировать, хотя и держу в голове , что у Ардуины вход - есть он же и выход. Главное согласовать по нагрузке.

Вот и решаю, пока первую задачу со стрелками, как и на чем это лучше реализовать? Каким образом нарастить Ардуину. Достаточно ли быдет двух MEGA, и ка ких совместить??? Пока уменя для проб UNO.

Мне очень нравиться идея контроллера прерываний.. Есть каике наработки, схемы???

Совет Бывалого, как говориться нужен.

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Вам не требуются "прерывания". Вполне достаточно иметь 58 входов и в цикле опрашивать их состояние. Скорости работы будет более чем достаточно. 16Мгц Ардуина (что мини, что про, что мега2560) выполняет почти 16 команд в 1 микросекунду. На опрос ваших ног требуется пусть даже по 100 команд .. итого 5800 / 16  менее .. 0.4 миллисекунды. И? Зачем вам прерывания? :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

andriano пишет:

Я уже размышлял о том, чтобы поставить на энкодеры реверсивные счетчики, и с них через сдвиговые регистры считывать информацию, на что-то мне такое решение не нравится как уж слишком аппаратное, т.е. не относящееся к изящным.

физики - лирики , аппаратчики - программисты....
кто-то дребезг давит кондёром , кто-то аппаратно....
я за аппаратную составляющую , чтобы облегчить работу МК

Sindbad
Offline
Зарегистрирован: 08.12.2015

EuBeginer пишет:

СИСТЕМНЫЙ вопрос. У меня 12 светофоров, 8 контрольных участков

Цитата:

Затем  19 стрелок, 

Много ли известно удачных реализаций монстрообразных конструкций? В большинстве случаев монстры умирают еще до рождения. Вот будет у вас новая хотелка с пятнадцатью светоформи и десятью стрелками, нового монстра нужно проектировать?

Системно задача решается через разработку трех устройств-датчиков, подключаемых к общей шине (или двум, трем шинам). Работа контроллера - получать данные и выдавать команды, общаясь со всеми устройствами по возможности единообразно. 

EuBeginer
Offline
Зарегистрирован: 16.11.2015

ЖД макет всегда монстр. В общем не очень конструктивно, а вот Arhat109-2 спасибо. В общем пока все эти две недели читал  и опыта набирался, задачка судя по всему очень изящно решается через ШИНУ IIC! Пара 16ти канальных контроллеров для серв типа PCA9685 и пары расширителей входов/выходов МСР23016. Тут и тумблеры можно подключить. И едйствительно все вести опросом, но от 8 прерываний не уйти, поскольку для всех серв надо делать некоторые задержки (30-40мс)на отработку (по крайней мере так пишут ПРОФИ) так , что время выполнения всей программы может быть и превысит 1-2мс, а прерывание пропустить нельзя! Иначе авария. А при шине IIC все решается элементарной УНО. Восьми контактов при таком решении там всегда можно будет найти. Теперь надо подумать как красивенько это все реализовать, хотя серво контроллеры надо будет поближе к узлам стрелок ставить благо шина это позволит.

inspiritus
Offline
Зарегистрирован: 17.12.2012

Идвас не сильно быстрая штука, библиотеки тормознутые. Про объединение прерываний уже все, что нужно написал. 

Соглашусь с Arhat109-2

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

Если поезд вблизи точки C , то зачем опрашивать все поле? Сделайте адаптивный алгоритм опрашивайте состояние B и D - выиграете время.

 

Logik
Offline
Зарегистрирован: 05.08.2014

inspiritus пишет:

Идвас не сильно быстрая штука, библиотеки тормознутые.

Все так при работе шины на 100КГц, при работе на 1МГц все летает, и такая скорость хороше согласуется с скоростю процессора, никто ничего не ждет долго. Применять I2C в данной ситуации сомнительно (требует более подробного рассмотрения) по соображениям помехозащищенности. Помехи от колес и щеток локомотива. 

Выбор сеть или монстр не так прост. У сети кроме вопроса протокола еще надо продумать как питать эти десятки отдельных датчиков. Я бы  не делал их 3-х типов, делал бы один, обслужывающий допустим пару сфетофоров+стрелку(или пару стрелок)+датчик прохода поезда. Конкретно состав устройств по реальным возможностям контроллера без расширений. Один датчик обслуживал бы группу устройств где она по факту  есть или одно устройство где группировать не удобно. Думаю я про сеть однопроводку,  на OneWare, её скорость низкая но опросить пару десятков датчиков за 5-10мс она успеет, а проблему не пропустить проход поезда решат сами датчики. Симпатично вырисовывается на неё: шина - экранированый провод, экран используется как земля, питание датчика от рельс.

У монстра свои плюсы. В целом это проще, но сильно много проводов. Я бы сразу исходил из того, что выводов ардуины не хватит и строил паралельную шину и регистры.  Это и решит проблему маштабируемости на будущее, и обезопасит контроллер от электрических проблем. Про прерывания - забудте. Для монстра опрашивать пару десятков вводов за милисекунду вообще не проблема. Ему кстати больше как бы и делать нечего - только опрашивать, проверять есть ли изменения, если есть - рагировать,  и снова опрашивать.

ПС. ЖД макет и сейчас  стоит у меня за спиной, ждет очереди на автоматизацию, еще не скоро, но яиногда думаю о нем, он скромней вашего. Выбор сеть или монстр для себя не решил пока.

ППС. Этот разговор достоен отдельной темы.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Всем спасибо за советы и комментарии. С прерываниями от контрольных точек я все таки попробую поэкспериментировать. Остальное да, пойдет по опросу. Кроме того, у меня уже есть Жесткая логика, сделаная еще в 2010 году, и в принципе контрольные участки я могу отслеживать аппаратно.  Всем, и в частности для Logik совет, никаких питаний от рельс! Вот тут то и сидит "собака". Рельсы это должны быть одни блоки питания, цифровая часть совершенно другие с развязанными землями. Я почему и затеваю всю эту переделку. Поезд идет, искры летят - логика живет своей жизнью. Это не DCC (не цифра) в прямом ее понимании, когда идет программирование движение поезда. Макет сделан не для демонстраций, а именно для игры мальчишек, которые любят крутить реостаты увеличивая скорость, щелкать тумблерами для переключения стрелок как на настоящем пульте в диспетчерской на настоящей железной дороге 60-90х годов. И гонять паровозы туда сюда, решать траспортные задачки по перестановке вагонов и т.п.

В общем педелюсь своими экпериментами.

Отдельная тема??? Да нет не думаю, на наших жд форумах есть такое обсуждение, но мы не такие корифеи как Вы в программировании и прочее... Я тут, чтобы если что посоветоваться, как програмнуть тот или оной момент. Но если Вы считаете, что имеет смысл - Тогда наверное можно попросить Модераторов создать такую Тему "Ардуино и ЖД моделизм". И перебросить туда эту переписку начиная с моего вопроса от 16 Декабря.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Проектировал в свое время макет ж/д для одного ПТУ, в старые добрые времена .. никаких "Ардуино", все "на пальцах", пардон реле и "автоконтактах" стрелок (стрелка - она же микро-переключатель тока для паровозиков, дабы не коротнуло) да, тоже с "реостатами" дабы "крутить-вертеть" .. только проектировал, не в курсях построили или как.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Ха! ну да. Когда все было на солиноидах - так им по барабану все помехи, даже не дергались особо. Там чтоб сработало конкретный ток должел был пройти. Ну вот, когда я с этими стрелками присобачил ТТЛ логику, вот тут оно все и выползло. Часть помех я задавил, но не все 100%. Поэтому и ухожу на чистую электронику - стрелки на сервы, полная изоляция от рельс, никаких контактных рельс - герконы, в общем гальваническая развязка на все 100%

Но времена, конечно, были интересные... Жизнь же...

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Да не. Я про то, что когда делаешь "разворотный круг" получается коротыш, если не сделать стрелку специальным образом, чтобы она работала ещё и как "микропереключатель" отсоединяя лишнее от тока. Там ваще круто получалось с такими стрелками: непроходной путь "автоматически" обесточивался.

Logik
Offline
Зарегистрирован: 05.08.2014

Arhat109-2 пишет:

 непроходной путь "автоматически" обесточивался.

При правильном подходе это даже хороше. Можно поезд загнать на него и остановить. Просто питание на него надо подать отдельно и управлять этим процессом чем нибудь, например ардуиной ;)

Про помехи. Обратите внимание, я не предлагал питать от 2-х рельс как паравозики. Общий отдельно, по оплетке, от рельс грубо говоря, только + силовой. Далее через фильтр, стабилизатор... Информационный провод в оплетке. При надежном общем проблем быть не должно. И БП естественно 2. Один нельзя ещё и потому, что при остановке паравозика обесточивалось бы все. А гальваноразвязка в общем то не обязательна.

Вобще помех боятся не надо, их надо учитывать. Настоящий электровоз с килоамперами тока дает помех куда больше, но по рельсам работает система блокировки, автоматика, и работает.

О реостатах в питании паравозика. Давно не видел, видел только ШИМ.

DCC - наше неизбежное светлое будущее. Интересно есть ли такие вещи на ардуино. 

Еще вопрос, а переводить стрелки на сервы зачем? Для реализма, чтоб медленей переключались? Я делал  их приводы из старых советских релюх, на ждмодельных форумах вычитал как. Замечаний к ним нет. И компактны очень.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Реостаты??? Да навалом - FZ1  до сих пор используются. Не могу вот картинку приложить. У меня их два.

Цифра или Аналог - каждому свое.

Относительно Ардуино и жд моделизма - очень много всяких идей и уже наработок. Так что Ардуин идет в ЖД моделизм семимильными шагами. Одно из первых, что буду делать управление поворотным кругом. Тут задача как задать движение по кратчайшему расстоянию. Как сделать разворот на 180гр. Надо со знатоками ЖД дела поговорить. Как это на самом деле было...

Logik
Offline
Зарегистрирован: 05.08.2014

Пробежался по стандарту dcc - http://larkot.com/index.php/Введение_в_DCC,_Часть_1 так там же нефиг делать на ардуинке! И пульта не надо, с компа можно управлять. В общем для себя я точно понял, нефиг изобретать велосипед.

ПС. От засада, и это уже сделали до меня - http://forum.spur-1-russia.com/showthread.php?p=7365 :(

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Всем привет!  да давно не писал - учился, пробовал...

DCC это конечно здорово, но для поиграть, погонять. А вот для транспортных задачек не очень. Да можно задаавть маршруты и т.п., но это здорово для демонстрациооных макетов с заранее определенным сценарием. Кроме того надо учесть, что в каждый локомотив надо вставлять декодер. Магазинный стоит около 50 Евро. Так что в целом вещь получится дорогая. И не стоит огорчаться. Например поворотный круг до сих пор остается в ручном исполнении. Я хочу это также реализовать, но пока надо мне с элементарными вещами разобраться.

Кстати, Logik, там на втором сайте есть BR95009 - Дмитрий, он большой любитель "садовых дорог" (стандарт G), ну и в первую очередь он мне открыл глаза на Ардуино. Так что, если бы ВСЕ УЖЕ было бы сделано, мы бы и не делали. Кроме того, Ардуино это гораздо, в РАЗЫ!!! бюджетнее, к тому же не все дорогие наши Зарубежные Изготовители автоматизировали.

И еще, есть DCC, есть старый Аналог, когда все вручную, а есть симбиоз Аналог-Цифра, к почитателям которого я и отношу себя. Простора больше и я бы сказал, что полная компьютеризация - это не полная DCC, это скорее смесь, поскольку человеческий фактор он остается, а не только тупой алгоритм движения. Так что, Ваш выбор вполне заслуживает уважения. 

Но продолжим о прерываниях. Итак собрал макетную плату с РСА9685 подключил для отладки три сервы. Нашел углы SERVOMIN, SERVOMAX - все работает. (Насчет блоков питания - у меня их в достатке от 3А до 5А поэтому с питанием 2х десятков серв проблем нет, а светоблокировка (светофоры) едят от 5-10мА. Вообще, не о чем говорить.)

Далее, кроме РСА9685 на шину I2C поставил два расширителя МСР23016. Входные пины портов подтянуты на +5В и могут замыкаться на землю тумблерами. Каждому тумблеру предполагается поставить в соответствие СЕРВУ! Тумблер переключил - серва сработала, стрелку куда надо перевела.

Вопроса два:

1. у МСР23016 есть выход 6 INT. Это очень интересно, поскольку тогда, можно вести опрос только в случае ИЗМЕНЕНИЙ на порте. Его можно соединять с Ардуино пин 4-5 (INT0, INT1) ??? И если да, то обработка прерывания стандартная? Пример бы какой элементарный. Проблема с программированием таких нюансов... Как определить, кто сказал Мяу?

2. Каким образом считанный байт из порта разложить на биты и присвоить им имена? Вот собственно и все , что я хотел бы реализовать. По "разложению байта на биты" есть тема. Там Leshak имеет какие-то идеи. Может тут и не стоит обсуждать, а оставить там...? Однако там тема старая, Апрель 2012.... Может действительно сделать тему Ардуино и шина I2C для пультов управления (кнопки тумблеры) ???

Sindbad
Offline
Зарегистрирован: 08.12.2015

EuBeginer пишет:

2. Каким образом считанный байт из порта разложить на биты и присвоить им имена? 

Разбор байта на отдельные биты (истина/ложь):

bool bits[8];
byte data; // байт, из которого надо выделить биты
.....
for (byte i=0;i<8;i++) {
  bits[i] = data % 2;
  data = data / 2;
}
// bits[0] - значение младшего (нулевого) бита переменной data
// bits[7] - значение старшего (седьмого) бита переменной data

Выделение отдельного бита (в данном случае второго, если считать самый младший нулевым):

if (data & B00000100) {
  /* действия когда второй бит установлен (равен единице) */
}
else {
  /* действия когда второй бит сброшен (равен нулю) */
};

Выделение отдельного бита, номер которого зенесен в переменную n

byte x = 1;
for (byte i=0;i<n;i++)
  x = x * 2;
if (data & x) {
  /* действия когда n-й бит установлен (равен единице) */
}
else {
  /* действия когда n-й бит сброшен (равен нулю) */
}

Это?
 

 

 

arduinec
Offline
Зарегистрирован: 01.09.2015

bitRead(x, n) - читает бит с определенной позиции из числа
http://atmel.ucoz.ru/publ/bitread/1-1-0-97
Там же описание других операций с битами и байтами.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Oh!  Sindbad, Arduinec!!!

как говорят англичане - You make me a day!!!  Огромное спасибо за такое подробное объяснение. По сути это же работа с массивом! Я вчера начал писать черновик скетча, но уперся в то, что байт скачал, а как его в массив впихнуть...??? Давно уже не брал я шашек....

я так понимаю это выглядит как то так, но читаем сразу 2 байта (просто не знаю как, после чтения 1го байта, прочитать отдельно только второй?) и тогда наверное надо переменную data определить как array, поскольку уже не байт ???:

1 bool bits[16];
2 array data; // 2 байта, из которых надо выделить биты

 ??? 

3

..... 

Wire.beginTransmission (0x20);

Wire.requestFrom (0x20, 2); //чтение 2х байт

data = Wire.receive (); //присвоение массиву data булевые значения 2х считанных байтов

4 for (array i=0;i<15;i++) {
5   bits[i] = data % 2;
6   data = data / 2;
7 }
8 // bits[0] - значение младшего (нулевого) бита переменной data
9 // bits[7] - значение старшего (седьмого) бита переменной data

а вот строчку 6 я не понял, что означает

Sindbad
Offline
Зарегистрирован: 08.12.2015

EuBeginer пишет:
и тогда наверное надо переменную data определить как array, поскольку уже не байт ???

Двухбайтное целое число объявляется так:

unsigned int data;

Массив из двух байт объявляется так:

byte data[2];

И то и другое займет в памяти два байта, разница только в удобстве восприятия. В некоторых случаях два байта удобнее считать одним большим числом, а в других двумя отдельными числами. Слово array при объявлении массивов в С/С++ не используется.

EuBeginer пишет:
а вот строчку 6 я не понял, что означает

Это обычный алгоритм перевода числа в двоичную систему счисления: https://ru.wikipedia.org/wiki/%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%81%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F#.D0.9F.D1.80.D0.B5.D0.BE.D0.B1.D1.80.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D0.B5_.D0.B4.D0.B5.D1.81.D1.8F.D1.82.D0.B8.D1.87.D0.BD.D1.8B.D1.85_.D1.87.D0.B8.D1.81.D0.B5.D0.BB_.D0.B2_.D0.B4.D0.B2.D0.BE.D0.B8.D1.87.D0.BD.D1.8B.D0.B5

Пятая строчка - вычисляем самый младший (нолевой) бит, он равен остатку от деления на два (остаток от деления на два всегда или 0 или 1).

Шестая строчка - деление числа на два равносильно сдвигу его двоичной записи на один разряд вправо. Второй бит становится первым, первый - нолевым, нолевой теряется. Правило справедливо для любой системы счисления. В десятичной также, при делении на десять все разряды сдвигаются вправо и самый младший разряд теряется.

Хочу обратить внимание, программисты по разным переменным или ячейкам массива биты раскладывают очень редко и в крайне экзотических случаях. Как правило, наоборот, считается, что байт - лучшее место для хранения восьми бит. Извлечь бит или сразу группу бит из байта можно в любой момент, непосредственно в том месте программы, где это потребуется. См. мой второй и третий примеры, а также пример arduinec.

EuBeginer пишет:
, но читаем сразу 2 байта (просто не знаю как, после чтения 1го байта, прочитать отдельно только второй?)

Скажу сразу, опыта работы с I2C у меня нет. Какой библиотекой Вы пользуетесь? Библиотека на "самом официальном сайте" не содержит описания функции receive() : https://www.arduino.cc/en/Reference/Wire . Зато есть описание функции read() с примером получения шести байт : https://www.arduino.cc/en/Reference/WireRead

Если переделать их пример, получается что-то вроде:

unsigned int data;
bool bits[16];
..........................
Wire.requestFrom (0x20, 2); //чтение 2х байт с адреса 32
int count = 0;
while(Wire.available())    // slave may send less than requested
{ 
  if (!count)
    data = Wire.read();    // получаем первый байт, сохраняем его в в младшем байте переменной data, т.е. он займет биты с 0 по 7
  else
    data = data + Wire.read() * 256; // получаем второй байт, сохраняем его в старшем байте переменной data, т.е. он займет биты с 8 по 15
  count++;
}
if (!count==2) {
  /* обрабатываем ошибку - получено не столько байт, сколько запрошено */
}
for (byte i=0;i<=15;i++)
  bits[i] = bitRead(data, i); //этот способ потребует несколько больше тактов контроллера на вызов функции (по сравнению с делением на два), если так кажется лаконичнее и понятнее, то "экономить на спичках" не стоит.

 

arduinec
Offline
Зарегистрирован: 01.09.2015

К сказанному Sindbad могу добавить то, что в Си переменные типа bool занимают 1 байт, следовательно массив bool bits[16] займёт 16 байтов. Реально же он не нужен, так как с помощью функции bitRead(x, n) можно в любое время получить любой бит из 2-байтового числа.

Sindbad
Offline
Зарегистрирован: 08.12.2015

EuBeginer пишет:

1. у МСР23016 есть выход 6 INT. Это очень интересно, поскольку тогда, можно вести опрос только в случае ИЗМЕНЕНИЙ на порте. Его можно соединять с Ардуино пин 4-5 (INT0, INT1) ??? И если да, то обработка прерывания стандартная? Пример бы какой элементарный. Проблема с программированием таких нюансов... Как определить, кто сказал Мяу?

Я так понял, что главная проблема - успеть поймать момент замыкания геркона. Если использовать простой опрос, возникает опасность, что контроллер не успеет опросить все датчики и сигнал будет пропущен. Но если использовать прерывания, проблема несколько изменяется, но не исчезает! Да, первый замкнутый геркон будет пойман прерыванием. Но что произойдет, если одновременно замкнутся второй, третий герконы? Одновременно не значит невероятное событие - действительно одновременно. Достаточно замыкания следующих датчиков до того как завершена обработка предыдущего прерывания.

Я бы поискал решение в другом направлении. Каждый геркон завязать на триггер. Замыкание геркона взводит триггер, который будет удерживать высокий уровень на одном из выходов расширителя I2C. Циклически опрашиваем шину I2C. Если обнаруживаем сработавший датчик, обрабатываем его срабатывание в соответствии с логикой программы и даем через шину команду для сброса триггера.

Таким образом, каждый герконовый датчк займет два выхода расширителя - один для чтения состояния триггера, второй для сброса триггера.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Arduinec, Sindbad огромное Вам спасибо, за время и за опыт. Буду пробовать. Отпишусь.

Герконы и триггера, да тоже уже думал в этом направлении. Наверное так и реализую, попробую.

Однако, вероятность срабатывания двух и более герконов маловероятна. Герконы (контрольные участки) разбросаны по всему макету. Верояность срабатываения двух последовательных вообще невозможна, поскольку второй "догоняющий" состав остановиться у предыдущего светофора (красный) и будет стоять до тех пор пока на следующем участке "догоняемый" поезд не пройдет геркон и не откроет (зеленый) предыдущий участок. Герконы стоят после светофоров.

Я вопрос по прерыванию задал относительно тумблеров стоящих на МСР23016. Чего их зря опрашивать и занимать процессор. Будет измение - будет прерывание, тогда уже и считывать эту микросхему.

Спасибо вот за это - изящество - я бы не дошел, ей Богу. Ну действительно уйти на 256 вперед (2 в 8й)

data = data + Wire.read() * 256; // получаем второй байт, сохраняем его в старшем байте переменной data, т.е. он займет биты с 8 по 15

Буду пробовать. Отпишусь.

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Что-то компилятор ругается на эту строчку

bits[i] = bitRead(data, i);

Правда у меня другая переменная АС

bool AC[9];

byte ACBC [2];

.....

AC[i] = bitRead(ACBC, i);

говорит, что переменная ACBC не определена для этой области....

Sindbad
Offline
Зарегистрирован: 08.12.2015

EuBeginer пишет:
говорит, что переменная ACBC не определена для этой области....

Это закономерно.

Переменную ACBC Вы определили как массив двух байт, поэтому обращаться к ней нужно с указанием номера элемента: ACBC[0] или ACBC[1]. Именно на отсутствие индекса и ругается компилятор. Пример для чтения и разбора двух байт в этом случае будет таким:

byte ACBC[2];
bool bits[16];
..........................
Wire.requestFrom (0x20, 2); //запрашиваем 2 байта с адреса 32
int count = 0;
while(Wire.available()) {   // slave may send less than requested 
  ACBC[count] = Wire.read();    // получаем байт, сохраняем его как очередной элемент массива
  count++;
};
if (!count==2) {
  /* обрабатываем ошибку - получено не столько байт, сколько запрошено */
};
for (byte i=0;i<=7;i++) // разбираем на биты первый байт
  bits[i] = bitRead(ACBC[0], i);
for (byte i=8;i<=15;i++) // разбираем на биты второй байт
  bits[i] = bitRead(ACBC[1], i);

 

EuBeginer
Offline
Зарегистрирован: 16.11.2015
Для отладки сократил скетч до минимума. Подправил АСВС как 2 байта..
 
[code]
#include <Adafruit_PWMServoDriver.h>
#include <Wire.h>
void setup() {
      byte ACBC[2];
      bool bits[16];
      Wire.begin();
 }
 
void loop() {
  // put your main code here, to run repeatedly:
Wire.requestFrom (0x20, 2); //запрашиваем 2 байта с адреса 32
int count = 0;
while(Wire.available()) {   // slave may send less than requested 
  ACBC[count] = Wire.read();    // получаем байт, сохраняем его как очередной элемент массива
  count++;
};
if (!count==2) {
  /* обрабатываем ошибку - получено не столько байт, сколько запрошено */
};
for (byte i=0;i<=7;i++) // разбираем на биты первый байт
  bits[i] = bitRead(ACBC[0], i);
for (byte i=8;i<=15;i++) // разбираем на биты второй байт
  bits[i] = bitRead(ACBC[1], i);
}
[/code]
 
Все равно результат тот же
причем первая ошибка выглядит так:
...I2C_pwmtest_with_MCP23016:56: error: 'ACBC' was not declared in this scope
 
             ACBC[count] = Wire.read();
И далее идет:
I2C_pwmtest_with_MCP23016:65: error: 'ACBC' was not declared in this scope
 
                    boolean AC[i] = bitRead(ACBC[0], i);
и еще такое есть
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:103:32: note: in definition of macro 'bitRead'
 
 #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
 
 

И еще вопрос. А правильно пишем bool ? Я в ситнаксие не нашел такое сокращение. И еще там пишется , что дли булевой переменной равна БАЙТУ и bool bits(16);   равно 16ти! байтам.

Sindbad
Offline
Зарегистрирован: 08.12.2015

Вот так попробуйте:

#include <Adafruit_PWMServoDriver.h>
#include <Wire.h>
byte ACBC[2];
bool bits[16];
void setup() {
      Wire.begin();
 };

Переменные объявленные внутри функции существуют до момента завершения этой функции, поэтому глобальные переменные необходимо объявлять вне функций. В нашем случае их можно бы объявить внутри функции loop(), при этом нужно помнить, что при завершении функции сохраненные в переменных значения будут теряться, а при очередном входе в функцию переменные заново создаются и инициализируются нолевыми значениями. 

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Получилось! ну да оказывается их надо определить до SETUP!!!

Теперь можено попробовать с железом и выбрать подходящий вариант опроса регистров.

Ну кое-что стал понимать. Фу...у!!!

След этапом хочу попробовать опрашивать регистры по прерываниям от МСР23016. Надо посмотреть ниписание программок обработки прерываний как и куда они впихиваются. 

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Sindbad, есть кое- каие успехи однако и непонятка. Не хочется засорять форум дурацкими вопросами, до появления уже конкретных работающих скетчей и схем по I2C. Чувствую уже где-то на выходе. Но никак не могу найти где и как написать если позволите в личку?!

Sindbad
Offline
Зарегистрирован: 08.12.2015

На этом форуме нет ЛС.

Пишите, a.g.vasiliev [известное животное] mail.ru если смогу - помогу.

Но вот форум дурацкими вопросами точно не засорить. Он для того и предназначен, в общем-то.