среда, 3 октября 2018 г.

Регулятор громкости Arduino, энкодер, pt2257 и OLED-дисплей


        Добавляем к регулятору громкости OLED-дисплей. Дисплей подключен к шине i2c. Для устойчивой работы добавлены два подтягивающих резистора R3 и R3.


Схема выглядит так:

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

На индикатор выводятся:


1) Заголовок – текст «VOLUME» или «МUTE», в зависимости от текущего режима
2) Уровень громкости – цифры от 0 до 26 (при заданном шаге громкости (fadeAmount) – 3
3) Шкала громкости – графическая полоска: чем выше громкость – тем шкала длиннее
Визуально это выглядит так:


Для вывода информации на OLED-дисплей используется библиотека OLED_i2C. Подробное ее описание на русском языке и ссылки для скачивания описаны в этой статье.
Скетч Arduino:

#include <Wire.h>
#include <EEPROM.h>
#include <OLED_I2C.h>
/********************************************************
**   Для управлением громкостью используется энкодер   **
**                    Arduino и pt2257  v5             **                  
** Вращением энкодера регулируется громкость, нажатием **                  
**       кнопки включается-отключается режим "MUTE"    **
**    Выключение "Mute" кнопкой и поворотом энкодера.  **   
**    Запоминает значение громкости при выключении     **
**                        http://mynobook.blogspot.com **                        **                
*********************************************************/
OLED  myOLED(SDA, SCL, 8); 
extern uint8_t SmallFont[];
extern uint8_t BigNumbers[];
int Volume;          // Переменная уровня громкости
int Mute=0;          // Переменная значения "Mute" (Отключение звука) - 0 отключено, 1 включено
int fadeAmount = 3;        // шаг изменения громкости
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 12;       // Подключение вывода A (CLK) энкодера
const int pin_B = 11;       // Подключение вывода B (DT) энкодера
const int pin_SW = 9;       // Подключение вывода кнопки (SW) энкодера
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;

int i2c_write(int Az){ // функция записи данных в pt2257 121 - MUTE ON, 120 -MUTE OFF, 0 - Volume
    Wire.beginTransmission(0x44);  // i2c адрес pt2257
if (Az == 0)   {  Wire.write(Volume/10+224);   // Отправляем десятки громкости в pt2257 значение 224-231(00-70)
              Wire.write(Volume%10+208);   // Отправляем единицы громкости в pt2257 значение 208-217(0-9)
              EEPROM.write(0, Volume);}  // Сохраняем значение громкости во встроенную память EEPROM
else Wire.write(Az);
    Wire.endTransmission(); 
  }
  
int oled_out(int Vol){
    myOLED.setFont(SmallFont);
   if (Mute == 1)  myOLED.print("  M U T E  ",CENTER,0);  else myOLED.print("V O L U M E",CENTER,0); //Вывести на дисплей "VOLUME" или "MUTE"
      myOLED.setFont(BigNumbers);
   if (((79-Vol)/fadeAmount) <= 9) for (int i=70; i<77; i++) for (int j=20; j<44; j++) myOLED.clrPixel(i, j);  // Если значение громкости занимает один знак - стереть мусор
   myOLED.printNumI((79-Vol)/fadeAmount, CENTER, 20); // Вывести на экран текущее значение громкости
 for (int i=0; i<79; i++) for (int j=55; j<60; j++) if (i<(79-Vol)) myOLED.setPixel(i+24,j); else myOLED.clrPixel(i+24,j); //Вывести шкалу
   myOLED.update();  
}

void setup()  {

    Wire.begin();
  pinMode(pin_SW,INPUT);  // устанавливаем pin pin_SW как вход
  digitalWrite(pin_SW,HIGH); // Поддяжка вывода к 1         
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  currentTime = millis();
  loopTime = currentTime;
   Volume=EEPROM.read(0);
   if (Volume == 255) Volume = 40; //Если считано значение 255, то установить громкость 50%
    myOLED.begin();

   oled_out(Volume);
  i2c_write(120); // "Mute" при включении отключен
  i2c_write(0); // Задаем громкость при включении
 } 
 
void loop()  {
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц)
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера 
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода B энкодера    
    if((!encoder_A) && (encoder_A_prev)){    // если состояние изменилось с положительного к нулю
     if (Mute == 1) {Mute=0; i2c_write(120); oled_out(Volume);} // если включен режим "Mute" то выключить его, иначе регулировать громкость
     else if(encoder_B) {
        // выход В в полож. сост., значит вращение по часовой стрелке
        // увеличиваем громкость, не более чем до 79 и записываем в pt2257
        if(Volume + fadeAmount <= 79) {Volume += fadeAmount;
                                      oled_out(Volume);
                                      i2c_write(0);
                                      }               
      }   
      else {
        // выход В в 0 сост., значит вращение против часовой стрелки     
        // уменьшаем яркость, но не ниже 0 и записываем в pt2257
        if(Volume - fadeAmount >= 0) {Volume -= fadeAmount;               
                                     oled_out(Volume);
                                     i2c_write(0); 
                                     }
      }   
     }   
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла 
    if  (digitalRead(pin_SW) == 0) // Если нажата кнопка то выключить или включить звук 
    {
     if (Mute == 0) 
     {
      Mute = 1;
      while (digitalRead(pin_SW) == 0) delay(100);   //  Дождаться отпускания кнопки
      i2c_write(121);
      oled_out(Volume);
     }
     else {
      while (digitalRead(pin_SW) == 0) delay(100);  //  Дождаться отпускания кнопки
      Mute = 0;
      i2c_write(120);
      oled_out(Volume);
     }     
    }   
    loopTime = currentTime;

  }                       
}

Скачать скетч можно здесь

На этом все!

Upd 31.05.2022:Выложил файлы в девятом комментарии к данной статье на нашем телеграмм канале. Не забудьте подписаться на канал!

8 комментариев:

  1. Спасибо большое за проделанную работу, Вячеслав. Благодаря Вам я нашел применее найденной в донорах PT-шке Если кто будет собирать этот регулятор на 2259, просто измените значения mute байтов в коде со 121 и 120 на 119 и 116. 2259 отличается от 2251 только расшеренным mute режимом.

    ОтветитьУдалить
  2. День добрый. Возможно ли приспособить эту схему для нескольких устройств вывода (колонки/наушники) с запоминанием уровня громкости для каждого?

    ОтветитьУдалить
    Ответы
    1. К сожалению нет. В этой микросхемы 1 стереовыход.

      Удалить
  3. Спасибо за быстрый ответ.
    Смысл не в одновременном использовании двух устройств, а в переключении между ними. Т.е. в каждый момент времени работает только одно выходное устройство.
    Может использовать 2 микросхемы и переключаться между ними?

    ОтветитьУдалить
  4. Скетч не загружается. Выдаёт ошибку

    ОтветитьУдалить
  5. Этот комментарий был удален автором.

    ОтветитьУдалить
  6. а можно ли ещё прикрутить пульт ir?

    ОтветитьУдалить