4.06.2. Лабораторная работа №4.6.2.md


Энкодер

Тема работы

Мы уже умеем управлять устройствами с помощью кнопок. Но что, если нам нужен более удобный и интуитивный орган управления, например, для выбора пункта в меню или плавной настройки параметра? В этой лабораторной работе мы познакомимся с инкрементальным энкодером и превратим его в «ручку» для переключения цветов на RGB-светодиоде по цветовому кругу. Вращаем по часовой — цвета меняются в одну сторону, вращаем против — в другую.

Цель

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

Оборудование и материалы

  • Отладочная плата Рудирон.
  • Макетная плата.
  • Модуль с инкрементальным энкодером.
  • 1 RGB-светодиод с общим катодом.
  • 3 резистора номиналом 220 Ом.
  • Соединительные провода.
  • USB-кабель для подключения Рудирона.
  • Компьютер с Arduino IDE.

Ход работы

  1. Что такое энкодер и как он работает?

    Инкрементальный энкодер — это датчик, который преобразует вращательное движение в последовательность электрических импульсов. В отличие от потенциометра, у него нет начального и конечного положения — его можно вращать бесконечно. Он не сообщает абсолютный угол, а лишь говорит: «Меня повернули на один шаг».

    Внутри энкодера находится диск с чередующимися проводящими и непроводящими секторами. Два контакта (для каналов A и B) скользят по этому диску. При вращении они поочерёдно замыкаются и размыкаются, генерируя на выходах S1 и S2 прямоугольные цифровые импульсы.

    Главный секрет энкодера — квадратурное кодирование. Контакты A и B расположены со сдвигом. Из-за этого импульсы на двух каналах тоже сдвинуты по фазе на 90 градусов. Именно этот сдвиг позволяет нам определить не только факт вращения, но и его направление.

    Как определить направление? Алгоритм простой - мы настраиваем прерывание на один канал, например, A. Когда на нём происходит изменение (например, нарастание сигнала), мы в этот самый момент смотрим на состояние второго канала (B). Если их состояния отличаются, значит, вращение идёт в одну сторону. Если совпадают — в другую.

  2. Сборка схемы

    • Подключите RGB-светодиод. Красный, зелёный и синий каналы (через резисторы 220 Ом) подключите к ШИМ-пинам 5, 7, 8. Общий катод — к GND.
    • Подключите энкодер:
      • + (или 5V) модуля — к пину 5V Рудирона.
      • GND модуля — к пину GND Рудирона.
      • S1 (канал A) — к пину 35 (BUTTON_BUILTIN_1, поддерживает прерывание).
      • S2 (канал B) — к пину 6 (любой свободный цифровой пин).
      • KEY (кнопку) мы в этой работе использовать не будем.
  3. Написание и загрузка кода

    • Убедитесь, что перемычка IRQ на плате снята, а перемычка PRG | RUN стоит в положении PRG.
    • В Arduino IDE введите следующий код:

      // Пины для RGB-светодиода
      const int redPin = 5;
      const int greenPin = 7;
      const int bluePin = 8;
      
      // Пины энкодера
      #define ENCODER_A 35
      #define ENCODER_B 6
      
      // Переменная для хранения текущего "цвета" (0-5)
      // volatile - потому что изменяется в прерывании
      volatile int colorState = 0;
      volatile bool changed = true; // Флаг, что цвет изменился
      
      void setup() {
        pinMode(redPin, OUTPUT);
        pinMode(greenPin, OUTPUT);
        pinMode(bluePin, OUTPUT);
      
        // Модули энкодеров обычно имеют встроенные подтягивающие резисторы,
        // но для надёжности лучше включить их и в микроконтроллере.
        pinMode(ENCODER_A, INPUT_PULLUP);
        pinMode(ENCODER_B, INPUT_PULLUP);
      
        // Настраиваем прерывание на пине A на RISING (передний фронт)
        attachInterrupt(digitalPinToInterrupt(ENCODER_A), handleEncoder, RISING);
      }
      
      // Обработчик прерывания для энкодера
      void handleEncoder() {
        // Проверяем состояние второго пина, чтобы определить направление
        if (digitalRead(ENCODER_B) == LOW) {
        colorState++; // По часовой стрелке
        } else {
        colorState--; // Против часовой стрелки
        }
      
        // Ограничиваем значение в пределах 0-5
        if (colorState > 5) colorState = 0;
        if (colorState < 0) colorState = 5;
      
        changed = true; // Устанавливаем флаг, что нужно обновить цвет
      }
      
      // Функция для установки одного из 6 цветов
      void setColor(int state) {
        switch (state) {
        case 0: analogWrite(redPin, 255); analogWrite(greenPin, 0);   analogWrite(bluePin, 0);   break; // Красный
        case 1: analogWrite(redPin, 255); analogWrite(greenPin, 128); analogWrite(bluePin, 0);   break; // Оранжевый
        case 2: analogWrite(redPin, 0);   analogWrite(greenPin, 255); analogWrite(bluePin, 0);   break; // Зелёный
        case 3: analogWrite(redPin, 0);   analogWrite(greenPin, 255); analogWrite(bluePin, 255); break; // Голубой
        case 4: analogWrite(redPin, 0);   analogWrite(greenPin, 0);   analogWrite(bluePin, 255); break; // Синий
        case 5: analogWrite(redPin, 255); analogWrite(greenPin, 0);   analogWrite(bluePin, 255); break; // Пурпурный
        }
      }
      
      void loop() {
        // Если флаг установлен (т.е. прерывание сработало)
        if (changed) {
        setColor(colorState); // Обновляем цвет светодиода
        changed = false;      // Сбрасываем флаг
        }
      }
      
    • Нажмите кнопку «Upload», чтобы загрузить код на плату.
  4. Проверка работы

    • Сразу после загрузки RGB-светодиод загорится красным цветом.
    • Начните вращать ручку энкодера по часовой стрелке. Цвет будет переключаться: красный → оранжевый → зелёный → голубой → синий → пурпурный и снова красный.
    • Теперь повращайте ручку против часовой стрелки. Цвета будут меняться в обратном порядке.

Результаты

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

Анализ результатов

  • Определение направления. Вся логика скрыта в ISR handleEncoder(). Ключевая строка — if (digitalRead(ENCODER_B) == LOW). Она сравнивает состояния двух каналов в момент изменения на одном из них, что и позволяет определить направление.
  • Переменная colorState. Эта переменная работает как счётчик, который увеличивается или уменьшается в прерывании. Она хранит текущий выбранный «цвет».
  • Флаг changed. Чтобы не вызывать setColor() в каждой итерации loop(), мы используем флаг. ISR устанавливает его в true, а loop(), увидев это, обновляет цвет и сбрасывает флаг. Это правильный способ взаимодействия между ISR и loop().

Выводы

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

Вопросы для самопроверки

  1. Что такое квадратурное кодирование и зачем энкодеру два сигнальных канала?
  2. Как с помощью состояний двух каналов можно определить направление вращения?
  3. Почему для отслеживания вращения энкодера мы использовали прерывание с режимом RISING?
  4. Зачем в программе используется флаг changed?
  5. Как изменить код, чтобы по нажатию на кнопку энкодера (KEY, пин 32) цвет сбрасывался на красный (colorState = 0)?

Поздравляем с освоением энкодера и прерываний!