Каталог товаров

Регулятор громкости из Digispark

Регулятор громкости компьютера из Digispark

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

 

Необходимые компоненты

  1. Плата Digispark
  2. USB кабель для подключения Digispark к компьютеру
  3. Поворотный энкодер с кнопкой
  4. Провода
  5. Корпус

В нашем магазине представлены платы Digispark двух видов: с разъемом microUSB и USB type A. Вы можете использовать любую из них, для нашей задачи это не принципиально. Если вам ещё не приходилось работать с Digispark, то по приведённым ссылкам вы также найдёте описание данной платы, её технические характеристики, назначение выводов и инструкцию по настройке ARDUINO IDE для программирования Digispark. Ознакомьтесь с приведённой информацией и выполните описанные настройки, прежде чем двигаться дальше.

Поворотный энкодер можно использовать как отдельный, так и распаянный на плату, например, модуль KY-040. Если вы остановили свой выбор на KY-040, то добавьте к списку необходимых компонентов резистор для подтяжки вывода кнопки к питанию. Номинал резистора оговорим позже, при рассмотрении схемы.

Что касается корпуса, то это уже дело вкуса. Я изготовил его самостоятельно из деревянного бруска.

 

Установка библиотеки TrinketHidCombo

Итак, у вас установлена среда разработки ARDUINO IDE, в неё добавлена поддержка плат Digispark и вы умеете загружать в них скетчи. Двигаемся дальше. Чтобы Digispark мог передавать на компьютер команды для изменения громкости, нам нужно установить библиотеку TrinketHidCombo в среду ARDUINO IDE. С её помощью мы превратим Digispark в USB HID устройство (Human Inrerface Device - устройство для взаимодействия с человеком). К таким устройствам относятся, например, мышь, клавиатура, джойстик. И наше устройство тоже будет своего рода клавиатурой.

Чтобы скачать данную библиотеку, перейдите по ссылке https://github.com/adafruit/Adafruit-Trinket-USB/, нажмите на зелёную кнопку Code и затем Download ZIP:

Скачанный архив содержит несколько библиотек, нам нужна только TrinketHidCombo. Откройте архив, найдите папку с таким именем и скопируйте её в каталог с библиотеками ARDUINO IDE.

Теперь мы готовы приступить к сборке нашего устройства и его программированию. Но сначала я предлагаю рассмотреть следующий скетч. Он поможет понять принцип работы собираемого устройства. А может и подаст вам идею для чего-то нового.

// Знакомство с библиотекой TrinketHidCombo.h
#include "TrinketHidCombo.h"

void myDelay(uint16_t t) {
  // Функция задержки, продолжающая вызывать poll() для поддержания USB подключения
  unsigned long tm = millis();
  while (millis() - tm < t) {
    TrinketHidCombo.poll();
    delay(1);
  }
}

void setup() {
  TrinketHidCombo.begin();
  while (!TrinketHidCombo.isConnected()) {
    // Дожидаемся подключения
    // Функция poll (или любая из функций print...) должна вызываться каждые 10мс
    // Иначе наше usb hid устройство "отвалится"
    TrinketHidCombo.poll();
  }
  myDelay(2000);
  // Теперь можно отправлять сообщения:
  TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_GUI, KEYCODE_R); // Нажали клавиши Win+R (все клавиши в файле TrinketHidCombo.h)
  TrinketHidCombo.pressKey(0x00, 0x00); // Отпустили обе клавиши
  myDelay(1000); // Задержка в 1 секунду, чтобы увидеть результат 
  TrinketHidCombo.print("notepad");   // Напечатали notepad
  myDelay(1000);
  TrinketHidCombo.println(); // Равносильно нажатию клавиши Enter
  myDelay(1000);
  TrinketHidCombo.print("Hello world!");
}

void loop() {
  TrinketHidCombo.poll();
}

