[частично решено] Проблема с экспериментом 20. Обработка прерываний - виснет ардуино.

Тема в разделе "Arduino & Shields", создана пользователем altex, 2 авг 2014.

  1. altex

    altex Гик

    Опять возникла проблема с последним экспериментом из методички из Матрёшки Z.
    Ссылка на описание -
    http://wiki.amperka.ru/конспект-arduino:перетягивание-каната

    Я специально купил резисторы на 100 кОм, чтобы не возникало вопросов несоответствия схемы с методичкой.

    В этом проекте идёт работа с аппаратными прерываниями. Прерывания срабатывают по нажатию на кнопку. Кнопок две.

    Если нажимать на кнопки по очереди, то всё работает идеально.
    Однако, если нажать и отпустить кнопки одновременно, то ардуина виснет прямо на ровном месте.

    В дебаг окне всё замирает. (Проблема номер один - виснет при нажатии на две кнопки)
    Код (Text):
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    Score=1
    // Вот тут всё повисло, дальше вывод не идёт.
     
    Дальше можно ждать, ничего не меняется.
    Однако если нажать опять на обе кнопки (а иногда одной хватает), то программа продолжает выполняться.
    Но значение score уже совсем другое. (Проблема номер два - слетает значение переменной)
    Код (Text):
    Score=1
    Score=1
    Score=1
    Score=1
    End
    Score=-2809
    Score=-10651
    Score=-20661
    Score=-30995
    Score=27292
    Score=27291
    Score=27290
    Score=27290
    Score=27290
    Score=27290
    Score=27290
    Score=27290
    Score=27290
    Score=27290
    // Здесь продолжается вывод программы, на кнопки реакция возникает, переменная меняется.
     
    Причём на кнопки реакция возникает, переменная меняется, программа продолжает работать.

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

    Скетч
    Код (Text):
    #define BUZZER_PIN    0
    #define FIRST_BAR_PIN  4
    #define BAR_COUNT      10
    #define MAX_SCORE      20
    // глобальные переменные, используемые в прерываниях (см. далее)
    // должны быть отмечены как нестабильные (англ. volatile)
    volatile int score = 0;

    void setup()
    {
      for (int i = 0; i < BAR_COUNT; ++i)
        pinMode(i + FIRST_BAR_PIN, OUTPUT);
      //pinMode(BUZZER_PIN, OUTPUT);
      // Прерывание (англ. interrupt) приостанавливает основную
      // программу, выполняет заданную функцию, а затем возобновляет
      // основную программу. Нам нужно прерывание на нажатие кнопки,
      // т.е. при смене сигнала с высокого на низкий, т.е. на
      // нисходящем (англ. falling) фронте
      attachInterrupt(INT1, pushP1, FALLING); // INT1 — это 3-й пин
      attachInterrupt(INT0, pushP2, FALLING); // INT0 — это 2-й пин

      Serial.begin(9600);
    }

    void pushP1() { ++score; } // функция-прерывание 1-го игрока
    void pushP2() { --score; } // функция-прерывание 2-го игрока
    void loop()
    {
      Serial.println("Start");
      //tone(BUZZER_PIN, 2000, 1000); // даём сигнал к старту.
      // пока никто из игроков не выиграл, обновляем «канат»
      while (abs(score) < MAX_SCORE) {
        Serial.print("Score=");
        Serial.println(score);
        delay(100);
        int bound = map(score, -MAX_SCORE, MAX_SCORE, 0, BAR_COUNT);
        int left = min(bound, BAR_COUNT / 2 - 1);
        int right = max(bound, BAR_COUNT / 2);
        for (int i = 0; i < BAR_COUNT; ++i)
          digitalWrite(i + FIRST_BAR_PIN, i >= left && i <= right);
      }
      //tone(BUZZER_PIN, 4000, 1000); // даём сигнал победы
      Serial.println("End");
      while (true) {
        Serial.print("Score=");
        Serial.println(score);
        delay(100);
      } // «подвешиваем» плату до перезагрузки
    }
    Прошу гуру объяснить с максимальным числом деталей, что происходит и почему?
    Заранее спасибо.
    Наконец-то интересная проблема возникла :)
     
  2. geher

    geher Гуру

    Интересный эффект.
    Судя по диагностике и коду можно сделать предположение, что "залипают" сигналы прерываний кнопок. В результате постоянная обработка прерываний не дает выполняться основному коду. После повторного нажатия двух кнопок сигнал прерывания первой кнопки снимается. В результате основной код может потихоньку выполняться.
    В то же время прерывание второй кнопки продолжает уменьшать значение score до вываливания из цикла и входа в финальный цикл "зависания" и продолжает это делать некоторое время после (завершаются сделанные ранее многочисленные вызовы прерывания?).
    Почему же так происходит, непонятно. Либо очередного слона не вижу, либо компилятор чудит, либо что-то не так с обработкой прерываний в самой ардуино.
    Так что вопрос, действительно, интересный.
     
    altex нравится это.
  3. Unixon

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

    Раздел "Reset and Interrupt Handling" категорически несогласен с такой интерпретацией.
     
  4. geher

    geher Гуру

    Вот именно. Так не должно быть по определению, но выглядит именно так, если, конечно, я просто какого-то слона не приметил.
     
  5. ALev

    ALev Гик

    И опять судя по всему вы наткнулись на нашу ошибку :)

    1. Уберите резистор в 100 кОм, одним концом соединённый с конденсатором.
    2. Замените второй резистор в 100 кОм на 10 кОм.
    3. Заменить конденсатор в 100 нФ на 10 мкФ.

    Теперь схема должна заработать. К обеду я сам смогу проверить на практике мои предположения и ответить развернуто.

    P.S. Не обязательно писать на Хабре, чтобы на ваш пост обратили внимание :) Иногда я могу день не заходить на форум, т.к. есть сверхсрочные дела по нашим новинкам. Но на другой день я обязательно зайду и всем отвечу :)
     
    altex нравится это.
  6. altex

    altex Гик

    Спасибо за ответ.
    Сделал как вы написали

    1) Новая проблема - одно нажатие на кнопку иногда дублируется

    Вот пример дебага:
    Код (Text):
    Score=0
    Score=0
    Score=0
    Score=0
    Score=-1
    Score=-1
    Score=-2
    Score=-2
    Score=-2
    Score=-2
     
    Здесь я один раз нажал на кнопку, а переменная изменилась на два. Такое бывает часто, но не всегда.

    2) теперь не виснет
    не удалось мне нажать на кнопки так, чтобы повисло

    3) иногда срабатывает кнопка и при нажатии и при отпускании

    Причём, вот так работает правая кнопка

    Код (Text):
    Score=-4
    Score=-4
    Score=-4
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-6
    Score=-6
    Score=-6
     
    Здесь я один раз нажал на кнопку, подождал секунду, и отпустил кнопку
    При нажатии и при отпускании переменная изменилась в одну сторону
    Так происходит не всегда, иногда кнопка работает правильно.

    А вот так работает левая кнопка

    Код (Text):
    Score=-4
    Score=-4
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-5
    Score=-4
    Score=-4
     
    Здесь при нажатии переменная изменилась в обратную сторону, потом пауза 1 сеунда, дальше я кнопку отпустил, и переменная изменилась ещё раз уже в правильном направлеии
    Так происходит не всегда, иногда кнопка работает правильно.
    Иногда кнопка работает так же как правая, увеличивая два раза переменную

    4) переменная слетает при одновременном отпускании двух кнопок

    Код (Text):
    Score=1
    Score=1
    Score=1
    Score=1
    Score=2
    Score=2
    Score=-1881
    Score=-1881
    Score=-1881
    Score=-1881
    Score=-1881
    Score=-1881
     
    При этом переменная изменяется на значение от -1000 до -2000.

    Код скетча

    Код (Text):
    #define BUZZER_PIN    0
    #define FIRST_BAR_PIN  4
    #define BAR_COUNT      10
    #define MAX_SCORE      20
    volatile int score = 0;

    void setup()
    {
      attachInterrupt(INT1, pushP1, FALLING); // INT1 — это 3-й пин
      attachInterrupt(INT0, pushP2, FALLING); // INT0 — это 2-й пин

      Serial.begin(9600);
    }

    void pushP1() { ++score; } // функция-прерывание 1-го игрока
    void pushP2() { --score; } // функция-прерывание 2-го игрока
    void loop()
    {
        Serial.print("Score=");
        Serial.println(score);
        delay(100);
    }
     
    Спасибо за замечание, больше не буду пользоваться хабром как аппаратным прерыванием для обработки вопросов форума.
     
    Последнее редактирование: 5 авг 2014
  7. ALev

    ALev Гик

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

    altex Гик

    Сделал код ещё проще

    Код (Text):
    volatile int score1 = 0;
    volatile int score2 = 0;

    void setup()
    {
      attachInterrupt(INT1, pushP1, FALLING);
      attachInterrupt(INT0, pushP2, FALLING);
     
      Serial.begin(9600);
    }

    void pushP1() {
      score1++;
    }

    void pushP2() {
      score2++;
    }

    void loop()
    {
        Serial.print("Score1=");
        Serial.print(score1);
        Serial.print(" Score2=");
        Serial.println(score2);
        delay(100);
    }
     
    Интересные результаты отладки

    1) Иногда нажатие на одну кнопку интерпретируется как нажатие на две кнопки сразу

    Код (Text):
    Score1=2 Score2=21
    Score1=2 Score2=21
    Score1=2 Score2=21
    Score1=2 Score2=21
    // вот тут я нажал на правую кнопку
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    Score1=3 Score2=22
    // вот тут я отпустил правую кнопку
    Score1=3 Score2=23
    Score1=3 Score2=23
     
    Код (Text):
    Score1=8 Score2=23
    Score1=8 Score2=23
    Score1=8 Score2=23
    // вот тут я нажал на левую кнопку
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    Score1=8 Score2=24
    // вот тут я отпустил левую кнопку
    Score1=9 Score2=24
    Score1=9 Score2=24
    Score1=9 Score2=24
    Score1=9 Score2=24
     
    2) если нажать на две сразу, то получается вот как

    Код (Text):
    Score1=50 Score2=40
    Score1=50 Score2=40
    Score1=50 Score2=40
    // вот тут отпустил обе кнопки
    Score1=51 Score2=1757
    Score1=51 Score2=1757
    Score1=51 Score2=1757
    Score1=51 Score2=1757
     
    или вот так

    Код (Text):
    Score1=53 Score2=1759
    Score1=53 Score2=1759
    Score1=53 Score2=1760
    Score1=53 Score2=1760
    // вот тут отпустил обе кнопки
    Score1=158 Score2=3481
    Score1=158 Score2=3481
    Score1=158 Score2=3481
    Score1=158 Score2=3481
    Score1=158 Score2=3481
     
    Код (Text):

    Score1=12 Score2=12
    Score1=12 Score2=12
    Score1=12 Score2=12
    Score1=12 Score2=12
    Score1=12 Score2=12
    Score1=12 Score2=12
    // вот тут отпустил обе кнопки
    Score1=800 Score2=2355
    Score1=1633 Score2=2355
    Score1=1633 Score2=2355
    Score1=1633 Score2=2355
    Score1=1633 Score2=2355
     
     
  9. altex

    altex Гик

    http://amperka.ru/collection/components/product/74act14-schmitt-trigger

    Пороги срабатывания триггера - 0.9 и 1.6 В
    У нас же с кнопки идёт 4.75 В
    Для увеличения петли гистерезиса я использовал делитель напряжения из резисторов 10кОм (и 100кОм тоже).
    Включил после кнопки, выход делителя к триггеру.
    Добился, чтобы напряжения было 1.89 В и 2.02 В, вместо 4.75 В,
    но триггер при таком значении напряжения не срабатывает!
    Какого фига?

    Срабатывает только при 3.89В и то не всегда.

    Кстати, когда я вольтметром просто касаюсь земли, чтобы замерить эти значения, прерывания срабатывают (иногда даже ардуина виснет и значение счётчика прерываний увеличивается на десятки тысяч). Какой бред :(
     
    Последнее редактирование: 6 авг 2014
  10. Unixon

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

    Попробуйте вместо кнопок подключить вторую ардуину и с помощью нее генерировать тестовые события.
     
  11. ALev

    ALev Гик

    Это не бред. Это наводки от сети 220 В. Если вы просто возьмётесь пальцем за щуп осциллографа, то увидите вот такую картину: IMG_7324.jpg

    Одна клетка - 5 В. И это я ещё не стрался, можно получить до 15 В и больше, надо только антенный эффект улучшить. Вобщем, все провода в помещениях наводят сигнал с частотой 50 Гц. И это далеко не единственная причина «тайных срабатываний».
     
  12. ALev

    ALev Гик

    У нас сейчас затык с одной новинкой. Сроки горят. Сейчас мы разберёмся с ней и я добью вопрос с кнопками.
     
  13. altex

    altex Гик

    Купил dso nano v3, чтобы проверить что происходит на контактах.
    Так вот с кнопки я вижу изменение сигнала, и вижу как конденсатор заряжается потом. Щупы ставил на две точки - вход и выход кнопки.
    А вот таким же образом посмотреть что на выходе триггера - не получается почему-то. Щупы ставлю на две точки - выход триггера и землю.
    И ещё я не нашел нормальной инструкции к нему :) Так что я им не умею пользоваться. Если поможете настроить так, чтобы можно было посмотреть выход триггера, то буду премного признателен.
     
  14. altex

    altex Гик

    Попробовал сделать схему всего с одной кнопкой (с rc цепочкой и триггером Шмитта).

    Код (Text):

    volatile int score1 = 0;

    void setup()
    {
      attachInterrupt(INT1, pushP1, RISING);
      Serial.begin(9600);
    }

    void pushP1() {
      score1++;
    }

    void loop()
    {
      Serial.print("Score1=");
      Serial.println(score1);
      delay(100);
    }
     
    Всё равно иногда прибавляется по 100 (примерно) за одно нажатие на кнопку.
    А не могли бы вы посмотреть на более быстром осциллографе (если у вас воспроизводится проблема, которую я описываю), что реально в эти моменты выходит с выхода триггера? Реально проскакивает много импульсов (как при дребезге), или это программный глюк?

    У меня на nano v3 не получается отловить момент, когда сразу по несколько значений прибавляется.
     
  15. ALev

    ALev Гик

    Да, там много импульсов проскакивает. DSO Nano это не отловит, он импульсы короче 10-20 микросекунд просто не видит.
     
  16. altex

    altex Гик

    Может быть тогда можно отфильтровать с помощью конденсатора такие высокочастотные импульсы?

    Я не сильно в этом разбираюсь, поэтому просто как идея. Например сделать что-то типа фильтра, и определённые высокие частоты отфильтровывать. Это же получается выше 100Кгц пульсации. Хотя мне лично такой вариант не очень нравится.

    Я вот не понимаю, в интернете очень много видео и описаний (находится по arduino hardware debouncing в гугле), неужели ни у кого больше таких проблем не возникало :-/
    Ничего похожего не нашел даже.
     
  17. altex

    altex Гик

    Наиболее стабильной работы (но не идеальной) я добился, подключив кнопку ко входу триггера через RC цепочку из резистора 100кОм и конденсатора 10нФ. При этом подтягивающий резистор на 10кОм был подключен ко входу RC-цепочки и кнопке. А выход RC-цепочки соответственно ко входу триггера.

    Вот я не могу понять причину таких импульсов.
    Допустим вы говорите, что импульсы проскакивают с выхода триггера физически. (Хотелось бы конечно посмотреть картинку осциллографа, просто интересно какой формы импульсы.)
    Это означает, что сам контроллер работает корректно и правильно всё считает.
    Так же получается, что если триггер срабатывает, значит такие же импульсы должны быть на входе триггера, тоесть с выхода кнопки (или rc цепочки, зависит от того, какая схема используется)
    Вот тут тоже хотелось бы посмотреть более точным чем nano осциллографом, есть ли тут такие импульсы, и какой они формы. Ведь получается, что эти импульсы должны быть амплитудой больше гистерезиса триггера. И тут тоже хотелось бы посмотреть на скрин с осциллографа, очень интересно просто.

    Что получается, во-первых не работает RC цепочка? Ведь как рассчитанная на 1мс RC-цепочка пропускает импульсы менее 10мКс? Вот это самый интересный вопрос.

    И тут значит есть несколько вариантов.
    1) Можно было бы увеличить гистерезис,
    а) взять другой триггер,
    б) или как я пробовал - через дополнительный делитель напряжения,
    или ещё какой-нибудь вариант придумать.

    И опять, если это наводки, то с какой частотой, если импульсы меньше 10мкс. Значит от 100Кгц. И что это может быть, wifi точка доступа, сеть сотовой станции, генератор тактовых импульсов самой arduino?
     
  18. ALev

    ALev Гик

    Сегодня вечером займусь этим вопросом. Осциллограммы сниму, если не решу вопрос быстрее.
     
  19. Unixon

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

    Для начала неплохо бы определиться, аппаратная это проблема или программная.

    Предлагаю (повторно) взять вторую ардуину и с помощью нее перебрать возможные комбинации сигналов сначала на INT0/INT1, а потом на месте кнопок и посмотреть как программа будет эти комбинации отрабатывать.

    С помощью линии задержки особо рассмотреть случаи одновременного (с задержкой 0~2 такта) прихода сигналов на INT0/INT1 на случай аппаратного глюка самого AVR.
     
  20. ALev

    ALev Гик

    А смысл? Если сборка простого счётчика нажатий даже одной кнопки уже открывает проблему в подключении , применённом в нашем эксперименте. И плата тут не причём. Проблема подтверждена давно, просто у нас небольшой завал случился.