Эксперимент 34. Подключение энкодера

В этом эксперименте мы научимся подключать инкрементальный энкодер и получать с него данные. В комплект конструктора входит модуль энкодера — небольшая печатная плата с энкодером и разъемом для удобного подключения к макетной плате. Модуль также включает встроенные подтягивающие резисторы на выводах A и B и кнопку, которая срабатывает при нажатии на вал.

Подписи выводов модуля:

  • GND — общий контакт
  • + — Питание
  • SW — выход кнопки
  • DT — Сигнал А
  • CLK — Сигнал B

Соберем устройство, которое отображает на экране число, увеличивающееся при вращении энкодера по часовой стрелке и уменьшающееся при вращении против часовой стрелки.

Схема эксперимента

Рисунок 1. Электрическая принципиальная схема эксперимента

Обрати внимание, что резисторы R1 и R2 уже припаяны на плате модуля энкодера и нам не нужно устанавливать на макетной плате. Зачем же нужны резисторы R3, R4 и конденсаторы C1, C2? Дело в том, что контакты энкодера, как и любые механические контакты, подвержены неприятному эффекту — дребезгу контактов. На самом деле при нажатии на кнопку и отпускании кнопки замыкание и размыкание контактов не происходит мгновенно. После замыкания происходят многократные неконтролируемые замыкания и размыкания контактов за счет упругости материалов и деталей контактной системы — некоторое время контакты отскакивают друг от друга при соударениях, размыкая и замыкая электрическую цепь. Это и называется дребезгом контактов. Этому явлению подвержены и контакты энкодера.

С дребезгом нужно бороться программным или электрическим способом. В нашей схеме резистор с конденсатором являются фильтром для коротких импульсов, возникающих при дребезге контактов. Благодаря этому фильтру данный эффект можно в значительной мере устранить.

Рисунок 2. Монтажная схема эксперимента

Программный код эксперимента

Exp34.py
  1. from time import sleep_ms, ticks_ms
  2. from machine import I2C, Pin
  3. from esp8266_i2c_lcd import I2cLcd
  4. _init()
  5.  
  6. DEFAULT_I2C_ADDR = 0x3F # Или 0x27 в зависимости от модели микросхемы на плате
  7.  
  8. encA = Pin(13, Pin.IN)
  9. encB = Pin(12, Pin.IN)
  10.  
  11. old_value_a = 1
  12.  
  13. count = 0
  14.  
  15.  
  16. def print_lcd(data):
  17. lcd.clear()
  18. lcd.putstr(str(data))
  19.  
  20.  
  21. i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000)
  22. lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)
  23. lcd.backlight_on()
  24.  
  25.  
  26. while True:
  27. value_a = encA.value()
  28. value_b = encB.value()
  29.  
  30. if value_a != old_value_a:
  31. if (value_a and value_b) or (not value_a and not value_b):
  32. print('+')
  33. count += 1
  34. print_lcd(count)
  35. elif (not value_a and value_b) or (value_a and not value_b):
  36. print('-')
  37. count -= 1
  38. print_lcd(count)
  39. old_value_a = value_a

Настраиваем выводы для работы с энкодером:

  1. encA = Pin(13, Pin.IN)
  2. encB = Pin(12, Pin.IN)

Объявляем переменную old_value_a для хранения предыдущего состояния сигнала A и переменную count в которой подсчитываем количество сигналов от энкодера.

Чтобы лучше понять алгоритм работы программы еще раз посмотрим на график сигналов энкодера:

В основном цикле программы получаем текущие состояния линий А и B. Если состояние линии А изменилось, то проверяем условие вращения против часовой стрелки:

  1. if (value_a and value_b) or (not value_a and not value_b):

Если уровни сигналов А и B оба стали высокими (состояние 2) или оба стали низкими (состояние 0), то увеличиваем значение count на 1, печатаем в терминал символ + и обновляем информацию на дисплее.

Если условие выше не подтвердилось, то проверяем второй вариант: вращение по часовой стрелке:

  1. elif (not value_a and value_b) or (value_a and not value_b):

Если уровень сигнала А стал низким, а сигнала B высоким (состояние 3) или уровень сигнала А стал высоким, а B низким (состояние 1), то уменьшаем значение count на 1, печатаем символ - в терминал и обновляем информацию на дисплее.

Если ни одно из этих условий не выполнено, то игнорируем сигналы. Перед завершением итерации записываем текущее состояние линии А как старое, для использования в следующей итерации.

  1. old_value_a = value_a

Дополнительное задание

  • Попробуй убрать конденсаторы из схемы и покрутить энкодер. Программа будет работать не так, как хотелось бы. Необходимость конденсаторов станет очевидной.