Разберёмся, что делает данный код. Работа с библиотекой TrinketHidCombo начинается с вызова функции begin() для инициализации USB HID устройства. Инициализация занимает какое-то время в зависимости от загруженности системы, поэтому далее в скетче идёт цикл while, проверяющий результат вызова функции isConnected(). Как только она вернёт true, цикл будет прерван и выполнение скетча продолжится. Обратите внимание, данный цикл содержит вызов функции poll(), она должна вызываться не реже одного раза в 10мс (как указано в описании к библиотеке, хотя по моему опыту можно и реже), иначе операционная система решит, что наше USB HID устройство неисправно. Поэтому скетч не должен содержать длительных задержек, а если они необходимы, то их следует делать при помощи цикла while с вызовом poll(). Именно так в скетче реализована функция myDelay. Она вызывается после выполнения инициализации HID устройства, чтобы обеспечить задержку в две секунды. Дело в том, что сообщения, отправленные сразу после инициализации, не будут обработаны операционной системой. Не могу сказать, в библиотеке дело или в системе, решений данной проблемы (отличных от моего) я не нашёл. По прошествии двух секунд можно посылать сообщения, в данном случае скетч передаёт компьютеру информацию:

  1. о нажатии клавиш WIN + R;
  2. наборе текста «notepad»;
  3. нажатии клавиши Enter;
  4. наборе текста "Hello world!";

То есть мы запускаем на компьютере Блокнот через команду «Выполнить» и набираем в нём текст.

После отправки каждого сообщения идёт задержка функцией myDelay, чтобы был виден результат. Попробуйте загрузить данный скетч в Digispark, чтобы увидеть его работу (при условии, что у вас Windows).

Таким образом, мы можем эмулировать нажатие любых клавиш и сочетаний, в том числе мультимедийных или системных (Power, Sleep, Wake). Список поддерживаемых клавиш вы найдёте в файле TrinketHidCombo.h, входящем в библиотеку TrinketHidCombo.

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

 

Схема регулятора громкости на Digispark

В зависимости от того, какой у вас энкодер (отдельный или модуль KY-040), способ его подключения к Digispark будет немного отличаться. Это связано с тем, что к выводу P1 платы Digispark подключен светодиод, и он стягивает данный вывод на землю. Поэтому на P1 всегда будет сигнал низкого уровня, и поэтому данный вывод не очень удобен для использования в режиме INPUT.

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

Схема регулятора громкости из Digispark и EC-11

Следует отметить, что выводы P3-P5 платы Digispark нам сейчас недоступны. P3 и P4 заняты библиотекой TrinketHidCombo для работы с шиной USB, а P5 - это вход сигнала RESET. Таким образом, нам остаются выводы P0, P1 и P2.

В модуле KY-040 энкодер распаян так, что вывод кнопки (SW) при нажатии соединяется с землёй. Этого не изменить. А значит, вывод Digispark, к которому мы подключаем кнопку, должен быть подтянут к питанию. И светодиод на выводе P1 этому будет препятствовать. Здесь у нас есть два варианта:

  • Перерезать дорожку, идущую от P1 к светодиоду (или выпаять светодиод, как вам удобнее). В этом случае для подтяжки к питанию нам будет достаточно резистора 10кОм.
  • Использовать сильную подтяжку, то есть резистор номиналом около 1,5кОм.

В любом случае нужен подтягивающий резистор на выводе P1. Схема подключения KY-040 к Digispark приведена ниже.

Схема регулятора громкости из Digispark и KY-040

 

Скетч

Поскольку приведённые схемы отличаются способом подключения кнопки, то и скетчи для них будут разные. Для первой схемы, то есть при использовании отдельного энкодера, нужный скетч уже есть в самой библиотеке. Называется он TrinketVolumeKnobPlus и находится в примерах:

Для модуля KY-040 используйте следующий скетч:

#include "TrinketHidCombo.h"
// Скетч управления громкостью компьютера при помощи Digispark и модуля поворотного энкодера KY-040
// Схема и описание: https://compacttool.ru/practic.php?view=13

#define PIN_ENCODER_A 0       // DT
#define PIN_ENCODER_B 2       // CLK
#define PIN_ENCODER_SWITCH 1  // SW 
#define TRINKET_PINx PINB

static uint8_t enc_prev_pos   = 0;
static uint8_t enc_flags      = 0;
static char    sw_was_pressed = 0;

void setup() {
  // Настройка выводов
  pinMode(PIN_ENCODER_A, INPUT_PULLUP);
  pinMode(PIN_ENCODER_B, INPUT_PULLUP);
  pinMode(PIN_ENCODER_SWITCH, INPUT); // Кнопка должна быть подтянута к питанию внешним резистором 1кОм

  TrinketHidCombo.begin();

  // Считываем начальное состояние энкодера
  if (digitalRead(PIN_ENCODER_A) == LOW) {
    enc_prev_pos |= (1 << 0);
  }
  if (digitalRead(PIN_ENCODER_B) == LOW) {
    enc_prev_pos |= (1 << 1);
  }
}

