Помогите встроить в код джойстик

Тема в разделе "Моторы, сервоприводы, робототехника", создана пользователем МихаилП, 16 мар 2016.

  1. AlexU

    AlexU Гуру

    И что же там такого, что не даст работать внутри обработчика прерывания?
     
  2. ostrov

    ostrov Гуру

    Не работают же прерывания внутри прерываний. По умолчанию во всяком случае. Потому, в частности, и delay() в них не действует,
     
  3. AlexU

    AlexU Гуру

    Функция 'delay()' не работает (в определённых условиях, в большинстве условий), но 'millis()'-то тут при чём? И при чём тут "прерывания внутри прерываний"?
    Вы хоть немного понимаете как работает функция 'delay()' и почему она может привести к зависанию?
    При вызове функции 'delay()' в первую очередь запоминается время при помощи функции 'micros()' (об этом времени чуть позже). Потом запускается цикл, который считывает очередной отсчёт времени при помощи функции 'micros()'. И, если разница этого отсчёта времени и запомненного времени больше заданного через параметр функции 'delay()', то цикл завершается и происходит выход из функции. Таким образом обеспечивается задержка -- т.е. тупо крутиться цикл пока не пройдёт нужное количество времени.
    Вот код:
    Код (C++):
    void delay(unsigned long ms)
    {
        uint32_t start = micros();

        while (ms > 0) {
            yield();
            while ( ms > 0 && (micros() - start) >= 1000) {
                ms--;
                start += 1000;
            }
        }
    }
    А вот количество пройденного времени (то что возвращает функция 'micros()') вычисляется из количества сработанных обработчиков прерываний для прерывания по переполнению для Timer0, а так же к количеству прерываний прибавляется счётчик Timer0, что позволяет вычислить микросекунды с определённой точностью. При этом функция 'micros()' может распознать одно пропущенное прерывание по переполнению Timer0, и немного поправить свой результат -- это к заявлению о "большинстве условий", при 'delay(1)' контроллер может и не зависнуть (ключевое слово "может").
    А теперь возвращаемся к 'millis()' -- почему она (функция) не будет работать? За время работы обработчика она будет возвращать один и тот же результат (потому что прерывания не работают и соответственно не подсчитывается количество переполнений Timer0). Но из прерывания вышли, начала работать основная программа, начали срабатывать другие прерывания (в частности Timer0), начался подсчёт времени -- соответственно при следующем вызове "нашего" прерывания функция 'millis()' вернёт новое значение, которое мы можем обработать по своему усмотрению. Это один из способов обеспечения задержек при обработке прерываний.

    PS: в теле функции 'delay()' производится вызов функции 'yield()' -- кто-нибудь может сказать зачем, почему и на что это повлияет?
     
  4. ostrov

    ostrov Гуру

    Я имел ввиду, что делать задержку на millis() внутри прерывания то же самое что делать ее на delay()! Вверху привели пример, мол delay() работать не будет, используйте millis(), но он будет меняться только при следующих вызовах прерывания, то есть бороться с дребезгом при его помощи внутри прерывания не получится. Надо или городить огород, передавая данные из вызова в вызов или сделать аппаратное, что во многих случаях проще и правильнее.
     
  5. AlexU

    AlexU Гуру

    Абсолютно не то же самое. Проблема дребезга в том, что функция - обработчик прерывания для одного и того же события вызывается несколько раз. Первый вызов, скажем так, "правильный", а последующие "ложные". Вот эти ложные и надо отсечь. Один из способов -- не обрабатывать следующие "ложные" вызовы в течении некоторого времени.
    Попробую другими словами: в небе над головой пролетают самолёты -- один самолёт каждые 20 минут, Вам нужно записывать на листочке количество пролетевших самолётов. И так Вы поднимаете голову и видите самолёт, опускаете голову фиксируете время 11 часов 10 минут и записываете на листочке "первый самолёт 11:10". Потом опять поднимаете голову и опять видите самолёт, опускаете голову и фиксируете время 11 часов 11 минут. И понимаете, что это тот же самый самолёт, т.к. следующий самолёт должен быть не ранее чем через 20 минут. Этот самолёт фиксировать не надо -- опять поднимаем голову.... И т.д.
    Извините за такое уж "детское" объяснение...
     
    Tomasina нравится это.
  6. ostrov

    ostrov Гуру

    Ваше объяснение про самолеты гораздо запутаннее чем обычное про прерывания. Я понял давно что дребезг пропускается не в одном прерывании а в нескольких, но спор не о том начинался. В итоге вообще все перемешалось и я уже потерял нить.
     
  7. ostrov

    ostrov Гуру

    Кстати, вспомнил как я однажды программно решил проблему антидребезна в прерываниях. Установил период на те же 40мс, которые требуются для успокоения кнопки, опрашивая состояния в каждой итерации сравнивал с соседними. Если кнопка была нажата в двух подряд, считалось что она нажата на самом деле и устанавливался соответствующий флаг. Аналогично с отпусканием кнопки. Работало без сбоев. По мне так проще и прозрачнее. Но опять же зависит от остального контекста программы.
     
  8. МихаилП

    МихаилП Нерд

    Теперь я немогу понять, какой способ то использовать?
    Если провернуть энкодер на один щелчок то при этом шд делает шаг, это нормально. Если повернуть ещё на один щелчок и шд делает 2-3 шага, потом снова один если провернуть энкодер на один щелчок - это и есть дребезг кнопок? Подаётся не верный сигнал?
     
  9. ostrov

    ostrov Гуру

    Осциллографом посмотреть бы в идеале. Дребезг хорошо видно. Но можно сделать программное или аппаратное подавление и сравнить.
     
  10. МихаилП

    МихаилП Нерд

    Осциллографа у меня точно нету А вот другими способами дребезг определяется? И как решить эту проблему?
     
  11. МихаилП

    МихаилП Нерд

    Как вы решили эту проблему?
     
  12. ostrov

    ostrov Гуру

    Написал же как.