Неадекватное поведение KY-040

Тема в разделе "Arduino & Shields", создана пользователем MaksOne, 21 янв 2018.

  1. MaksOne

    MaksOne Нерд

    Друзья! Прошу Вашей помощи. Никак не получается научить энкодер KY-040 адекватно работать с arduino nano. Суть проблемы такая: при медленном вращении энкодер работает нормально. Как только вращение ускоряется, ардуина начинает "топтаться на месте", не понимая, в какую сторону идёт вращение. Чем быстрее скорость вращения энкодера, тем больше ошибок при считывании направления вращения.
    Пробовал обрабатывать энкодер двумя методами: с использованием библиотеки encoder.h и без неё.
    1. С библиотекой Encoder.h код следующий:
    Код (C++):
    #include <Encoder.h>
    Encoder myEnc(4, 5);               //создаем объект "энкодер" подключенный к ногам 4 и 5
    long oldPosition  = -999;           //устанавливаем значение переменной для хранения текущей позиции

    void setup()                          
    {   }
    void loop()
    {
      long newPosition = myEnc.read();             //считываем изменения на энкодере
      if (newPosition != oldPosition)                   //если новое значение позиции не равно старому, тогда
         {
           if(newPosition > oldPosition)                //если значение новой позиции больше старой
           {frequency=frequency+settingstep;      //то совершаем действие при вращении вправо
            oldPosition = newPosition;                  //приравниваем старую позицию к текущей
           }
           if(newPosition < oldPosition)               //если значение новой позиции меньше старой
           {frequency=frequency-settingstep;      //то совершаем действие при вращении влево
            oldPosition = newPosition;                 //приравниваем старую позицию к текущей
           }
         }
      }
    Результат - каждый шаг энкодера ардуина считает за 2, при быстром вращении топчется на месте, при очень быстром - вообще считает в противоположную сторону :D

    2. Без библиотеки:
    Код (C++):
    unsigned char encoder_A, encoder_B, encoder_A_prev;  //переменные для хранения уровней сигналов, полученных от энкодера.
    void setup()
    {  }
    void loop()
    {
    encoder_A = digitalRead(5);                                    //считываем на 5 ноге дату с ноги CLK энкодера
    encoder_B = digitalRead(4);                                    //считываем на 4 ноге дату с ноги DT энкодера
    if(!encoder_A && encoder_A_prev)   //если уровень сигнала на 5 ноге низкий, а в предыдущем цикле он был высокий, то
    {
        if(encoder_B)                                 //если уровень на 4 ноге высокий
        {
           frequency=frequency+settingstep;   //то считаем, что энкодер повернули вправо
        }
        else
        {
           frequency=frequency-settingstep;   //в противном случае - влево
        }
    }
        encoder_A_prev = encoder_A;     //сохраняем текущее состояние сигнала А
    }
    В таком варианте то же самое, что и с библиотекой, только для одного отсчёта необходимо провернуть валкодер в определенном направлении 2 раза (считывание происходит, наоборот, в 2 раза медленнее реального).

    Оба примера кода взяты со сторонних сайтов, и их авторы клятвенно божатся, что всё работает идеально.
    Я думал, может энкодер подсунули бракованный, поменял - история та же...
    Помогите, у кого есть опыт. Сильно не ругайте, если что не так, ибо я новичок, можно сказать...
     
  2. 9xA59kK

    9xA59kK Гик

    По какой схеме подлючен энкодер?
    Попробуй. Отредактируй под себя. Там энкодер на один шаг выдает значения 4. Если у тебя выдает 2, то дели на 2.

    Код (C++):

    #define ENCODER_DO_NOT_USE_INTERRUPTS          //используем энкодер без прерываний
    #include <Encoder.h>
    #include <avr/io.h>

    Encoder myEnc(4, 5);      // пины к которому подключен энкодер
    long position  = -9999;
    int voltSet = 0;

    long old = 0;



    void setup() {
      Serial.begin(9600);
      Serial.println("Basic NoInterrupts Test:");
    }



    void loop() {
      long newPos = (myEnc.read()/4);    // на один шаг энкодера выдает 4 поэтому, делим на 4
      if (newPos != position) {
        position = newPos;
        Serial.print(position);
        Serial.print("\t");
        Serial.print("|voltSet ");
        Serial.println(voltSet);
          }

      if (newPos > old)
         {
         voltSet = voltSet + 1;
         old = newPos;
         } else if (newPos < old)
                  {
                   voltSet = voltSet - 1;
                   old = newPos;
                   }
    }



     
     
    Последнее редактирование: 21 янв 2018
  3. MaksOne

    MaksOne Нерд

    Спасибо, попробую, отпишусь :)
     
  4. MaksOne

    MaksOne Нерд

    Энкодер подключен без заморочек всяких: земля к земле, 5в к 5в, кнопка SW через подтягивающий резистор (к +5в) замыкается на землю, CLK подключен к D5, DT к D4
     
  5. MaksOne

    MaksOne Нерд

    Отредактировал под себя. Делил на 2, ибо если делить на 4, то один шаг энкодера ардуина пропускает. Код получился следующий:
    Код (C++):
    long newPos = (myEnc.read()/2);    // на один шаг энкодера выдает 4 поэтому, делим на 4
      if (newPos != position)
          {
          position = newPos;
          }
      if (newPos > old)
          {
          frequency=frequency+settingstep;
          old = newPos;
          } else if (newPos < old)
             {
             frequency=frequency-settingstep;
             old = newPos;
             }
    История та же самая. При медленном вращении считывание происходит корректно, при быстром - топтание на месте. :( Уже три варианта испробовано - всё бесполезно.
     
  6. MaksOne

    MaksOne Нерд

    Отвечу сам себе: помогло подключение библиотеки Button.h , в которой реализовано подавление дребезга контактов. Для энкодера KY-040 она тоже подходит.
     
    arkadyf нравится это.