Инкрементный датчик и прерывания

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

  1. Daemon2017

    Daemon2017 Нерд

    Добрый день!

    Имеется двигатель с инкрементным датчиком HC-020K:
    [​IMG]

    Двигатель управляется с помощью Motor Shield. Плата управления - Arduino Uno.

    Хочу сделать так, чтобы двигатель сделал 5 оборотов в одну сторону, а после - начал вращаться в обратную сторону до бесконечности. Писал скетч на прерываниях:

    Код (Text):

    int E2=6;
    int M2=7;

    volatile int i = LOW;

    void setup()
    {
      pinMode (M2, OUTPUT);
      pinMode (2, INPUT_PULLUP);
      attachInterrupt(0, gogogo, FALLING);
    }

    void loop()
    {
      analogWrite(E2, 125);
     
      if (i>5)
      {
        digitalWrite(M2, LOW);
      }
      else
      {
        digitalWrite(M2, HIGH);
      }
    }

    void gogogo()
    {
      i++;
    }
     
    Подключил 1-й канал осциллографа к ноге 2 (прерывание №0), а второй - к ноге 7 (направление движения двигателя). В итоге, переключение M2 с LOW на HIGH происходит не после 5 импульсов, пришедших на пин прерывания (отслеживаю и осциллографом, и по числу просветов на насадке для вала двигателя), а после двух! Даже если задать вместо 5 что-то большее: 35, 55 - все равно 2 импульса и переключение.

    В чем может быть проблема?
     
  2. Onkel

    Onkel Гуру

    конденсатор попробуйте 0,1 uF параллельно подключить, или программно дребезг убрать.
     
  3. Daemon2017

    Daemon2017 Нерд

    Спасибо за ответ!
    Думаете, что дело в дребезге? Тогда почему именно после 2, а не 5 (как в скетче) импульсов происходит переключение?

    На осциллографе картина довольно устойчивая. С конденсатором попробую сегодня сделать.
     
  4. Onkel

    Onkel Гуру

    хобби энкодеры всегда звенят. ну или почти всегда.
    я не спец в ардуине, но я так понимаю FALLING - вызывает прерывание по спаду? Если да, то вроде все правильно в софте, но повторюсь- возможно, я не в курсе неких тонкостей ардуины.
    кстати
    void gogogo()
    {
    i++;
    }
    докрутит i до максимума переменной Int - она какая в ардуине- и i cтанет отрицательным? Обычно если знаковое, то int от -32 к до +32 к
    примерно. я бы вставил что-то вроде
    if( i>6)
    i=6
     
    Последнее редактирование: 13 сен 2015
  5. Daemon2017

    Daemon2017 Нерд

    Да, FALLING - вызов прерывания при спаде. Так и есть: в Arduino int = от -32,768 до 32,767. Но разве это важно? Я всего лишь 5 импульсов хочу поймать, а программа обрывается только на 2-х.

    Попробовал параллельное включение конденсатора - не помогло.
    Сделал попытку убрать дребезг программно в AVR Studio - тоже без результата:(
     
  6. Onkel

    Onkel Гуру

    я бы подключил вместо энкодера кнопку с кондером 0,1 uF и посмотрел бы с кнопкой.
     
  7. Daemon2017

    Daemon2017 Нерд

    Та же самая хурма...
    Вот что обнаружил, включив вывод i на сериал порт: 1 метка (реальная и на осциллографе) = 3 меткам в МК. Т.е. поэтому я проезжаю 2 метки (реальные), мк считает их как 6 и условие i>=5 выполняется.
    Я так полагаю, это очень жесткий дребезг.
    Кондер не помогает, подтяжка - тоже. Какие есть советы?
     
  8. Onkel

    Onkel Гуру

    метод последовательных приближений рулит.
    Это не дребезг, дело скорее всего в софте. Если спад вызывает четко три прерывания - дело точно в софте. Тут надо четко просмотреть все строки кода, но я тут пас - в ардуинах не силен.
     
  9. Daemon2017

    Daemon2017 Нерд

    Да, ряд проверок и перепроверок с разными источниками сигнала показал, что это не дребезг: по непонятным причинам МК обрабатывает 1 сигнал сразу по двум фронтам - вне зависимости от того, задаем мы RISING или FALLING.

    Как это понимать - я без идей:(
     
  10. Onkel

    Onkel Гуру

    проверьте байт (а может быть, установить его прямо в коде), отвечающий за внешние прерывания.
     
  11. AlexU

    AlexU Гуру

    Дребезг может и присутствует, но в данном случае дело не в нем.
    Посмотрите на условный оператор:
    Код (C++):
    if (i>5)
      {
        digitalWrite(M2, LOW);
      }
      else
      {
        digitalWrite(M2, HIGH);
      }
    При первом вызове функции 'loop()' значение переменной 'i' будет меньше 5, и поэтому в пин 'M2' запишится HIGH. Если Вы хотите, что бы переход с LOW в HIGH произошед через 5 импульсов, измените условие на 'i < 5'.
    Но это не все. В сових экспериментах заметил одну особенность. При рестарте Arduino всегда вызывается обработчик прерывания один раз не зависимо от типа (FALLING, RISING, CHANGE). Почему так происходит пока не разобрался. Следовательно условие должно быть 'i < 6'.
     
  12. Вадыч

    Вадыч Нерд

    Сегодня как раз экспериментировал с прерываниями. RISING точно вызывается когда нужно. При старте нет вызова
     
  13. Onkel

    Onkel Гуру

    попробуйте сбрасывать флаг этого прерывания перед тем, как его включить. В ассемблере это
    регистр EIFR. У меня не ардуино, но всегда когда включаешь прерывания хорошо этот флаг сбрасывать, чтобы не сидел флаг прерывания.
     
    AlexU нравится это.
  14. AlexU

    AlexU Гуру

    Спасибо за совет.
     
  15. Ujin

    Ujin Нерд

    При рестарте Arduino всегда вызывается обработчик прерывания один раз не зависимо от типа (FALLING, RISING, CHANGE)......
    в вашем бы случае я настоятельно рекомендовал бы смотреть в даташит на мк который установлен на ардуину...
    есть рус мануал на мегу128...
    вот вам выдержка от туда к примеру...(биты ISCn регистр EICRA отвечают за характер срабатывания прерывания..низкий ....высокий...изменение уровеня сигнала).
    ...Если разрешено прерывание по уровню, то оно будет генерироваться непрерывно до тех пор, пока на входе присутствует низкий уровень...
    Перед изменением бит ISCn1/ISCn0 необходимо запретить работу прерывания путем очистки бита
    разрешения прерывания в регистре EIMSK. В противном случае прерывание может возникнуть после
    изменения данных бит.