enjoynering
Well-known member
Тестированно на Arduino AVR, Arduino ESP8266, Arduino STM32.
Из 16 состояний энкодера вырезаются все ненужные. Какая нам польза от того что мы будем знать где крутилка до/после клика? На основе оставшихся 4-х с помощью булевой алгебры и switch case делается простейший счетчик.
Есть нюанс. ATmega328 или реализация digitalRead() оказалась настолько медленной, что я не успевал читать значения pinA и pinB при срабатывании внешнего прерывания на pin A. Поэтому для AVR пришлось использовать прерывание по Timer1. Каждые 0.01 сек таймер не спеша читает состояние пинов и обновляет счетчик энкодера.
Для быстрых STM32 и ESP8266 все работает на внешнем прерывании по изменению состояния pinA.
Как только энкодер начинает крутиться, срабатывает внешнее прерывание, считываются значения pinA и pinB и обновляется позиция энкодера.
Обязательно добавить два конденсатора по 100nF/0.1uF как показано на картинке, иначе иногда будут появляться пропуски! Библиотека подсчитывает только физические клики, оставляя все лишнее за бортом. Внутренняя подтяжка включена. У популярного шилда KY-040 10КОм уже есть на плате.
Расшифровка пинов KY-040
Забирать как всегда тут.
Из 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
Обязательно добавить два конденсатора по 100nF/0.1uF как показано на картинке, иначе иногда будут появляться пропуски! Библиотека подсчитывает только физические клики, оставляя все лишнее за бортом. Внутренняя подтяжка включена. У популярного шилда KY-040 10КОм уже есть на плате.
Расшифровка пинов KY-040
Забирать как всегда тут.
Последнее редактирование: