Данная статья является продолжением этой статьи. Так сказать, работой над ошибками. Первое исправление коснулось схем, где я в этот раз исправил название микросхемы на pt2257 и изменил рисунок Arduino Uno на Arduino nano:
Функционально эти платы идентичны и собраны на одном микроконтроллере, поэтому скетчи (прошивки) подходят к обоим. Также подойдут другие платы Arduino и их клоны, собранные на микроконтроллерах ATmega168/328, например, Arduino mini, Arduino pro mini, Arduino pro и т.д.
Далее пойдут изменения, коснувшиеся программной части. Выбирайте тот скетч, который Вам больше нравится по функционалу:
Версия 2:
В данном скетче часть программы, отвечающая за передачу данных от микроконтроллера в микросхему регулировки громкости выведена в отдельную функцию (подпрограмму) и обращаться к ней после каждого поворота ручки энкодера или нажатия на его кнопку. Это позволило чуть-чуть уменьшить размер скетча. Также я заметил, что в режиме "MUTE" звук продолжает регулироваться. В некоторых случаях это очень удобно: допустим у Вас в семье спит маленький ребенок или кто-то из домочадцев, а Вы захотели тихонько послушать музыку. Включаете магнитофон, а звук по умолчанию, громче желаемого, и чтобы не крутить 1-3 оборота энкодера, плавно уменьшая громкость, вы нажимаете на ручку регулировки громкости, звук выключается. Вы уменьшаете громкость (в режиме "MUTE") и нажимаете еще раз на ручку энкодера. Включается музыка, но уже намного тише.
Текст программы версии 2:
Скачать скетч можно тут.
Версия 3:
От версии 2 отличается тем, что в режиме "MUTE" регулировка громкости не осуществляется. Т.е. на какой громкости вы включили режим "MUTE" на такой еe и включите, независимо от того, крутили ли Вы в этом режиме ручку регулировки громкости или нет.
Текст программы версии 3:
Скачать скетч можно тут.
Версия 4:
Режим "MUTE" включается кнопкой энкодера, выход из режима осуществляется либо повторным нажатием кнопки, либо поворотом ручки регулировки громкости в любую сторону. На мой взгляд, самый удобный алгоритм, из всех ранее предложенных.
Текст программы версии 4:
Скачать скетч можно тут.
Версия 5:
Самое интересное, как всегда в конце. Во всех предыдущих версиях программ громкость при включении была фиксированной и составляла 50% от максимальной. Первоначальный уровень громкости задавался в первой строке программы:
int Volume=40;
Но микроконтроллеры ATmega168/328 имеют собственную энергонезависимую память EEPROM. Таким образом, добавив в программу библиотеку EEPROM.h удалось добиться того, что при включении магнитофона громкость такая, какая была при выключении. Алгоритм включения-выключения режима "MUTE" полностью соответствует описанному в программе версии 4. Т.е. режим "MUTE" включается кнопкой энкодера, а выход из режима осуществляется либо повторным нажатием кнопки, либо поворотом ручки регулировки громкости в любую сторону.
Текст программы версии 5:
Скачать скетч можно тут.
На этом все. До новых встреч.
Далее пойдут изменения, коснувшиеся программной части. Выбирайте тот скетч, который Вам больше нравится по функционалу:
Версия 2:
В данном скетче часть программы, отвечающая за передачу данных от микроконтроллера в микросхему регулировки громкости выведена в отдельную функцию (подпрограмму) и обращаться к ней после каждого поворота ручки энкодера или нажатия на его кнопку. Это позволило чуть-чуть уменьшить размер скетча. Также я заметил, что в режиме "MUTE" звук продолжает регулироваться. В некоторых случаях это очень удобно: допустим у Вас в семье спит маленький ребенок или кто-то из домочадцев, а Вы захотели тихонько послушать музыку. Включаете магнитофон, а звук по умолчанию, громче желаемого, и чтобы не крутить 1-3 оборота энкодера, плавно уменьшая громкость, вы нажимаете на ручку регулировки громкости, звук выключается. Вы уменьшаете громкость (в режиме "MUTE") и нажимаете еще раз на ручку энкодера. Включается музыка, но уже намного тише.
Текст программы версии 2:
#include <Wire.h> /******************************************************** ** Для управлением громкостью используется энкодер ** ** Arduino и pt2257 v2 ** ** Вращением энкодера регулируется громкость, нажатием ** ** кнопки включается-отключается режим "MUTE" ** ** Выключение "Mute" только кнопкой. ** ** Регулировка громкости в режиме "Mute" изменяется ** ** http://mynobook.blogspot.com ** *********************************************************/ int Volume=40; // Начальная громкость составляет половину (50%) int Mute=0; // Отключение звука 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) else Wire.write(Az); Wire.endTransmission(); } 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; 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(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем громкость, не более чем до 79 и записываем в pt2257 if(Volume + fadeAmount <= 79) {Volume += fadeAmount; i2c_write(0); } } else { // выход В в 0 сост., значит вращение против часовой стрелки // уменьшаем яркость, но не ниже 0 и записываем в pt2257 if(Volume - fadeAmount >= 0) {Volume -= fadeAmount; 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); } else { while (digitalRead(pin_SW) == 0) delay(100); // Дождаться отпускания кнопки Mute = 0; i2c_write(120); } } loopTime = currentTime; } }
Версия 3:
От версии 2 отличается тем, что в режиме "MUTE" регулировка громкости не осуществляется. Т.е. на какой громкости вы включили режим "MUTE" на такой еe и включите, независимо от того, крутили ли Вы в этом режиме ручку регулировки громкости или нет.
Текст программы версии 3:
#include <Wire.h> /******************************************************** ** Для управлением громкостью используется энкодер ** ** Arduino и pt2257 v3 ** ** Вращением энкодера регулируется громкость, нажатием ** ** кнопки включается-отключается режим "MUTE" ** ** Выключение "Mute" только кнопкой. ** ** Регулировка громкости в режиме "Mute" не изменяется ** ** http://mynobook.blogspot.com ** *********************************************************/ int Volume=40; // Начальная громкость составляет половину (50%) int Mute=0; // Отключение звука 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) else Wire.write(Az); Wire.endTransmission(); } 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; 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)&&(Mute == 0)){ // если состояние изменилось с положительного к нулю if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем громкость, не более чем до 79 и записываем в pt2257 if(Volume + fadeAmount <= 79) {Volume += fadeAmount; i2c_write(0); } } else { // выход В в 0 сост., значит вращение против часовой стрелки // уменьшаем яркость, но не ниже 0 и записываем в pt2257 if(Volume - fadeAmount >= 0) {Volume -= fadeAmount; 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); } else { while (digitalRead(pin_SW) == 0) delay(100); // Дождаться отпускания кнопки Mute = 0; i2c_write(120); } } loopTime = currentTime; } }
Версия 4:
Режим "MUTE" включается кнопкой энкодера, выход из режима осуществляется либо повторным нажатием кнопки, либо поворотом ручки регулировки громкости в любую сторону. На мой взгляд, самый удобный алгоритм, из всех ранее предложенных.
Текст программы версии 4:
#include <Wire.h> /******************************************************** ** Для управлением громкостью используется энкодер ** ** Arduino и pt2257 v4 ** ** Вращением энкодера регулируется громкость, нажатием ** ** кнопки включается-отключается режим "MUTE" ** ** Выключение "Mute" кнопкой или поворотом энкодера. ** ** http://mynobook.blogspot.com ** *********************************************************/ int Volume=40; // Начальная громкость составляет половину (50%) int Mute=0; // Отключение звука 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) else Wire.write(Az); Wire.endTransmission(); } 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; 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);} // если включен режим "Mute" то выключить его, иначе регулировать громкость else if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем громкость, не более чем до 79 и записываем в pt2257 if(Volume + fadeAmount <= 79) {Volume += fadeAmount; i2c_write(0); } } else { // выход В в 0 сост., значит вращение против часовой стрелки // уменьшаем яркость, но не ниже 0 и записываем в pt2257 if(Volume - fadeAmount >= 0) {Volume -= fadeAmount; 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); } else { while (digitalRead(pin_SW) == 0) delay(100); // Дождаться отпускания кнопки Mute = 0; i2c_write(120); } } loopTime = currentTime; } }
Версия 5:
Самое интересное, как всегда в конце. Во всех предыдущих версиях программ громкость при включении была фиксированной и составляла 50% от максимальной. Первоначальный уровень громкости задавался в первой строке программы:
int Volume=40;
Но микроконтроллеры ATmega168/328 имеют собственную энергонезависимую память EEPROM. Таким образом, добавив в программу библиотеку EEPROM.h удалось добиться того, что при включении магнитофона громкость такая, какая была при выключении. Алгоритм включения-выключения режима "MUTE" полностью соответствует описанному в программе версии 4. Т.е. режим "MUTE" включается кнопкой энкодера, а выход из режима осуществляется либо повторным нажатием кнопки, либо поворотом ручки регулировки громкости в любую сторону.
Текст программы версии 5:
#include <Wire.h> #include <EEPROM.h> /******************************************************** ** Для управлением громкостью используется энкодер ** ** Arduino и pt2257 v5 ** ** Вращением энкодера регулируется громкость, нажатием ** ** кнопки включается-отключается режим "MUTE" ** ** Выключение "Mute" кнопкой и поворотом энкодера. ** ** Запоминает значение громкости при выключении ** ** http://mynobook.blogspot.com ** ** *********************************************************/ 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(); } 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% 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);} // если включен режим "Mute" то выключить его, иначе регулировать громкость else if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем громкость, не более чем до 79 и записываем в pt2257 if(Volume + fadeAmount <= 79) {Volume += fadeAmount; i2c_write(0); } } else { // выход В в 0 сост., значит вращение против часовой стрелки // уменьшаем яркость, но не ниже 0 и записываем в pt2257 if(Volume - fadeAmount >= 0) {Volume -= fadeAmount; 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); } else { while (digitalRead(pin_SW) == 0) delay(100); // Дождаться отпускания кнопки Mute = 0; i2c_write(120); } } loopTime = currentTime; Serial.print(EEPROM.read(0)); } }
На этом все. До новых встреч.
Upd 31.05.2022:Выложил файлы в первых комментариях к данной статье на нашем телеграмм канале. Не забудьте подписаться на канал!
Спасибо за труд. Заказал микруху и енкодер. Хочу повторить.
ОтветитьУдалитьБольше бы таких изобретателей.
Огромное спасибо. Все детали заказал. Как прийдет и сделаю. Напишу
ОтветитьУдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьИнтересное решение, уже месяц ищу подобное, будем пробовать. Энкодер определенный или любой пойдет? И еще вопрос, вы можете дописать скетч для управления адресной светодиодной лентой? Остался небольшой кусок ленты, на ее основе можно реализовать круговую индикацию положения энкодера. Т.е. Добавляем громкость светодиоды по кругу вокруг ручки включаются, убавляем выключаются.
ОтветитьУдалитьЭнкодер любой, с функцией нажатия. У меня нет адресной светодиодной ленты, поэтому под нее писать программу пока не буду.
Удалитьhttps://m.youtube.com/watch?v=DydNINFv548. Вот что то типа этого
ОтветитьУдалитьДля этого необязательно использовать адресно-управляемые светодиоды. У меня одной где-то есть программа с семисегментным индикатором, таким на основе платы со статьи "74НС595 и 7-ми сегментный светодиодный дисплей".
УдалитьНайду - выложу. Заменить индикатор на светодиоды - дело 10 мин.
Сделал регулятор от кнопок пульта телевизора, скетч на основе вашего. Ньюансы: при увеличении Volume громкость уменьшается; диапазон получился не от 0 до 79, а до 40 (0 это максимум, а на 40 уже ничего не слышно). Почему так?
ОтветитьУдалитьЯ же не экстрасенс. Не могу догадаться что не так. Покажите скетч - попробуем разобраться.
УдалитьУ меня вопрос: если место энкодера использовать кнопки без фиксации, скетч без корректировки будет работать?
ОтветитьУдалитьНет не будет. Нужно менять в программе, чтоб при нажатии кнопки "+" значение переменной Volume увеличивалось на значение переменной fadeAmount, а при нажатии кнопки "-" - уменьшалось...
УдалитьВсем привет! Автору есть вопрос, решил повторить, всё сделал, как описано, а громкость не регулируется
ОтветитьУдалитьPT2257 рабочая? На i2c запросы отвечает? (Попробуйте ее просканировать https://robotchip.ru/i2c-skaner-na-arduino/ )
УдалитьСпасибо за совет! как проверю, - отпишусь. На связи!
УдалитьЕще чтобы исключить неисправность обвязки или ошибки монтажа просто подключите PT2257 к ардуино 4 проводниками (SDA, SCL, GND и питание) и просканируйте еще раз.
УдалитьПоходу, купил бракованную. Дивайс нот фоунд, йопта... Буду заказывать снова ((
ОтветитьУдалитьПривет подскажи .я могу подключить регулировку собранную на ардуинке к колонкам компьютера. Там используется микросхем SJ2882M. К каким контактам подключить А4 иА5 ???
ОтветитьУдалитьSJ2882M (TDA2822) - это обычный УНЧ. В нем нет функции регулировки громкости по шине I2С
УдалитьА4 и А5 подключаются к pt2257, а вся схема включается между выходом ПК и Вашими колонками