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

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

  1. Yoda

    Yoda Нерд

    А это где, простите? Если просмотр порта - у меня нету работы с портом... :(
    Могу показаться лентяем, можете общий вид работы с портом здесь привести?
     
  2. Yoda

    Yoda Нерд

    Так и поведение движка было бы системным! Я могу понять ошибку в управлении в 2 раза, но постоянную ошибку, а не колебания туда-сюда...

    Я тут подумал.... (неужели :) ) А если у меня на нарастающем фронте оптопары все же проходит много сработок? Как проверить работу RC фильтра и триггера?

    .... Сам себе отвечаю: прослушка порта со значениями таймингов помогут юному падавану. Сегодня вечером буду курить работу с серийным портом....
     
  3. warman

    warman Гик

  4. roggedhorse

    roggedhorse Гик

    Иногда контроллер уходит в рестарт.
    Причиной такого поведения могут быть ошибки программирования (вызов несуществующего обработчика прерывания или исчерпание лимита свободной памяти и т.д.) и схемотехнические ошибки (например, проседает напряжение на МК ниже BOD-lvel).
    Если у вас под рукой нет осциллографа (а в таких задачах, за которую взялись вы нужен как минимум двухлучевой осциллограф), то что чтобы понять, происходит ли рестарт, лучше всего поджигать светодиод в первой же строке Setup() и не гасить его.
    Если светодиод моргает - МК перезапускается.

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

    Yoda Нерд

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

    Про "негаснущую" лампочку (на пине13?) - понял, попробую.
     
  6. roggedhorse

    roggedhorse Гик

    Кстати, какая у вас Ардуино ?
     
  7. roggedhorse

    roggedhorse Гик

    да
     
  8. Yoda

    Yoda Нерд

    Уно, на 328р контроллере. Кварц стоит на 16 MHz
     
  9. roggedhorse

    roggedhorse Гик

    DigitalOut 2 на плате Ардуино = PD2 : маска для проверки бита _BV(PORTD2) = 0x04
    DigitalOut 3 на плате Ардуино = PD3 : маска для проверки бита _BV(PORTD3) = 0x08

    А у вас 0х11 и 0х12 в обработчике. Или я не прав ?
     
  10. Yoda

    Yoda Нерд

    Попробую не сморозить глупость.
    93 страница всем известного даташита.
    Вот эта табличка:
    Безымянный.jpg
    Считаю: Pin0=09, Pin1=10 (?), Pin2=11 (?), Pin3=12 (?)
    Или сколькеричная система?
    Наверное вопрос нубский.... :eek:


    Не, стоп! Я же проверял! лампочкой на пине 13 моргал по прерыванию. Или нет.... АААА, я запутался!
     
  11. roggedhorse

    roggedhorse Гик

    ничего, бывает.
    система двоичная
    счет справа налево:
    разряды 0, 1, 2, ... 7
    маски 1, 2, 4, ... 128 (0x01, 0x02, 0x04 ... 0x80)
     
  12. roggedhorse

    roggedhorse Гик

    http://arduino.cc/en/Hacking/PinMapping168

    Это хорошо, что вы читаете даташит
     
  13. Yoda

    Yoda Нерд

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

    Одно только не понял, почему 1,2,4? Я согласен 3 перевести в двоичную систему. Или это двоично-десятичная система?

    Большое спасибо всем кто участвовал! Пока я загрузился по горлышко. Тему не закрываю, но пока мне материала хватит на несколько дней (маленький ребенок не много времени на эксперименты оставляет)). По результатам ОБЯЗАТЕЛЬНО отпишусь, возможны другие нубские вопросы. Если всё выйдет - приложу правильный скетч по управлению одним движком. А когда дострою - выложу свой проект (если он меня не победит)

    Как видно на поверку - не совсем правильно его понимаю.... :oops: А картинку я эту видел...
     
  14. roggedhorse

    roggedhorse Гик

    еще пара небольших советов:
    - обычно идентификаторы констант записывают большими буквами - легче читается код
    - переменная "невязки" будет лучше читаться в коде, если вы так и назовете ее "discrepancy". Если речь идет о двигателе №1, то, например, discrepancyDrive1 и т.д.
    - взводите биты правильно: вместо DDRB = 0x02 лучше писать DDRB |= _BV(PORTB1)
    - сбрасывайте биты правильно: пишите PORTB &= ~(_BV(PORTB5)); (погасить светодиод) PORTB |= _BV(PORTB5) - зажечь
     
  15. roggedhorse

    roggedhorse Гик

    0x01 HEX = 1 DEC = 00000001 BIN
    0x02 HEX = 2 DEC = 00000010 BIN
    0x04 HEX = 4 DEC = 00000100 BIN

    Если вы проверяете второй бит (а нумерация битов начинается с нуля), то маска должна быть 00000100 BIN (бит 2 это третий по счету справа, в то время как бит 0 - это первый справа )

    Удачи в вашем проекте!
     
  16. Yoda

    Yoda Нерд

    Семён Семеныч!!!! Я же с этим разбирался!!!! Блин, даст ист нубишь фантастишь!!!:mad: Ну в самом деле - ведь написал же я как-то практически сам всё это (где нету волшебных чисел)... Тормоззз.
    Оправдываю себя только тем, что с МК вообще да и с Си в частности имею дело только с марта этого года.

    За пожелание - спасибо.
    Сам себе определил срок - два месяца. Просто у меня зуд в руках и в голове - УЖЕ ХОЧУ ВСЁ СДЕЛАТЬ. Жаль - времени на реализацию мало - только 2-3 часа в день (спать тоже надо - итак 2-2,5 часа в сутки сплю). Проект будет полностью фри - опенсорсным и некоммерческим. Но после создания работающего прототипа (не хочу все оставлять только словами).
     
  17. roggedhorse

    roggedhorse Гик

    может взять готовый телевизор ? :)
     
  18. Yoda

    Yoda Нерд

    :)
    А вы ВНИМАТЕЛЬНО читаете скетч! ;) (или я вроде где-то пробалтывался текстом)))
    Нет, к сожалению в телевизор смысла нету двигатели ставить :):):)
    Но близко, близко... Пока внес коррективы в свой скетч, не компилируя его и не занося в контроллер....
    Вечером/ночером все эксперименты
     
  19. roggedhorse

    roggedhorse Гик

    Вас вдохновил эпизод из "Духless" ?
     
  20. roggedhorse

    roggedhorse Гик

    Да, кстати, тут

    Код (C):
    void loop() {
       TIMSK1 = 0x00; //Запрещаем прерывания по таймеру
        DV1NEV2 = (DV1S2 - DV1S1) * 16000 / 64 * 6 / 2;
        OCR1AH = HI(DV1NEV2);
        OCR1AL = LO(DV1NEV2);
       TIMSK1 = 0x12;//разрешаем прерывания по таймеру
    }
    есть одна проблема.
    Есть понятие атомарных операций. Грубо говоря атомарная операция выполняется за один так процессора, стало быть она не может быть прервана сигналом прерывания. Это означает, что когда вы используете в обработчике прерывания и в цикле loop() однобайтовую переменную, то ее значение не может быть искажено возникшим из неоткуда прерыванием.
    Когда же используются многобайтовые переменные, то в машинном коде операция DV1NEV2 = (DV1S2 - DV1S1) * 16000 / 64 * 6 / 2 может занимать несколько тактов (а то и десятков или даже сотен) тактов. Вычисление разности DV1S2 - DV1S1 может иметь неопределенный результат, поскольку вычисление разности выполняется не за один такт и в процессе вычисления разности может произойти прерывание PCINT2, которое вы не запрещаете. МК прервет процесс вычисления разности и выполнит обработчик, который с высокой вероятностью изменит значение переменных DV1S2 и DV1S1.

    Чтобы такого не произошло, следует вообще запретить прерывания на время, когда вы занимаетесь вычислением разности:

    Код (C):
    void loop() {
       TIMSK1 = 0x00; //Запрещаем прерывания по таймеру
       uint8_t sr = SREG;    //<<<<<<<<<<<<<<<<<< сохраняем состояние регистра SREG
       cli();           //<<<<<<<<<<<<<<<<<< запрещаем прерывания
       DV1NEV2 = (DV1S2 - DV1S1) * 16000 / 64 * 6 / 2;
       SREG = sr;       //<<<<<<<<<<<<<<<<<< восстанавливаем регистр SREG
       OCR1AH = HI(DV1NEV2);
       OCR1AL = LO(DV1NEV2);
       TIMSK1 = 0x12;//разрешаем прерывания по таймеру
    }