• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Делюсь опытом Библиотека для работы с энкодером

enjoynering

Well-known member
Тестированно на Arduino AVR, Arduino ESP8266, Arduino STM32.

Из 16 состояний энкодера вырезаются все ненужные. Какая нам польза от того что мы будем знать где крутилка до/после клика? На основе оставшихся 4-х с помощью булевой алгебры и switch case делается простейший счетчик.
Код:
void RotaryEncoder::readAB()
{
  noInterrupts();                              //disable interrupts

  _currValueAB  = digitalRead(_encoderA) << 1;
  _currValueAB |= digitalRead(_encoderB);

  switch ((_prevValueAB | _currValueAB))
  {
    #if defined(__AVR__)                       //slow MCU
    case 0b0001:                               //CW states for 1 count  per click, use "case 0b0001: case 0b1110:" for CW states for 2 counts per click
    #else                                      //fast MCU
    case 0b0001: case 0b1110:                  //CW states for 1 count  per click, use "case 0b0001: case 0b1110: case 0b1000: case 0b0111:" for CW states for 2 counts per click
    #endif
      _counter++;
      break;

    #if defined(__AVR__)
    case 0b0100:                               //CCW states for 1 count  per click, use case 0b0100: case 0b1011:
    #else
    case 0b0100: case 0b1011:                  //CCW states for 1 count  per click, use "case case 0b0100: case 0b1011: case 0b0010: case 0b1101:" for CCW states for 2 counts per click
    #endif
      _counter--;
      break;
  }

  _prevValueAB = _currValueAB << 2;            //update previouse state

  interrupts();                                //enable interrupts
}

Есть нюанс. ATmega328 или реализация digitalRead() оказалась настолько медленной, что я не успевал читать значения pinA и pinB при срабатывании внешнего прерывания на pin A. Поэтому для AVR пришлось использовать прерывание по Timer1. Каждые 0.01 сек таймер не спеша читает состояние пинов и обновляет счетчик энкодера.

Код:
 Timer1.attachInterrupt(encoderISR, 10000);                                 //call encoderISR() every 10000 microseconds/0.01 seconds

Для быстрых STM32 и ESP8266 все работает на внешнем прерывании по изменению состояния pinA.

Код:
attachInterrupt(digitalPinToInterrupt(PIN_A),  encoderISR,  CHANGE);  //call encoderISR()    when high->low or high->low changes happened
Как только энкодер начинает крутиться, срабатывает внешнее прерывание, считываются значения pinA и pinB и обновляется позиция энкодера.

Обязательно добавить два конденсатора по 100nF/0.1uF как показано на картинке, иначе иногда будут появляться пропуски! Библиотека подсчитывает только физические клики, оставляя все лишнее за бортом. Внутренняя подтяжка включена. У популярного шилда KY-040 10КОм уже есть на плате.




Расшифровка пинов KY-040



Забирать как всегда тут.
 
Последнее редактирование:

enjoynering

Well-known member
Воспользовался ООП и путем наследвания сделал более тяжелый класс "RotaryEncoderAdvanced". В нем можно прописывать количество шагов на клик, минимальное и максимальное значение. Получился законченный велосипед.

Код:
RotaryEncoderAdvanced encoder(PIN_A, PIN_B, BUTTON, 0.1, 0.0, 3.3); //0.1 step per click, minimum value 0, maximum value 3.3
читать и менять значение можно командами:

Код:
lcd.print(encoder.getValue());

encoder.setValue(3.3);

Естественно легкий класс "RotaryEncoder" никуда не делся и работает так же как и раньше.
 
Последнее редактирование:

enjoynering

Well-known member
переделал "RotaryEncoderAdvanced" на template. класс может занимать меньше памяти - все зависит от типа используемых переменных. например ваши значения int, тогда инициализация будет выглядеть так:

Код:
RotaryEncoderAdvanced<int> encoder(PIN_A, PIN_B, BUTTON, 1, 0, 12); //1 step per click, minimum value 0, maximum value 12
добавил возможность на лету менять - step per click, minimum value и maximum value. управляем множеством различных значений с помощью одного энкодера:
Код:
encoder.setValues(backupVoltageValue, V_STEPS_PER_CLICK, V_MIN_VALUE, V_MAX_VALUE)
полный пример тут - AVRRotaryEncoderAdvancedMultiValuesLCD
 
Последнее редактирование:
Сверху Снизу