Управление двигателем через таймер и прерывания с синхронизацией по задаче - как?

Тема в разделе "Arduino & Shields", создана пользователем Yoda, 10 июн 2013.

  1. roggedhorse

    roggedhorse Гик

    И, честно говоря, не верю, что двигателем можно так тонко управлять. Все же у любого вращающегося тела, имеющего массу, есть некая инерционность, которую видимо ваш код не учитывает.
     
  2. Yoda

    Yoda Нерд

    Наконец-то руки дошли до исправления ошибок.
    Ряд ошибок исправил, поведение движка стало более объяснимым. )))) Контроллер точно не рестартует, движок колбасит, но уже предсказуемо. Возникла следующая проблема. Как тут писали, прерывание отрабатывает дважды при прохождении угла призмы через оптопару. Я думал про это, как про возможную проблему, теперь она стала реальной. Таким образом отловленные тайминги прохождения грани - это и время прохождения грани и время прохождения угла призмы.
    Есть способ определить - как прерывание отработало - по растущему фронту сигнала, или по падающему?
    Как вариант - использовать на оптопары (их будет как раз две) прерывания типа EXT, задав параметром RISING. (а на задающий синхросигнал по-прежнему PINCHANGE) А есть возможность определить то же самое (проверяя какое-нибудь условие) на типе прерывания PINCHANGE? Я не уверен, что там будет четкий 0 или четкая единица...
    О великие гуру - что делать юному падавану? Объявлять прерывания и EXT и PINCHANGE?

    Специально посмотрел этот фильм. Речь шла про картинки на здании? Немножко не то. В интернетах навалом статей, как сделать векторный лазерный проектор. А купить готовый лазерный модуль повышенной мощности на ебее не проблема. Я бы просто повторил готовое, и не мучал бы вас глупыми вопросами. Я иду новой дорогой, готовых проектов DIY похожих на задуманный мной пока не встречал.
     
    roggedhorse нравится это.
  3. roggedhorse

    roggedhorse Гик

    не нужно бояться PINCHANGE :)

    Код (C):
    volatile uint8_t _PINDLastState;

    void setup() {
            ...
            _PINDLastState = PIND;
            ...
    }


    ISR(PCINT2_vect) {
            uint8_t pinState = PIND;
            uint8_t changes = pinState ^ _PINDLastState;
            ...
                    if (changes & (_BV(PD2))) {
                           // состояние ноги PIND2 изменилось
                           // зажечь светодиод, если PIND2 = HIGH, иначе погасить
                           if (pinState & (_BV(PD2))) PORTB |= _BV(5); else PORTB  &= ~(_BV(5)); // UNO
                    }      
            ...
            _PINDLastState = pinState;
    }
     
     
    Yoda нравится это.
  4. roggedhorse

    roggedhorse Гик

    Почитайте "Хроники лабораторий" (полную версию). Очень позитивно :)
     
  5. roggedhorse

    roggedhorse Гик

    Эта проблема легко решаема. Просто не используйте оптопару, а примените датчик линии. У большинства датчиков линий дискретный выход.
     
  6. Unixon

    Unixon Оракул Модератор

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

    Yoda Нерд

    Я долго сидел и втыкал в ваш кусок кода.
    Это понятно, если состояние ноги изменилось
    Вот именно в эту строчку я и втыкал около часа. Вопрос: а если тип переменной однобайтный(uint8_t), чему будет равно состояние переменной при логической 1? pinState=255? Это будет шкала от 0 до 255, как в случае с аналоговыми входами (только там верхняя граница другая)? Или это будет некое число с "зашифрованными" состояниями пинов порта D, расставленными по старшинству пинов? Скажем, единицу или ноль на пине PD2 (третий по счету пин в порте D) мне нужно искать, вычисляя достаточно сложную функцию? Блин, а как? Если переменная однобайтная, берем F, переводим в бинарный - 1111 - состояние всего четырех пинов описано? Или ещё где-то есть старший байт?
    Похоже мне все-таки придется использовать прерывания EXT, на оптопары. Датчики линии что-то не хочется использовать. Прототип проекта должен состоять только из необходимого минимума деталей, и на этом минимуме должен работать. Остальное должен решать софт.
    Я зря вас пугал отсутствием четкой 1 на входе ноги прерывания - у меня же триггер Шмитта стоит! Он без принудительного сброса на 0, но четкую единицу-то он выдает. Таким образом мне просто надо будет проверить состояние ноги на единицу, добавив второй ИФ внутри первого:
    Код (C):
    ISR(PCINT2_vect) {
    ...
      if (PIND & _BV(PORTD2)) {
                  if (_BV(PORTD2)) { //срабатывает, если 1 на PORTD2
    Похоже, пришло время ещё глубже погрузиться в программирование. Потому что эпюры синхросигналов чуть-чуть посложнее, чем я думал - там проскакивает ещё парочка единичных сихросигналов. Придется мне усложнять функцию setup - сначала ловить и вычислять периоды по задающим синхросигналам (синхросигналов два, и они включают в себя этакий признак "конца строки" каждый), а уже зная "эталонные" тайминги (и сравнивая их с фактом на оптопаре) - рулить движком. Причем придется продолжать обработку двух прерываний на движок, поскольку нужно ещё начало задающего тика синхронизировать с определенным угловым положением призмы, которое задается как сдвижка от времени с оптопары. %)
     
  8. Yoda

    Yoda Нерд

    Почитал. Причем плюсом и вторую и третью часть. Не, я не такой гениальный/безумный ученый. Чтобы собрать установку холодного термоядерного синтеза менее чем за месяц..... Они конечно там асы. Или спиртовые наркоманы.. :) Интересно, на каком принципе у них там голограммы реализовывались? :):):)
    (одна из моих безумных идей - сделать что-то похожее, рисуя тремя и более лазерными проекторами в дыму))))) а тут гляди ж ты! на воздухе голограммы! Сильны однако! :)
     
  9. roggedhorse

    roggedhorse Гик

    Тааакс...
    Начнем с последнего:

    Что такое PORTD2 ? Это макрос.
    Где-то в h-файле есть строки:
    Код (C):
    #define PORTD0   0
    #define PORTD1   1
    #define PORTD2   2
     
    и т.д.

    Что такое _BV ? Это макрос.
    Где-то в другом h-Файле написано:
    Код (C):
    #define _BV(bit) (1 << (bit))
     
    _BV() - функция, которая "взводит" нужный вам бит

    Пример:
    Код (C):
    uint8_t x = 0;
    // x = 0
    x = _BV(2);
    // теперь x = (1 << 2) - т.е. равно 4
     
    Отсюда следует, что _BV(2) эквивалентно _BV(PORTD2) и равно 4
    Это маска для проверки второго бита однобайтовой переменной, коей является результат выполнения операции = PIND
    Регистры-то 8-битные, стало быть результат умещается (записывается) в однобайтовую переменную.
     
  10. roggedhorse

    roggedhorse Гик

    именно, если речь идет о строке
    Код (C):
    pinState = PIND
    Отсюда следует, что ваша запись

    Код (C):
    if (_BV(PORTD2)) ....

    лишена всякого смысла
     
  11. Yoda

    Yoda Нерд

    Это-то я знаю. Я думал, что "if (_BV(PORTD2))" будет интерпретирована так: "если значение регистра PORTD2 - истина (то есть единица)". Не вышло...
    Тогда получается, что ваши строчки
    имеют такой смысл:
    1. в переменную pinState загоняем весь регистр PIND, который имеет несколько битов.
    2. Нас интересует бит номер три, то есть (_BV(PD2))
    3. сравнением pinState И (_BV(PD2)) проверяется, что в переменной pinState есть бит (_BV(PD2)). Так?

    А я могу написать так?
    Код (C):
    if (PIND & _BV(PORTD2)) ....
    Или опять нету проверки на единицу?
     
  12. roggedhorse

    roggedhorse Гик

    Написанное означает, что надо логически умножить однобайтовое значение PIND на маску _BV(PORTD2)
    то есть PIND & 4
    Если третий бит порта Д взведен (High, 1), то результатом будет true
    Если третий бит порта Д не взведен (Low, 0), то результатом будет false

    Все верно: так вы проверяете третий справа бит порта Д
    При этом третий бит переменной changes будет равен 1, если значение третьего бита порта Д измениось с нуля на единицу или с единицы на ноль.
     
    Yoda нравится это.
  13. Yoda

    Yoda Нерд

    Вот спасибо, добрый человек! Всё разжевал и в рот положил :)
    Теперь бы реализовать всё это...
    Напишу сюда, как только доделаю до конца синхронизацию или в очередной тупик забреду. Из прогнозируемых на данным момент проблем - написание закона регулирования. Надо будет вносить поправочное воздействие на двигатель с небольшим перерегулированием, чтобы кривая управления была более оптимальной. Будет смешно, если выяснится, что этот конкретно взятый движок мне не подойдет. Я описаюсь от смеха. Надо будет брать другой движок (есть парочка других доступных вариантов), реализовывать для него схему управления, и опять, по-новой... ;)
    Наверно надо на днях движок проверить - поставлю-ка я переменник на аналоговый вход, и протестирую "на коленке" - хватит ли оборотов этого движка? А то может прикольно получиться.... Радует только то, что я сейчас не за конкретные обороты убиваюсь, а про автоматическое управление с обратной связью и с задачей думаю. И чисто технически может подойти достаточно много движков.
    Есть сильные в ТАУ юниты? :)