digispark attiny85 прерывания

Тема в разделе "Микроконтроллеры AVR", создана пользователем ale, 13 янв 2019.

  1. ale

    ale Нерд

    Здравствуйте. Пытаюсь разобраться с attiny85. А именно с прерываниями. Светодиодом поморгать получилось, теперь пробую подключить энкодер EC11 и потрогать собственно прерывание. Схема подключения: 1-я нога к PB2, средняя (земля) к земле attiny, 3-я нога к PB3. Кнопка не используется. Используя инфу из интернета написал такой код:
    Код (C++):
    #define PIN_LED PB1 //встроеный лед
    #define DELAY_MS 100

    long pause = 100; // Пауза против дребезга
    long lastTurn = 0; //последнее время изменения состояния


    static inline void initInterrupt(int _pin, int _mode)
    {
    GIMSK |= (1 << _mode);
    PCMSK |= (1 << _pin);
    }

    ISR(PCINT0_vect)
    {
    //строчками ниже, пытаюсь избавиться от дребезга, но с ними вообще на энкодер нет реакции
    // LED просто горит и все

    //if ((millis() - lastTurn) < pause) return;
    //lastTurn = millis();
    PORTB ^= (1 << PIN_LED); //инвертирую значение выхода
    }

    int main(void)
    {
    DDRB = 0b00000010; //ставлю все пины порта на вход, кроме 1-го LED
    PORTB |= (1 << PIN_LED); //зажигаю LED
    PORTB |= (1 << PB3);//подключаю подтягивающий резистор
    initInterrupt(PCINT3, PCIE); //регистрирую прерывание на PB3 на CHANGE
    sei();// разрешаю прерывания
    while (1)
    {
    //ничего тут не делаем
    }
    return (0);
    }
    По задумке, при повороте энкодера, встроенный светодиод должен загораться/гаснуть в зависимости от положения. Но у меня он моргает, причем в какой-то момент гаснет и начинает уже моргать в инверсии. Пробую избавиться от дребезга (в функции прерывания закомментированные строки) так у меня вообще перестает реагировать на энкодер. Помогите разобраться. Я так понимаю, что millis не работает видимо, а как быть тогда
     
  2. Daniil

    Daniil Гуру

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

    Еще можете сделать тупую задержку. Есть ассемблерная команда nop. Выполняется 1 такт. Эта команда "ничегонеделания". Можно запускать в цикле, для "тупой" задержки.
     
  3. parovoZZ

    parovoZZ Гуру

    Так не делают. Энкодер необходимо опрашивать по таймеру. Например, 50 раз в секунду. Автоматом получится антидребезг.
     
  4. ale

    ale Нерд

    Да вроде в моей процедуре длительных операций и нет. Видел код, правда под ардуину, в котором в ISR digitalWrite используют да еще и кучу if-ов и все вроде как работает.
    Прерывания на таймер и там смотреть состояния пинов, правильно понимаю? И теорию данного утверждения где можно почитать?
     
  5. Daniil

    Daniil Гуру

    а как же защита от дребезга (millis). Сейчас вчитался. По вашему плану когда вы нажали должно сработать прерывание. Засечь время и потом опять попасть в прерывание.

    В таком случае, в прерывание нужно попадать не по смене напряжения (chаnge), а по уровню. Ведь, когда кнопка уже нажата уровень НЕ меняется и в прерывание НЕ попадаете.

    И вам нужно засекать не lastTurn, а первое нажатие.
    все в даташите, конечно, есть. Чем глубже в лес, тем больше остается на совести разработчика)
     
  6. parovoZZ

    parovoZZ Гуру

    Да. Если энкодер будет «проскальзывать», то увеличить частоту опроса. Какая теория нужна? По настройке таймера?
     
  7. Asper Daffy

    Asper Daffy Иксперд

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

    ТС, Вы на правильно пути, работайте. Можете посмотреть как другие делают (я бы, на Вашем месте, с этого и начал). Например, откройте и посмотрите как сделаны энкодерные библиотеки для той же ардуины.
     
  8. parovoZZ

    parovoZZ Гуру

    Да здрасти, ага. Если мы выяснили, что дребезг длится 5 мс, для чего нам прерывания на все это время? Правильно, мы их отключаем и засекаем время. Затем опять включаем прерывания. Вместо этого можно опрашивать пины раз в 6 мс.
     
  9. DetSimen

    DetSimen Guest

    я ненормальный

    Код (C++):
    TEncoder::TEncoderValue TEncoder::internalRead(void)
    {
        TEncoder::TEncoderValue result = { Value:0 };

        result.Bits.button = !digitalRead(fbtnpin);
        result.Bits.a_pin  = !digitalRead(fapin);
        result.Bits.b_pin  = !digitalRead(fbpin);

        return result;
    }

    void TEncoder::Read()
    {
        static int8_t lastValue = 0xFF;

        int8_t value = internalRead().Value;

        if (lastValue == value) return;

        lastValue = value;


        if (value < 0) {
            SendClassMessage(msg_EncoderButton, ID);
            return;
        }

        value &= 0x03;

        if (value == 0x02) SendClassMessage(msg_EncoderLeft, ID);
        if (value == 0x01) SendClassMessage(msg_EncoderRight, ID);

        while (internalRead().Value);

        return;

    }
    работает без дребезга. :)
     
    Последнее редактирование модератором: 14 янв 2019
    Asper Daffy нравится это.
  10. DetSimen

    DetSimen Guest

    Код (C++):
    union TEncoderValue {
            int8_t Value;
       
            struct TBitValue {
                bool    b_pin : 1;
                bool    a_pin : 1;
                uint8_t dummy : 5;
                bool    button : 1;
            } Bits;
        };
     
  11. Asper Daffy

    Asper Daffy Иксперд

    Бывает :)))
     
    DetSimen нравится это.
  12. DetSimen

    DetSimen Guest

    Да.
     
  13. Asper Daffy

    Asper Daffy Иксперд

    И что мешает попасть как раз на дребезговое значение? Ничего - запросто попадетё.

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

    Зачем это энкодеру (также, как и зачем "выключать прерывания", как Вы изволили выразиться) я не понимаю, но так (с двойной частотой) подавление дребезга работать будет, а просто раз в 6мс - хрен там.
     
  14. parovoZZ

    parovoZZ Гуру

    ну твоя правда же =)
    а если рядом дисплей? Или UART какой? А мы из прерываний не вылезаем. Всё то, что нельзя спрогнозировать, необходимо переводить в прогнозируемую сущность.
     
  15. Asper Daffy

    Asper Daffy Иксперд

    Паровоз,

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

    Это несложно и недорого. Триггер Шмитта на пинах МК уже есть. Значит, осталось только правильно посчитать интегрирующую цепочку. Считается она на раз-два-три.

    1. Определяем максимальное значение постоянной времени. Для этого берём количество импульсов на полный оборот (например, для энкодеров вполне уважаемой фирмы Bourns это может быть 12, 18 или 24) и максимальное количество оборотов в секунду – ну, сколько Вы там руками накрутите – 5? 10? Ладно, давайте 10. Таким образом, максимально мы имеем 10*24 = 240, т.е. максимальное время 1/240 = 4мс (чуть занизил для запаса).
    2. Определяем минимальное значение постоянной времени. Оно должно быть больше одиночного импульса дребезга (не всего дребезга целиком, а именно одиночного импульса). Его можно посмотреть на осциллографе для своего энкодера и взять максимальное из того, что удастся поймать, да ещё и удвоить для запаса. Мой опыт показывает, одиночные импульсы никогда не бывают длиннее, чем 100 мкс (нет, ну, можно найти совсем убитый энкодер, но мы же специально искать не будем), итого считаем 200мкс
    3. Теперь берём среднее (4000 + 200)/2 = 2100 мкс. И на это время считаем постоянную времени. Получаем, что цепочка из резистора и конденсатор в 1к / 2,2мкф или 1,1к / 2мкф позволят нам просто забыть о дребезге и не париться.

    Кстати, можно и по-другому. Смотрим тот же даташит Bourns (ссылка выше). Максимальное время дребезга (всего, а не одного импульса) – 2мс. Т.е. чтобы подавить весь дребезг за раз, получаем примерно такую же постоянную времени – 2000мкс. Здесь подходят 1к/2мкф. Т.е. результат почти такой же - можно пользовать любой

    Т.е. как-то так. Программно можно, но головной боли будет сильно больше, чем просто поставить один резистор и один конденсатор.
     
    Сусемьбек, ZAZ-965 и DetSimen нравится это.
  16. SergeiL

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

    :)
     
  17. parovoZZ

    parovoZZ Гуру

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

    Я согласен, но - совершенство - это не тогда, когда нечего добавить, а когда нечего отнять. (с)Антуан де Сент-Экзюпери
     
    Ariadna-on-Line нравится это.
  18. ale

    ale Нерд

    По поводу аппаратного устранения - согласен на 100%, но нужно и программное решение.
    DetSimen, пытаюсь понять ваш код. Сам не сишник, только учусь сильно не пинайте. Видимых проверок и задержек на антидребезг нету, я правильно понимаю что веcь фокус в использовании union? Т.е. используя данный тип структуры мы однозначно защищаемся от дребезга благодаря модели работы с памятью? Если это так, то это гениальный хак имхо и должен срабатывать в 99.9% случаев! К сожалению, в боевых условиях еще не проверял.
    Подумалось вот еще что... совместить код DetSimen-a с использованием прерывания на CHANGE только для выставления флага "выполнять чтение или нет"... для разгрузки процессора, правда памяти больше потребуется и стоит ли оно того...
     
    Asper Daffy нравится это.
  19. DetSimen

    DetSimen Guest

    У меня просто опрос ( Read() ) вызываеца по таймеру раз в 10 миллисекунд, за это время весь дребезг устаканивается.
    Короче, к моему коду много еще что надо. Например это
    https://github.com/DetSimen/Arduino_TimerList
     
  20. DetSimen

    DetSimen Guest

    НЕТ.
    И прерываний у меня, кроме таймерных - нету. На Attiny я этот код не тестировал, там таймеры совершенно другие