void loop() {
  int8_t enc_action = 0; // 1 - энкодер вращается вправо; -1 - влево; 0 - энкодер не вращается

  // Для увеличения быстродействия вместо digitalRead будем работать напрямую с портом B (PINB),
  // используя функции bit_is_clear и bit_is_set. Подробности:
  // http://www.arduino.cc/en/Reference/PortManipulation
  uint8_t enc_cur_pos = 0;
  // Опрашиваем энкодер
  if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_A)) {
    enc_cur_pos |= (1 << 0);
  }
  if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_B)) {
    enc_cur_pos |= (1 << 1);
  }

  // Если энкодер вращается
  if (enc_cur_pos != enc_prev_pos) {
    if (enc_prev_pos == 0x00)  {
      // Это передний фронт импульса
      if (enc_cur_pos == 0x01) {
        enc_flags |= (1 << 0);
      }
      else if (enc_cur_pos == 0x02) {
        enc_flags |= (1 << 1);
      }
    }

    if (enc_cur_pos == 0x03) {
      // На обох выводах энкодера LOW - мы в середине шага
      enc_flags |= (1 << 4);
    }
    else if (enc_cur_pos == 0x00) {
      // Это задний фронт импульса
      if (enc_prev_pos == 0x02) {
        enc_flags |= (1 << 2);
      }
      else if (enc_prev_pos == 0x01) {
        enc_flags |= (1 << 3);
      }

      // Проанализируем считанные значения для определения направления вращения
      if (bit_is_set(enc_flags, 0) && (bit_is_set(enc_flags, 2) || bit_is_set(enc_flags, 4))) {
        enc_action = 1;
      }
      else if (bit_is_set(enc_flags, 2) && (bit_is_set(enc_flags, 0) || bit_is_set(enc_flags, 4))) {
        enc_action = 1;
      }
      else if (bit_is_set(enc_flags, 1) && (bit_is_set(enc_flags, 3) || bit_is_set(enc_flags, 4))) {
        enc_action = -1;
      }
      else if (bit_is_set(enc_flags, 3) && (bit_is_set(enc_flags, 1) || bit_is_set(enc_flags, 4))) {
        enc_action = -1;
      }

      enc_flags = 0; // Сбрасываем флаги для следующего шага
    }
  }

  enc_prev_pos = enc_cur_pos;

  if (enc_action > 0) { // При вращении вправо увеличиваем громкость
    TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP);
  }
  else if (enc_action < 0) { // При вращении влево уменьшаем
    TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN);
  }

  // Опрашиваем кнопку (при её нажатии на выводе SW будет LOW)
  if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_SWITCH)) {
    if (sw_was_pressed == 0) { // Отслеживаем изменение SW от HIGH к LOW
      TrinketHidCombo.pressMultimediaKey(MMKEY_MUTE);
      delay(5); // Задержка для борьбы с дребезгом
    }
    sw_was_pressed = 1;
  }
  else
  {
    if (sw_was_pressed != 0) {
      delay(5); // Задержка для борьбы с дребезгом
    }
    sw_was_pressed = 0;
  }

  TrinketHidCombo.poll(); // Функция poll должна вызываться каждые 10мс для поддержания соединения
}

После заливки скетча в Digispark он появится в диспетчере устройств как HID устройство. Проверьте его работу, поворачивая ручку энкодера. Если при вращении по часовой стрелке громкость будет уменьшаться, значит, вам нужно поменять местами номера выводов, к которым он подключен. Для этого поправьте в самом начале скетча два «дефайна», должно получиться:

#define PIN_ENCODER_A 2
#define PIN_ENCODER_B 0

Ещё одна проблема, с которой вы можете столкнуться, это самопроизвольное срабатывание кнопки. Такое поведение говорит о том, что подтяжка вывода P1 недостаточна и номинал резистора нужно уменьшить.

 


Теперь остаётся поместить энкодер и Digispark в подходящий корпус и регулятор громкости готов! Как уже отмечалось, корпус можно выбрать из огромного числа, представленных на рынке. Просто просверлите в нём отверстия для провода и энкодера. Я же решил сделать корпус из дерева. Процесс изготовления и результат вы можете посмотреть в следующем видео. Думаю, получилось неплохо.

Контакты

г. Москва, Пятницкое ш. д. 18, пав. 566

zakaz@compacttool.ru

8-495-752-55-22

Информация представленная на данном информационном ресурсе преследует исключительно рекламные цели и не является договором-офертой !

© Все права защищены 2015 - 2022г https://compacttool.ru