• Система автоматизации с открытым исходным кодом на базе 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
 
Последнее редактирование:
Сверху Снизу