PCCar.ru - Ваш автомобильный компьютер

PCCar.ru - Ваш автомобильный компьютер (http://pccar.ru/index.php)
-   Звук (http://pccar.ru/forumdisplay.php?f=174)
-   -   регулировка звука аудиопроцессором TDA7442 + ардуино (http://pccar.ru/showthread.php?t=24440)

oleg707 27.09.2016 13:58

регулировка звука аудиопроцессором TDA7442 + ардуино
 
Вложений: 6

Поскольку уже со всем разобрался и сделал рабочую модель скетч для TDA7442D можно посмотреть здесь


Итак, задача
Нужно регулировать громкость в машине.
Линейный выход с звуковой карты идёт на звуковой процессор tda7442и после него – на усилитель мощности.



ПЕЧАТКА + скетч
Вложение 45875


картинки вложения опытов пусть пока останутся.

oleg707 27.09.2016 23:11

Вложений: 1
Сделал тестовую печатку.
Вложение 44888

Запаял железо согласно даташиту и подключил ардуину мегу 2560
Вложение 44890
Вложение 44891
Вложение 44892

ТЕПЕРЬ СОФТ

Для начала открываем даташит и читаем
4 SOFTWARE SPECIFICATION

И там ищем chipadress, то есть I2C адрес чипа (звукового процессора)
Для TDA 7719
1000100
Открываем виндовый калькулятор вид – программист.
Выбираем BIN – 8 байт (то есть цифровой вид ОДИН-НОЛЬ, 8 символов)
Забиваем 1000100 и тыкаем в HEX.
Видимцифры44.
Значит I2C адреc TDA 7719 0x44

Для tda7442 адрес 0x80 (8 страница мануала)
5 DATA BYTES
Address = 80(HEX)

В скетч заливаю:
PHP код:

#include <Wire.h>
 
void setup() {
  
Wire.begin();
}
 
void loop() {
Wire.beginTransmission(0x80);  // i2c adress 7442
Wire.write(0b11110000);        // задаем десятки
//Wire.write(0b11111111);        // задаем еденицы
Wire.endTransmission();
//delay(500);


И вижу осциллографом:

Вложение 44893
Синяя – SCL
Красная – SDA (наши данные). Если Посылать данные на другой адрес (например 0х44), то форма красной линии меняется.

Если я загружаю другой скетч, то осциллограмма не меняется:
PHP код:

//Для запуска TDA7719 достаточно загрузить скетчь который ниже в ардуино
//http://alekssandr.myjino.ru/na-stadii-razrabotki/audioprotsessor-na-tda7719
#include "Wire.h" 
 
void setup() 

Wire.begin(); 
delay(1000); 
Serial.begin(9600); 
 

void loop(){ 
 
//delay(2000); 
 
tda7719(00b11100000);  //Конфигурация входа/выбора источника     :Input Configuration / Main Source Selector 
tda7719(10b00011111);  //2-й выбор источника / Прямой Путь       :2nd Source Selector / Direct Path 
tda7719(20b00011111);  //Смешивание Источников / Смешивание Gain :Mixing Source / Mixing Gain 
tda7719(30b00011111);  //Контроль смешивания и т.д               :Mix Control / Level Meter / DC Offset Detector Config 
tda7719(40b00000000);  //Soft Mute / Others 
tda7719(50b00000000);  //Soft Step I 
tda7719(60b00000000);  //Soft Step II / DC-detector 
tda7719(70b10000000);  //Громкость                              :Loudness 
tda7719(80b00010000);  //Объем / Output Gain                    :Volume / Output Gain 
tda7719(90b01110000);  //Treble filter  
tda7719(100b01110000); //Middle filter 
tda7719(110b01110000); //Bass filter 
tda7719(120b01111000); //Настройки Сабвуфер/Средний/Басс        :Subwoofer / Middle / Bass 
tda7719(130b00010000); //Настройки динамика передний левый      :Speaker Attenuator Left Front 
tda7719(140b00010000); //Настройки динамика передний правый     :Speaker Attenuator Right Front 
tda7719(150b00010000); //Настройки динамика задний Левый        :Speaker Attenuator Left Rear 
tda7719(160b00010000); //Настройки динамика задний правый       :Speaker Attenuator Right Front 
tda7719(170b00010000); //Настройки сабвуфера Левый              :Subwoofer Attenuator Left 
tda7719(180b00010000); //Настройки сабвуфера Правый             :Subwoofer Attenuator Right 
 

 
void tda7719(int subaddressint data)  //Вызов tda7719 

Wire.beginTransmission(0x80); //СТАРТ и Адрес микросхема TDA7442
Wire.write(subaddress);       //Подадрес команды 
//Wire.write(0b01110000);       //Подадрес команды 
Wire.write(data);             //Команда 
Serial.println(subaddress);   //Пишем подадрем в монитор 
Serial.println(data);         //Пишем команду в монитор 
//Serial.println(tda7719,(6)); 
Wire.endTransmission();       //СТОП 
//delay(500); 


Теперь вопрос.
Как послать данные, какие послать данные, и как увидеть реакцию звукового проца(должен ли он что либо отвечать.:be:



итак, запустил этим кодом.
не получалось потому, что адрес в мануале указан 80 (hex), а в bin адрес 1000000.
А адрес 1000000 в BIN это 40 HEX! Прямо в мануале обманули?:shok:
Итак, I2C адрес tda7442 HEX(0x40) или 0b1000000
Сканер I2C в ардуино тоже показал 0x40.
Работоспособность видно на осциллограмме.
Вложение 44902

По массам:
Массу DIGgnd можно не подключать (только к ардуине)
Масса Agnd подключается на минус источника питания (9В)
Подключение к ардуине:

ардуино мега 2560 tda7442
+5В ______________ на резисторы подтяжки шины
- ______________ - на DIGgnd
20pin ______________ - SDA
21pin______________ -SCL


PHP код:

//Для запуска tda7442 достаточно загрузить скетчь который ниже в ардуино
#include "Wire.h" 
 
void setup() 

Wire.begin(); 
delay(1000); 
Serial.begin(9600); 
 

void loop(){ 
 
//delay(2000); 
 /*
tda7442(0, 0b01100000);  //INPUT ATTENUATION  -16dB (0b - показывает, что данные будут в двоичной форме. )
потом идут разряды
D7 D6 D5 D4 D3 D2 D1 D0
по даташиту (5,1 пункт) D7 это B ( в табличке, B = 1 incremental bus; active B = 0 no incremental bus;X = indifferent 0,1)поэтому D7 будет 0.
D7 D6 D5 D4 D3 D2 D1 D0
B  X  X  X  0  0  0  0    INPUT ATTENUATION (из даташита)

X X X 0 0 0 0 INPUT ATTENUATION

*/


tda7442(00b01100000);  //INPUT ATTENUATION   (-16dB )
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
tda7442(50b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER ATTENUATION = 0dB ~ -79dB)
tda7442(60b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB)
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER
            
 

 
void tda7442(int subaddressint data)  //Вызов tda7719 char??

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//или Wire.beginTransmission(0b1000000);
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Serial.println(subaddress);   //Пишем подадрем в монитор 
Serial.println(data);         //Пишем команду в монитор 
Wire.endTransmission();       //СТОП 
//delay(500); 


в мониторе ком порта тоже видим реакцию - наши данные в десятичном виде
PHP код:

0
96
1
6
2
3
3
31
4
126
5
0
6
0
7
0
8
0
9
6
0
96
1
6
2
3
3
31
4
126
5
0
6
0
7
0
8
0
9



Alekssandr 27.09.2016 23:57

Молодец!!! Хотел написать чтоб попробовал 40, так как я не понял за что отвечает буковка B, а вообще она может быть или 0 (в итоге 0x40) или 1 (в итоге 0x80).

oleg707 28.09.2016 00:14

Цитата:

Сообщение от Alekssandr (Сообщение 370246)
Молодец!!! Хотел написать чтоб попробовал 40, так как я не понял за что отвечает буковка B, а вообще она может быть или 0 (в итоге 0x40) или 1 (в итоге 0x80).

Очень помог yuriy m:yes2:
Адрес в мануале явно указан, так что ХЗ.
буковку видел только в субадресе
B = 1 incremental bus; active
B = 0 no incremental bus;

И потом ( пока еще рано) у меня возникнет вопрос, как управлять этой штукой в режиме incremental bus ( 7 стр мануала, я так понял это когда
CHIP ADDRESS --- SUBADDRESS --- DATA 1 to DATA n)
И надо ли это. По идее шину разгружать должно при большом объеме данных. А на шине и так пару устройств...

yuriy m 28.09.2016 10:03

Цитата:

Сообщение от oleg707 (Сообщение 370248)
Очень помог yuriy m:yes2:
Адрес в мануале явно указан, так что ХЗ.

Вот теперь я вспомнил,ардуиновская библиотека "су**"в адресе rw 8й бит подставляет сама, посему ей нужно указывать только старшие 7бит :big:

oleg707 28.09.2016 11:11

Цитата:

Сообщение от yuriy m (Сообщение 370270)
Вот теперь я вспомнил,ардуиновская библиотека "су**"в адресе rw 8й бит подставляет сама, посему ей нужно указывать только старшие 7бит :big:

Первый пакет шлется от ведущего к ведомому это физический адрес устройства и бит направления.
http://easyelectronics.ru/img/starters/IIC/IIC-SLA.GIF
Сам адрес состоит из семи бит (вот почему до 127 устройств на шине), а восьмой бит означает что будет делать Slave на следующем байте — принимать или передавать данные. Девятым битом идет бит подтверждения ACK.

Если Slave услышал свой адрес и считал полностью, то на девятом такте он придавит линию SDA в 0, сгенерировав ACK — то есть Понял!
Мастер, заметя это, понимает, что все идет по плану и можно продолжать. Если Slave не обнаружился, прозевал адрес, неправильно принял байт, сгорел или еще что с ним случилось, то, соответственно, SDA на девятом такте будет прижать некому и ACK не получится. Будет NACK. Мастер с горя хлопнет водки и прекратит свои попытки до лучших времен.
После адресного пакета идут пакеты с данными в ту или другую сторону, в зависимости от бита RW в заголовочном пакете.
Вот, например, Запись. В квадратиках идут номера битов. W=0
http://easyelectronics.ru/img/starte.../I2C-2byte.GIF


Если смотрим в мануал, то адрес у нас S 100000 A 0, то есть косяк в физическом адресе звукового проца и обработкой его WIRE. КОгда я писал все нули в нужном количестве, wire смещала первую единицу левее и на физику она не попадала. Поэтому в первой осциллограмме запрос выглядит, как все нули. Соответственно ответить некому.
Короче, используем скетч поиска I2C устройств.

Ладно, пойду припаивать вход и выход линейные и дальше с софтом гуляться.
Наушники эта TDA7442D потянет?

oleg707 28.09.2016 16:44

итак
подключил
вход к джеку наушников телефона
выход - на линейный вход активной акустики.

Прицепил 2 кнопки для теста ( подтяжку не надо, использую внутренние резаки; один конец на минус, второй на 52 и 53 пины)

скетч, при нажатии кнопок громкости в ком порт идут значения громкости
0-80 звук есть, 80-255 Mute.

Монитор ком порта работает только когда есть питание на TDA7442!

PHP код:

//Для запуска tda7442 достаточно загрузить скетчь который ниже в ардуино
#include "Wire.h" //добавление библиотеки I2C шины 
//настройка кнопок громкости
const int volUPbutton 52;     // номер пина на подключение кнопки VOL+
const int volDNbutton 53;     // номер пина на подключение кнопки VOL-  


int buttonStateVOLup 0//переменная для чтения статуса кнопки
int buttonStateVOLdn 0//переменная для чтения статуса кнопки
byte MasterVolume 80// переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, в диапазоне 0..255
 
void setup() 

pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
pinMode(volUPbuttonINPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости +
pinMode(volDNbuttonINPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости -
digitalWrite(volUPbuttonHIGH);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
digitalWrite(volDNbuttonHIGH);       // включить подтягивающий резистор

Wire.begin(); // включение библиотеки I2C шины 
delay(1000); 
Serial.begin(9600); // ком порт
Serial.println(MasterVolume);
delay(1000); 

void loop(){ 

  
buttonStateVOLup digitalRead(volUPbutton); // читаем статус кнопки volUPbutton
  // проверяем, нажата ли кнопка 
    
if (buttonStateVOLup == LOW) {      digitalWrite(13HIGH); MasterVolume--; Serial.println(MasterVolume);  delay(300); } //если нажата кнопка VOL+, то включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт и паузу от дребезга
     
else {      digitalWrite(13LOW);  }//если нет - тушим светик.
     
  
buttonStateVOLdn digitalRead(volDNbutton); // читаем статус кнопки volDNbutton   
      // проверяем, нажата ли кнопка 
      
if (buttonStateVOLdn == LOW) {      MasterVolume++; Serial.println(MasterVolume);  delay(300); }//если нажата кнопка VOL- увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт и паузу от дребезга

 /*
tda7442(0, 0b01100000);  //INPUT ATTENUATION  -16dB (0b - показывает, что данные будут в двоичной форме. )
потом идут разряды
D7 D6 D5 D4 D3 D2 D1 D0
по даташиту (5,1 пункт) D7 это B ( в табличке, B = 1 incremental bus; active B = 0 no incremental bus;X = indifferent 0,1)поэтому D7 будет 0.
D7 D6 D5 D4 D3 D2 D1 D0
B  X  X  X  0  0  0  0    INPUT ATTENUATION (из даташита)

X X X 0 0 0 0 INPUT ATTENUATION

*/




tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER
            
 

 
void tda7442(int subaddressint data)  //Вызов tda7719 char??

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//или Wire.beginTransmission(0b1000000);
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
//Serial.println(subaddress);   //Пишем подадрем в монитор 
//Serial.println(data);         //Пишем команду в монитор 
Wire.endTransmission();       //СТОП 
//delay(500); 



oleg707 28.09.2016 16:56

Еще по качеству звука -
Источник - телефон играет флак через штекер наушников
Эквалайзер отключен на телефоне и на tda7442.
С выхода tda7442 звук идет на линейный вход ресивера Yamaha RX-V1071, который выводит звук на колонки Yamaha ns-f700.
Ардуина питается от ЮСБ компа, 7442 питается от домашнего блока питания (12В) через КРЕНку (8В).

Так вот, звук НОРМАЛЬНЫЙ. Нет хрюкания, жевания, "басы басовые, верха серебристые."

oleg707 28.09.2016 17:42

а вот простой готовый скетч для регулировки громкости, собирай, прошивай ардуину и регулируй. Начальная громкость -35dB. Никаких плюшек, только громкость!

PHP код:

//Для запуска tda7442 достаточно загрузить скетчь который ниже в ардуино
/*
вход к джеку наушников телефона
выход - на линейный вход активной акустики.
Прицепил 2 кнопки для теста ( подтяжку не надо, использую внутренние резаки; один конец на минус, второй на 52 и 53 пины)
скетч, при нажатии кнопок громкости в ком порт идут значения громкости 
0-80 звук есть, 80-255 Mute.
Монитор ком порта работает только когда есть питание на TDA7442!
*/

#include "Wire.h" //добавление библиотеки I2C шины 
//настройка кнопок громкости
const int volUPbutton 52;     // номер пина на подключение кнопки VOL+
const int volDNbutton 53;     // номер пина на подключение кнопки VOL-  


int buttonStateVOLup 0//переменная для чтения статуса кнопки
int buttonStateVOLdn 0//переменная для чтения статуса кнопки
byte MasterVolume 35// переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, в диапазоне 0..255
 
void setup() 

pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
pinMode(volUPbuttonINPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости +
pinMode(volDNbuttonINPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости -
digitalWrite(volUPbuttonHIGH);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
digitalWrite(volDNbuttonHIGH);       // включить подтягивающий резистор

Wire.begin(); // включение библиотеки I2C шины 
delay(1000); 
Serial.begin(9600); // ком порт
Serial.println(MasterVolume);
delay(1000); 

void loop(){ 

  
buttonStateVOLup digitalRead(volUPbutton); // читаем статус кнопки volUPbutton
  // проверяем, нажата ли кнопка 
    
if (buttonStateVOLup == LOW) {  
                                     
digitalWrite(13HIGH); 
                                     if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);
                                     
Serial.println(MasterVolume);  delay(50);
                                 } 
//если нажата кнопка VOL+, то включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт и паузу от дребезга
                                              
else {      digitalWrite(13LOW);  }//если нет - просто тушим светик.
     
  
buttonStateVOLdn digitalRead(volDNbutton); // читаем статус кнопки volDNbutton   
      // проверяем, нажата ли кнопка 
      
if (buttonStateVOLdn == LOW)
                                 {      if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);
                                         
Serial.println(MasterVolume);  delay(30); 
                                 }
//если нажата кнопка VOL- увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт и паузу от дребезга

 /*
tda7442(0, 0b01100000);  //INPUT ATTENUATION  -16dB (0b - показывает, что данные будут в двоичной форме. )
потом идут разряды
D7 D6 D5 D4 D3 D2 D1 D0
по даташиту (5,1 пункт) D7 это B ( в табличке, B = 1 incremental bus; active B = 0 no incremental bus;X = indifferent 0,1)поэтому D7 будет 0.
D7 D6 D5 D4 D3 D2 D1 D0
B  X  X  X  0  0  0  0    INPUT ATTENUATION (из даташита)

X X X 0 0 0 0 INPUT ATTENUATION

*/




tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
            
 

 
void tda7442(int subaddressint data)  //Вызов tda7719 char??

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//или Wire.beginTransmission(0b1000000);
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
//Serial.println(subaddress);   //Пишем подадрем в монитор 
//Serial.println(data);         //Пишем команду в монитор 
Wire.endTransmission();       //СТОП 
//delay(500); 



yuriy m 28.09.2016 19:48

И тут Остапа понесло...:big: в хорошем смысле:smile1:

oleg707 28.09.2016 20:27

Цитата:

Сообщение от yuriy m (Сообщение 370324)
И тут Остапа понесло...:big: в хорошем смысле:smile1:

Когда я искал хоть какую нибудь инфу, чтобы делать самому с нуля - нифига нету, только на одном сайте печатка+HEX прошивка, так только за деньги ( с платного аккаунта).
А тут простая схема, ардуину любую цеплять, пины только переназначить.
Бери и повторяй.


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

PHP код:

//Для запуска tda7442 достаточно загрузить скетчь который ниже в ардуино
/*
вход к джеку наушников телефона
выход - на линейный вход активной акустики.
Прицепил 2 кнопки для теста ( подтяжку не надо, использую внутренние резаки; один конец кнопок  на минус, второй на 52 и 53 пины)
Энкодер подключается так: общий на массу, остальные на 50 и 53 пины.

При нажатии кнопок громкости в ком порт идут значения громкости 
0-80 звук есть, 80-255 Mute.
Монитор ком порта работает только когда есть питание на TDA7442!
*/

// про энкодер http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder
#include "Wire.h" //добавление библиотеки I2C шины 
//настройка кнопок громкости
const int volUPbutton 52;     // номер пина на подключение кнопки VOL+
const int volDNbutton 53;     // номер пина на подключение кнопки VOL-  
//для энкодера
int stepVOLamount 2// шаг изменения громкости энкодером
unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
const 
int pin_A 50// 
const int pin_B 51// 
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
//конец для энкодера

int buttonStateVOLup 0//переменная для чтения статуса кнопки
int buttonStateVOLdn 0//переменная для чтения статуса кнопки
byte MasterVolume 36// переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, в диапазоне 0..255
 
void setup() 

pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
pinMode(volUPbuttonINPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости +
pinMode(volDNbuttonINPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости -
digitalWrite(volUPbuttonHIGH);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
digitalWrite(volDNbuttonHIGH);       // включить подтягивающий резистор

Wire.begin(); // включение библиотеки I2C шины 
delay(1000); 
Serial.begin(9600); // ком порт
Serial.println(MasterVolume);

pinMode(pin_AINPUT); //настройка пинов энкодера
digitalWrite(pin_AHIGH);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(pin_BINPUT);
digitalWrite(pin_BHIGH);
currentTimeVoumeControl millis(); //для энкодера
loopTimeVoumeControl currentTimeVoumeControl;//для энкодера


void loop(){ 

  
buttonStateVOLup digitalRead(volUPbutton); // читаем статус кнопки volUPbutton
  // проверяем, нажата ли кнопка 
    
if (buttonStateVOLup == LOW) {  
                                     
digitalWrite(13HIGH); 
                                     if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);
                                     
Serial.println(MasterVolume);  delay(50);
                                 } 
//если нажата кнопка VOL+, то включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт и паузу от дребезга
                                              
else {      digitalWrite(13LOW);  }//если нет - просто тушим светик.
     
  
buttonStateVOLdn digitalRead(volDNbutton); // читаем статус кнопки volDNbutton   
      // проверяем, нажата ли кнопка 
      
if (buttonStateVOLdn == LOW)
                                 {      if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);
                                         
Serial.println(MasterVolume);  delay(30); 
                                 }
//если нажата кнопка VOL- увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт и паузу от дребезга

 /*
tda7442(0, 0b01100000);  //INPUT ATTENUATION  -16dB (0b - показывает, что данные будут в двоичной форме. )
потом идут разряды
D7 D6 D5 D4 D3 D2 D1 D0
по даташиту (5,1 пункт) D7 это B ( в табличке, B = 1 incremental bus; active B = 0 no incremental bus;X = indifferent 0,1)поэтому D7 будет 0.
D7 D6 D5 D4 D3 D2 D1 D0
B  X  X  X  0  0  0  0    INPUT ATTENUATION (из даташита)

X X X 0 0 0 0 INPUT ATTENUATION

*/




tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
            
 

 
void tda7442(byte subaddressbyte data)  //Вызов tda7719 char??

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//или Wire.beginTransmission(0b1000000);
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
//Serial.println(subaddress);   //Пишем подадрем в монитор 
//Serial.println(data);         //Пишем команду в монитор 
Wire.endTransmission();       //СТОП 
//delay(500); 


//для энкодера
currentTimeVoumeControl millis();
if(
currentTimeVoumeControl >= (loopTimeVoumeControl 5)){ // проверяем каждые 5мс (200 Гц)
encoder_A digitalRead(pin_A); // считываем состояние выхода А энкодера
encoder_B digitalRead(pin_B); // считываем состояние выхода А энкодера
if((!encoder_A) && (encoder_A_prev)){ // если состояние изменилось с положительного к нулю
                                     
if(encoder_B)  { // выход В в полож. сост., значит вращение по часовой стрелке
                                                    // увеличиваем громкость, не более чем до 80
                                                     
if(MasterVolume stepVOLamount <= 80) (MasterVolume += stepVOLamount); Serial.println(MasterVolume);
                                                    }
                                                             else { 
// выход В в 0 сост., значит вращение против часовой стрелки
                                                                    // уменьшаем громкость, но не ниже 0
                                                                    
if(MasterVolume stepVOLamount >= 0) (MasterVolume -= stepVOLamount); Serial.println(MasterVolume);
                                                                  }
                                     }

encoder_A_prev encoder_A// сохраняем значение А для следующего цикла
loopTimeVoumeControl currentTimeVoumeControl; }
//конец для энкодера



Rage2 29.09.2016 19:12

oleg707, красафчик! Лайк! =)
...плз. продолжай

oleg707 30.09.2016 23:21

http://pccar.ru/showthread.php?p=370522#post370522
фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие и т.д.

В ардуино понадобилось мне иметь шаблон для обработки кучи кнопок.
Начал было писать сам, но нашел на просторах код, который подстроил под себя. Может кому пригодиться.
Просто подключаете кнопки к массе и пинам ( X + n) количеством сколько хотите, правите код и пользуете.

oleg707 01.10.2016 15:11

без энкодера, без ДЕЛАЕВ, с подавлением дребезга кнопок
 
без энкодера, без ДЕЛАЕВ, с подавлением дребезга кнопок и с увеличением/уменьшением громкости при удержании кнопок.

PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include "Wire.h" //добавление библиотеки I2C шины

  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;                                           }
}
}

};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~









//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

// __________ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ__________(также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(53);   //назначаем кнопке ГРОМКОСТИ++ ножку 53
BUTTON VOLDNbutton(52);   //назначаем кнопке ГРОМКОСТИ-- ножку 52
byte MasterVolume 26//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)






 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины  

 


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки

 // Serial.println("___________________start__________________________________ ");

 
if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки 
 
if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки
 
if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик
 
if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность
 
if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание 
 


 
if (BLACKbutton.click_down) {Serial.println("BLACKbutton = click_down"); }
 if (
BLACKbutton.click_up) {Serial.println("BLACKbutton = click_up"); }
 if (
BLACKbutton.doubleclick) {Serial.println("BLACKbutton = doubleclick"); }
 if (
BLACKbutton.timer) {Serial.println("BLACKbutton = timer"); }
 if (
BLACKbutton.retention) {Serial.println("BLACKbutton = retention"); }

 
// Serial.println("___________________end______________________________ ");




  
if (VOLUPbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL+, то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.
           
if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
          
        
}

  if (
VOLDNbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL-  то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт
           
if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
        
        
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
if (VOLUPbutton.retention==1)//если кнопка нажата  и удержмвается //надо бы увеличивать громкость по шагам
        

         
digitalWrite(13,1); 
         
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
         
if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
         
Vupupup 1;
        }
 if (
VOLUPbutton.click_up) { Vupupup 0; }          
 
//if (Vupupup == 1){VOLUPbutton.read();if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");} 
//~~~~~~~~~~~~
 
if (VOLDNbutton.retention==1)//если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
        

         
digitalWrite(13,1); 
         if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
         
Vdndndn 1;
        }
         
 
//if (Vdndndn == 1){} 
if (VOLUPbutton.click_up) { Vupupup 0; }  
if (
VOLDNbutton.click_up) { Vdndndn 0; }          
//===================================================================================
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью interval.
   

  
     
if(REDbutton.click_down==1)//если кнопка REDbutton нажата ... (статус нажатой кнопки == 1)
           

            
digitalWrite(13,0); //выключили диодик
           

      if (
REDbutton.click_up==)//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)
      
           

            
digitalWrite(13,1); //включили диодик
           
}
        



//конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
// То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
// Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
// и так до конца: tda7442(9, 0b00000110); 
//конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~








//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью interval.
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval ) {
                                      
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) { if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1) { if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
   
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 


то же самое, но с УСКОРЕНИЕМ при удержании
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include "Wire.h" //добавление библиотеки I2C шины

  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;                                           }
}
}

};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~









//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

// __________ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ__________(также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(53);   //назначаем кнопке ГРОМКОСТИ++ ножку 53
BUTTON VOLDNbutton(52);   //назначаем кнопке ГРОМКОСТИ-- ножку 52
byte MasterVolume 26//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
int USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины  

 


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки

 // Serial.println("___________________start__________________________________ ");

 
if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки 
 
if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки
 
if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик
 
if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность
 
if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание 
 


 
if (BLACKbutton.click_down) {Serial.println("BLACKbutton = click_down"); }
 if (
BLACKbutton.click_up) {Serial.println("BLACKbutton = click_up"); }
 if (
BLACKbutton.doubleclick) {Serial.println("BLACKbutton = doubleclick"); }
 if (
BLACKbutton.timer) {Serial.println("BLACKbutton = timer"); }
 if (
BLACKbutton.retention) {Serial.println("BLACKbutton = retention"); }

 
// Serial.println("___________________end______________________________ ");




  
if (VOLUPbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL+, то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.
           
if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }

  if (
VOLDNbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL-  то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт
           
if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
if (VOLUPbutton.retention==1)//если кнопка нажата  и удержмвается //надо бы увеличивать громкость по шагам
        

         
digitalWrite(13,1); 
         
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
         
if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
         
Vupupup 1;
        }
 if (
VOLUPbutton.click_up) { Vupupup 0; }          
 
//if (Vupupup == 1){VOLUPbutton.read();if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");} 
//~~~~~~~~~~~~
 
if (VOLDNbutton.retention==1)//если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
        

         
digitalWrite(13,1); 
         if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
         
Vdndndn 1;
        }
         
 
//if (Vdndndn == 1){} 
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}  
if (
VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}          
//===================================================================================
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
   

  
     
if(REDbutton.click_down==1)//если кнопка REDbutton нажата ... (статус нажатой кнопки == 1)
           

            
digitalWrite(13,0); //выключили диодик
           

      if (
REDbutton.click_up==)//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)
      
           

            
digitalWrite(13,1); //включили диодик
           
}
        



//конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
// То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
// Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
// и так до конца: tda7442(9, 0b00000110); 
//конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~








//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                      
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

то же самое, но еще и с энкодером.
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include "Wire.h" //добавление библиотеки I2C шины
//для энкодера
int stepVOLamount 2// шаг изменения громкости энкодером
unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
const 
int pin_A 50// 
const int pin_B 51// 
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
//конец для энкодера
  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;                                           }
}
}

};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~









//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

// __________ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ__________(также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(53);   //назначаем кнопке ГРОМКОСТИ++ ножку 53
BUTTON VOLDNbutton(52);   //назначаем кнопке ГРОМКОСТИ-- ножку 52
byte MasterVolume 26//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
int USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины  
//~~~~~~~~ для энкодера~~~~~~~~~~
pinMode(pin_AINPUT); //настройка пинов энкодера
digitalWrite(pin_AHIGH);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(pin_BINPUT);
digitalWrite(pin_BHIGH);
currentTimeVoumeControl millis(); //для энкодера
loopTimeVoumeControl currentTimeVoumeControl;//для энкодера
//~~~~~~~~конец для энкодера~~~~~~~~~~
 


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки

 // Serial.println("___________________start__________________________________ ");

 
if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки 
 
if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки
 
if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик
 
if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность
 
if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание 
 


 
if (BLACKbutton.click_down) {Serial.println("BLACKbutton = click_down"); }
 if (
BLACKbutton.click_up) {Serial.println("BLACKbutton = click_up"); }
 if (
BLACKbutton.doubleclick) {Serial.println("BLACKbutton = doubleclick"); }
 if (
BLACKbutton.timer) {Serial.println("BLACKbutton = timer"); }
 if (
BLACKbutton.retention) {Serial.println("BLACKbutton = retention"); }

 
// Serial.println("___________________end______________________________ ");




  
if (VOLUPbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL+, то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.
           
if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }

  if (
VOLDNbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL-  то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт
           
if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
if (VOLUPbutton.retention==1){Vupupup 1;}//если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
  
if (VOLDNbutton.retention==1){Vdndndn 1; }     //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}  
if (
VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}          
//===================================================================================

VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.

//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
currentTimeVoumeControl millis();
if(
currentTimeVoumeControl >= (loopTimeVoumeControl 5)){ // проверяем каждые 5мс (200 Гц)состояние энкодера
encoder_A digitalRead(pin_A); // считываем состояние выхода А энкодера
encoder_B digitalRead(pin_B); // считываем состояние выхода А энкодера

if((!encoder_A) && (encoder_A_prev)) // если состояние изменилось с положительного к нулю
                                     
{
                                       if(
encoder_B)  { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем громкость, не более чем до 80
                                                      
if(MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount); Serial.println(MasterVolume);}
                                                      }
                                                     else { 
// выход В в 0 сост., значит вращение против часовой стрелки
                                                          
if(MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount); Serial.println(MasterVolume); }  // уменьшаем громкость, но не ниже 0
                                                          
}
                                     }
    
encoder_A_prev encoder_A// сохраняем значение А для следующего цикла
loopTimeVoumeControl currentTimeVoumeControl; }
//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


  
     
if(REDbutton.click_down==1)//если кнопка REDbutton нажата ... (статус нажатой кнопки == 1)
           

            
digitalWrite(13,0); //выключили диодик
           

      if (
REDbutton.click_up==)//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)
      
           

            
digitalWrite(13,1); //включили диодик
           
}
        



//конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
// То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
// Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
// и так до конца: tda7442(9, 0b00000110); 
//конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~








//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 


oleg707 02.10.2016 20:55

//Скетч
// с подавлением дребезга кнопок
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером
// с функцией MUTE
//без дисплея по I2C
//без активации внутреннего эквалайзера TDA7442D

PHP код:

//~~~~~~~~~~~~Описание начнется с 100 строки~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include "Wire.h" //добавление библиотеки I2C шины
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int stepVOLamount 2// шаг изменения громкости энкодером
unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
const 
int pin_A 50// 
const int pin_B 51// 
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


//Скетч 
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером с функцией MUTE
//без дисплея по I2C






//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

// __________ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ__________(также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(53);   //назначаем кнопке ГРОМКОСТИ++ ножку 53
BUTTON VOLDNbutton(52);   //назначаем кнопке ГРОМКОСТИ-- ножку 52
BUTTON MUTEbutton(49);   //назначаем кнопке MUTE ножку 49
byte MasterVolume 26//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
bool MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины  
//~~~~~~~~ для энкодера~~~~~~~~~~
pinMode(pin_AINPUT); //настройка пинов энкодера
digitalWrite(pin_AHIGH);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(pin_BINPUT);
digitalWrite(pin_BHIGH);
currentTimeVoumeControl millis(); //для энкодера
loopTimeVoumeControl currentTimeVoumeControl;//для энкодера
//~~~~~~~~конец для энкодера~~~~~~~~~~
 


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
MUTEbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки MUTE
 // Serial.println("___________________start__________________________________ ");

 
if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки 
 
if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки
 
if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик
 
if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность
 
if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание 
 


 
if (BLACKbutton.click_down) {Serial.println("BLACKbutton = click_down"); }
 if (
BLACKbutton.click_up) {Serial.println("BLACKbutton = click_up"); }
 if (
BLACKbutton.doubleclick) {Serial.println("BLACKbutton = doubleclick"); }
 if (
BLACKbutton.timer) {Serial.println("BLACKbutton = timer"); }
 if (
BLACKbutton.retention) {Serial.println("BLACKbutton = retention"); }

 
// Serial.println("___________________end______________________________ ");
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTEbutton.click_down)//если кнопка MUTE однократно нажата
        

        
Serial.println("   M U T E     ");
        if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
        
MuteActiv = (!MuteActiv); 
        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
        
Serial.println("   END M U T E     ");
        }


        
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

  
if (VOLUPbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL+, то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.
           
if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }

  if (
VOLDNbutton.click_down)//если кнопка однократно нажата
        
{//если нажата кнопка VOL-  то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт
           
if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
if (VOLUPbutton.retention==1){Vupupup 1;}//если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
  
if (VOLDNbutton.retention==1){Vdndndn 1; }     //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}  
if (
VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}          
//===================================================================================

VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.

//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
currentTimeVoumeControl millis();
if(
currentTimeVoumeControl >= (loopTimeVoumeControl 5)){ // проверяем каждые 5мс (200 Гц)состояние энкодера
encoder_A digitalRead(pin_A); // считываем состояние выхода А энкодера
encoder_B digitalRead(pin_B); // считываем состояние выхода А энкодера

if((!encoder_A) && (encoder_A_prev)) // если состояние изменилось с положительного к нулю
                                     
{
                                       if(
encoder_B)  { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем громкость, не более чем до 80
                                                      
if(MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount); Serial.println(MasterVolume);}
                                                      }
                                                     else { 
// выход В в 0 сост., значит вращение против часовой стрелки
                                                          
if(MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount); Serial.println(MasterVolume); }  // уменьшаем громкость, но не ниже 0
                                                          
}
                                     }
    
encoder_A_prev encoder_A// сохраняем значение А для следующего цикла
loopTimeVoumeControl currentTimeVoumeControl; }
//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


  
     
if(REDbutton.click_down==1)//если кнопка REDbutton нажата ... (статус нажатой кнопки == 1)
           

            
digitalWrite(13,0); //выключили диодик
           

      if (
REDbutton.click_up==)//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)
      
           

            
digitalWrite(13,1); //включили диодик
           
}
        



//конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(90b00000110);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); //СТАРТ и Адрес микросхема tda7442 
//после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
// То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
// Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
// и так до конца: tda7442(9, 0b00000110); 
//конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~








//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 


demtro 05.10.2016 23:58

Если можно схему подключения выложи.

yuriy m 06.10.2016 00:51

Когда с андрюши управлять будишь ?

oleg707 06.10.2016 19:21

Цитата:

Сообщение от yuriy m (Сообщение 370878)
Когда с андрюши управлять будишь ?

Когда андроид сдк освою.:dntknw:
Фишка в том, что это решение АППАРАТНОЕ и не зависит от зависаний планшета, задержек включения-выключения и прочего. И подключать можно хоть на кассетный плеер.

oleg707 06.10.2016 19:25

Цитата:

Сообщение от demtro (Сообщение 370872)
Если можно схему подключения выложи.

а чего её выкладывать то, в даташите есть.
Когда сделаю рабочую версию с 8 атмегой - тогда печатку и выложу.

Kisel39 06.10.2016 19:58

Не в обиду Олег, можно намного правильнее сделать:
Как я понимаю приемом и управлением будет рулить приложение с андройда,
Так делай всю обработку в приложении, а атмега будет только шлюзом.
Я тоже пытался читать протокол cannyo , но на ардуино ничего не вышло, вернее читать получалось, а отправлять - никак, только на 32 битах ARM заработало и то на 96 Mhz. Андройду посилу многое, да и ресурсы другие, у меня сейчас тинси наполовину шлюз на вторую ( управление питанием и чтением данных ), если андройд тупонет...
Молодец, удачи в проекте !

ali_vlad 06.10.2016 20:20

Цитата:

Сообщение от Kisel39 (Сообщение 370929)
Не в обиду Олег, можно намного правильнее сделать:
Как я понимаю приемом и управлением будет рулить приложение с андройда,
Так делай всю обработку в приложении, а атмега будет только шлюзом.
Я тоже пытался читать протокол cannyo , но на ардуино ничего не вышло, вернее читать получалось, а отправлять - никак, только на 32 битах ARM заработало и то на 96 Mhz. Андройду посилу многое, да и ресурсы другие, у меня сейчас тинси наполовину шлюз на вторую ( управление питанием и чтением данных ), если андройд тупонет...
Молодец, удачи в проекте !

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

yuriy m 06.10.2016 20:31

Цитата:

Сообщение от ali_vlad (Сообщение 370931)
Тыкать в экран во время езды чревато большими неприятностями.
Покрутить крутилку и потыкать кнопки можно и не отрывая глаз от дороги. Да и на руле бывают кнопки.
А что касаемо трансляции команд с андроида на ардуину, так это уже давно придумано. Сериал менеджер. Только добавить в скетч опрос ком-порта и вызов имеющихся функций.

Не ну если просто громкость менять,то да. А как у меня, несколько десятков установок,то удобней с экрана выставить, ну и в параллелей с кнопок управление тоже будит. Да и информация должна как-то отображаться. Кнопками изменишь ,а на андрюше ползунок двигается и все сразу видно...

oleg707 06.10.2016 21:57

tda7442
умеет регулировать громкость
_____ регулировать басы
_____ регулировать пищалки
ВСЁ.
Ну ещё выбор между 4 линейными входами с возможностью микширования основного канала и одного из этих 4х.

Зачем данной конкретной микрухе связь с андроидом то?! Только на экране ползунок показать? :dntknw:
Даже эквалайзер я не активировал в скетче ( во первых, меня устраивает акустика в машине, а во вторых и в плеере можно настроить, как раз в андроиде:big:), хотя на плате детали для EQ распаял.

Когда я в дороге еду я очень редко смотрю на экран, когда делаю громче-тише. Ориентир - по нужной громкости на данный момент.
Дисплей для I2C можно прикрутить, и в него уже скидывать информацию от блока питания и звукового процессора.

oleg707 18.10.2016 00:25

пока я не полез в дебри
 
Вложений: 2
Вложение 45184
схема в диптрейсе - исходникиВложение 45185

С удовольствием выслушаю критику и предложения:smile2:


PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч v22 i7442
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея)
// с функцией MUTE
// дисплей по I2C
//без активации внутреннего эквалайзера TDA7442D 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
LiquidCrystal_I2C lcd(0x27162); // set the LCD address to 0x27 for a 16 chars and 2 line display для 0x27 - настройка экрана для библиотеки LiquidCrystal_I2C2004V1
//LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347



  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTEbutton(8);   //назначаем кнопке MUTE ножку D8
   // BUTTON pin_A(9);
   // BUTTON pin_B(10);
byte MasterVolume 26//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int stepVOLamount 2// шаг изменения громкости энкодером
unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;

  for (
bin 0graygray >>= 1)
    
bin ^= gray;

  return 
bin;
}

//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея


//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
lcd.init();      // initialize the lcd занимает почти секунду

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);
/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.println("   ver e22_testenc   ");
MasterVolume 80;//mute
delay (2000);
MasterVolume 26;
Serial.println("perexodim k osnovnoy programme ");
 } 
//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTEbutton.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTEbutton.click_down)//если кнопка MUTE однократно нажата
        

       
// Serial.println("   M U T E     ");
        
if (MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
        
MuteActiv = (!MuteActiv); 
        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
       
// Serial.println("   END M U T E     ");
        
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}//если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }     //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}  //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
static uint8_t oldValue 0;
  
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);

  if (
value == 0// Энкодер вращается
      
{
    if (
oldValue == 3) { /*  вращение по часовой стрелке // увеличиваем громкость, не более чем до 80*/
                                                      
if(MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount); Serial.println(MasterVolume);}
                       }
    else if (
oldValue == 1) { // Влево
                             
if(MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount); Serial.println(MasterVolume); }  /* уменьшаем громкость, но не ниже 0*/
                            
}
      }



  
oldValue value;


/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

     



/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





  
lcd.backlight();
  
lcd.setCursor(00);
  
lcd.print((millis() )/1000); // вывод кол-ва сек работы блока ( 1 строка 1 символ)
  
  
lcd.setCursor(70);
  
/*lcd.print(flagAKB); // вывод флага AKB
  
  lcd.setCursor(8, 0);
  lcd.print(flagACC); // вывод флага АСС
  
  lcd.setCursor(9, 0);
  lcd.print(flagREM); // вывод флага rem
  lcd.setCursor(11, 0);
  lcd.print(U_acc_real); // вывод напряжения АСС
  
  //lcd.setCursor(5,1);
  */
  //-------------------2 строка---------------------------------
  
lcd.setCursor(01);
  
lcd.print("VOLUME -");
  
lcd.setCursor(81);
  
lcd.print(MasterVolume); 
  
lcd.setCursor(111);
  
lcd.print("dB");


















}
//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 

вот еще для другой библиотеки для I2C дисплея
тут я вывел ползунок текущей громкости на дисплей, приведя его к удобному виду (больше полоска = громче)
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч v22 i7442
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера, но за счёт этого медленно) 
// с функцией MUTE
// дисплей по I2C
//с ползунком громкости
//без активации внутреннего эквалайзера TDA7442D 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
//LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display для 0x27 - настройка экрана для библиотеки LiquidCrystal_I2C2004V1
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347



  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTEbutton(8);   //назначаем кнопке MUTE ножку D8
byte MasterVolume 26//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int stepVOLamount 2// шаг изменения громкости энкодером
unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;

  for (
bin 0graygray >>= 1)
    
bin ^= gray;

  return 
bin;
}

//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея


//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
//lcd.init();      // initialize the lcd занимает почти секунду
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);
/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.println("   ver e24_NEW_E   ");
MasterVolume 80;//mute
delay (2000);
MasterVolume 26;
Serial.println("perexodim k osnovnoy programme ");
 } 
//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTEbutton.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTEbutton.click_down)//если кнопка MUTE однократно нажата
        

       
// Serial.println("   M U T E     ");
        
if (MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
        
MuteActiv = (!MuteActiv); 
        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
       
// Serial.println("   END M U T E     ");
        
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}//если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }     //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}  //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
static uint8_t oldValue 0;
  
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);

  if (
value == 0// Энкодер вращается
      
{
    if (
oldValue == 3) { /*  вращение по часовой стрелке // увеличиваем громкость, не более чем до 80*/
                                                      
if(MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount); Serial.println(MasterVolume);digitalWrite(13,!digitalRead(13));}
                       }
    else if (
oldValue == 1) { // Влево
                             
if(MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount); Serial.println(MasterVolume);digitalWrite(13,!digitalRead(13)); }  /* уменьшаем громкость, но не ниже 0*/
                            
}
      }



  
oldValue value;


/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

     



/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





  
lcd.backlight();
  
  
  
  
  
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
  
  
  
  
  
  
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value
  
lcd.setCursor(00);
  
//lcd.print((millis() )/1000); // вывод кол-ва сек работы блока ( 1 строка 1 символ)
  
  
lcd.setCursor(70);
  
/*lcd.print(flagAKB); // вывод флага AKB
  
  lcd.setCursor(8, 0);
  lcd.print(flagACC); // вывод флага АСС
  
  lcd.setCursor(9, 0);
  lcd.print(flagREM); // вывод флага rem
  lcd.setCursor(11, 0);
  lcd.print(U_acc_real); // вывод напряжения АСС
  
  //lcd.setCursor(5,1);
  */
  //-------------------2 строка---------------------------------
  
lcd.setCursor(01);
  
lcd.print("VOLUME -");
  
lcd.setCursor(81);
  if (
MasterVolume==80){ lcd.print("MUTE");} else  {lcd.print(MasterVolume); }
  
lcd.setCursor(111);
  
lcd.print("dB");


















}
//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


oleg707 18.10.2016 22:50

столкнулся с одним моментом. Когда подключен дисплей, то звуковой тракт ловит помеху от I2C шины. Если дисплей отключен - всё тихо.
Выражается в лёгком писке.
Как бороть?


РАЗОБРАЛСЯ.
Не было массы на кондёре С4, который идёт на ножку 23(CREF).
Из-за этого шла помеха от I2C шины на OUT.
Теперь на максимальной громкости абсолютная тишина.

demtro 19.10.2016 00:04

Если не трудно в диптрейсе укажите номиналы элементов, какую атмегу используете? Планирую повторить вашу схему с небольшими доработками и добавлением необходимых мне частей

oleg707 19.10.2016 00:19

Цитата:

Сообщение от demtro (Сообщение 371794)
Если не трудно в диптрейсе укажите номиналы элементов, какую атмегу используете? Планирую повторить вашу схему с небольшими доработками и добавлением необходимых мне частей

328P. Можно 8, они по выводам одинаковые. Только скетч сразу залить.
номиналы в диптрейсе указаны, или я что пропустил?

oleg707 21.10.2016 01:24

вот скетч, который начал меня устраивать 3
 
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч v29 i7442
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости
// с монитором по ком-порту
//мигание встроенного светодиода при вращении энкодером или при нажатии-удержании кнопок громкости.
//без активации внутреннего эквалайзера TDA7442D 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
//LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display для 0x27 - настройка экрана для библиотеки LiquidCrystal_I2C2004V1
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347



  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTEbutton(8);   //назначаем кнопке MUTE ножку D8
byte MasterVolume 24//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE

//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
int stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
 
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia


unsigned graydecode(unsigned gray) {
  
unsigned bin;

  for (
bin 0graygray >>= 1)
    
bin ^= gray;

  return 
bin;
}

//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея


//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
//lcd.init();      // initialize the lcd занимает почти секунду
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.println("   ver e31_NEW_E   ");
MasterVolume 80;//mute
delay (2000);
MasterVolume 24;
Serial.println("perexodim k osnovnoy programme ");
 } 
//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void printDISPLAY(unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
    
prevTime=millis();
     
     
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
  
  
  
  
  
  
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value
  
lcd.setCursor(00);
  
//lcd.print((millis() )/1000); // вывод кол-ва сек работы блока ( 1 строка 1 символ)
  
  
lcd.setCursor(70);
  
  
//-------------------2 строка---------------------------------
  
lcd.setCursor(01);
  if (
MasterVolume==80){ lcd.print("  MUTE  ");  } else  {lcd.print("VOLUME -");  }
 
// lcd.write(("VOLUME -")+(MasterVolume));   // так получится только с двумя аргументами
 
lcd.print(MasterVolume);
//  lcd.setCursor(12, 1);
lcd.print(" dB ");

if (
13,1){digitalWrite(13,0);}
//lcd.noBacklight();
//lcd.Backlight();
 
  
}
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER (unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
    
prevTime=millis();
    
//    ENCuscorenie(500);
      
static uint8_t oldValue 0;
  
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);


  

  if (
stepENC >0)
  {
    if((
millis() - prevTimeE 120 )  ) 
    {
      
      if (
stepENC>6){stepENC=6;}//НАДО ОбНУЛЯТЬРАЗ В 420
         
if((millis() - prevTimeE 130 )  ) { prevTimeE millis(); stepENC--; }
    }
  }

  if (
value == 0// Энкодер вращается
      

         
     


    if (
oldValue == 3) { /*  вращение по часовой стрелке // увеличиваем громкость, не более чем до 80*/
                                                      
                                                        
if (MasterVolume == 80){stepENC 1;} else {stepENC++;}    Serial.println(stepENC);
                                                        if( 
stepENC ) {stepVOLamount 1;}
                                                        else  if( 
stepENC 10 ) {stepVOLamount 4;}
                                                        else  if( 
stepENC 14 ) {stepVOLamount 6;}
                                                        else  if( 
stepENC 24 ) {stepVOLamount 8;}
                                                        
prevTimeE millis();
                                                        if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                        
                                                      
                       }
    else if (
oldValue == 1) { // Влево


                                                        
if (MasterVolume == 0){stepENC 1;} else {stepENC++;}    Serial.println(stepENC);
                                                        if( 
stepENC ) {stepVOLamount 1;}
                                                        else  if( 
stepENC ) {stepVOLamount 4;}
                                                        else  if( 
stepENC 12 ) {stepVOLamount 6;}
                                                        else  if( 
stepENC 18 ) {stepVOLamount 10;}
                                                        
prevTimeE millis();
                                                        if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                             
                            
}
      }
     
 

 
  
oldValue value;

          

 
  }
}

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================
/*/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  с периодичностью interval
void ENCuscorenie(unsigned long interval )
{

  static unsigned long prevTime = 0; // время когда последний раз переключали 
  if((millis() - prevTime > interval)  ) 
  {
    prevTime = millis();  // 
    digitalWrite(13,0); 
    
    
  }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTEbutton.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTEbutton.click_down)//если кнопка MUTE однократно нажата
        

       
// Serial.println("   M U T E     ");
        
if (MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
        
MuteActiv = (!MuteActiv); 
        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
       
// Serial.println("   END M U T E     ");
        
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(0); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

     



/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





 
  
  
  
  
 








printDISPLAY(100); // выводим на дисплей раз в 100( запуская фушкцию)






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


oleg707 24.10.2016 22:28

PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч v32 i7442
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода при вращении энкодером или при нажатии-удержании кнопок громкости.
//без активации внутреннего эквалайзера TDA7442D 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
//LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display для 0x27 - настройка экрана для библиотеки LiquidCrystal_I2C2004V1
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347



  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTEbutton(8);   //назначаем кнопке MUTE ножку D8
byte MasterVolume 24//СТАВИМ НАЧАЛЬНОЕ ЗНАЧЕНИЕ ГРОМКОСТИ ПРИ ПОДАЧЕ ПИТАНИЯ НА АРДУИНУ - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE

//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
int stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia


unsigned graydecode(unsigned gray) {
  
unsigned bin;

  for (
bin 0graygray >>= 1)
    
bin ^= gray;

  return 
bin;
}

//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея


//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
//lcd.init();      // initialize the lcd занимает почти секунду
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.println("   ver e32_NEW_Eopt   ");
MasterVolume 80;//mute
lcd.noBacklight();
delay (2000);
MasterVolume 24;
Serial.println("perexodim k osnovnoy programme ");
lcd.backlight();
 } 
//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void printDISPLAY(unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
    
prevTime=millis();
     
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
  
  
// lcd.setCursor(0, 0); не надо явно указывать, т.к. отсчет все равно с 0,0
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value вывод полоски громкости в первой строке
 
  //-------------------2 строка---------------------------------
lcd.setCursor(01); //2строка 0символ 
if (MasterVolume==80){ lcd.print("  MUTE  ");  } else  {lcd.print("VOLUME -");  }
lcd.print(MasterVolume);
lcd.print("dB ");

if (
13,1){digitalWrite(13,0);}

 
  }
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER (unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
    
prevTime=millis();
    
      static 
uint8_t oldValue 0;
  
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);


  

  if (
stepENC >0)
  {
    if((
millis() - prevTimeE 120 )  ) 
    {
      
      if (
stepENC>6){stepENC=6;}//НАДО ОбНУЛЯТЬРАЗ В 420
         
if((millis() - prevTimeE 130 )  ) { prevTimeE millis(); stepENC--; }
    }
  }

  if (
value == 0// Энкодер вращается
      

         
     


    if (
oldValue == 3) { /*  вращение по часовой стрелке // увеличиваем громкость, не более чем до 80*/
                                                      
                                                        
if (MasterVolume == 80){stepENC 1;} else {stepENC++;}    Serial.println(stepENC);
                                                        if( 
stepENC ) {stepVOLamount 1;}
                                                        else  if( 
stepENC 10 ) {stepVOLamount 4;}
                                                        else  if( 
stepENC 14 ) {stepVOLamount 6;}
                                                        else  if( 
stepENC 24 ) {stepVOLamount 8;}
                                                        
prevTimeE millis();
                                                        if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                        
                                                      
                       }
    else if (
oldValue == 1) { // Влево


                                                        
if (MasterVolume == 0){stepENC 1;} else {stepENC++;}    Serial.println(stepENC);
                                                        if( 
stepENC ) {stepVOLamount 1;}
                                                        else  if( 
stepENC ) {stepVOLamount 4;}
                                                        else  if( 
stepENC 12 ) {stepVOLamount 6;}
                                                        else  if( 
stepENC 18 ) {stepVOLamount 10;}
                                                        
prevTimeE millis();
                                                        if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                             
                            
}
      }
     
 

 
  
oldValue value;

          

 
  }
}

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTEbutton.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTEbutton.click_down)//если кнопка MUTE однократно нажата
        

        if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
        
MuteActiv = (!MuteActiv); 
        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
        }
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(0); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

     



/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





 
  
  
  
  
 








printDISPLAY(100); // выводим на дисплей раз в 100( запуская фушкцию)






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


demtro 25.10.2016 07:33

Как на счет микширования источников? Имеет ли смысл через tda7442 это делать? Или лучше их физически объединить через сумматор? Думаю просто на счет pcm2704+бт модуль+ радио

oleg707 25.10.2016 12:53

Цитата:

Сообщение от demtro (Сообщение 372461)
Как на счет микширования источников? Имеет ли смысл через tda7442 это делать? Или лучше их физически объединить через сумматор? Думаю просто на счет pcm2704+бт модуль+ радио

У 7442 есть выбор источника (1-4), микшер там не заявлен.
Но конструктивно звук выходит после селектора наружу и заходит обратно. То есть можно смешать 2 источника с регулировкой одного на минус 30 децибел.
В моей конфигурации это не нужно, потому пока сами :acute:

oleg707 13.11.2016 18:38

Добавил меню ( долгое удержание MUTE)
Добавил выбор в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )

PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч v51 i7442
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода   при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//без активации внутреннего эквалайзера TDA7442D 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.

#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347 
#include <EEPROM.h>
char  strokaI[32] = "                ";// Массив для вывода 1 строки на дисплей
char strokaII[32] = "                ";// Массив для вывода 2 строки на дисплей




  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTE_or_MENU_button(8);   //назначаем кнопке MUTE_or_MENU ножку D8

#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MENUmode 0// Признак включённого режима MENU
unsigned long timerMENU =  millis(); // время до того, как мы выйдем из режима меню в обычный режим.
byte vibor_nomera_punkta_v_MENU=1// выбор режима меню
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
byte MasterVolume EEPROM.read(80); //Значение громкости во время первого включения атмеги, надо читать из еепром. - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255


//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
byte stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;
  for (
bin 0graygray >>= 1)
    
bin ^= gray;
  return 
bin;
}
//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея

//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(9600); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.println("   ver s51  ");
//MasterVolume = 80;//mute
lcd.noBacklight();

Serial.println("perexodim k osnovnoy programme ");
lcd.backlight();
if (
MasterVolume == 255) {EEPROM.write(80,24); MasterVolume 24;} //если считанное значение громкости_при_включении за рамками диапазона (0-80), то берём среднее значение 24 и пишем его в еепром по адресу 80 (0x80)

 

//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void IntToChar(int numchar *text)
{
  
text[0] = (num/100) + '0';
  
text[1] = ((num/10)%10) + '0';
  
text[2] = (num%10) + '0';
}
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


void printDISPLAY(unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
                                     
prevTime=millis();
                                     if (
13,1){digitalWrite(13,0);} 
                                     if (
MENUmode == 0) {
                                                        
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
                                                        
lcd.setCursor(00);
                                                        
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value вывод полоски громкости в первой строке
                                                        //-------------------2 строка---------------------------------
                                                        
lcd.setCursor(01); //2строка 0символ 
                                                        
if (MasterVolume==80)
                                                              {
lcd.print("  MUTE  ");  }
                                                              else  {
lcd.print("VOLUME     -");  }
                                                        
lcd.print(MasterVolume);
                                                        
lcd.print("dB ");
                                                        
                                                       }
                                      else 
//if (MENUmode == 1)
                                                        
{
                                                          
                                                          

                              

                                                          
lcd.setCursor(00);
                                                          
lcd.print(strokaI);
                                                          
                                                          
lcd.setCursor(01); //2строка 0символ 
                                                          
lcd.print(strokaII);
    
                                                        }

                                  
                              }
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER (){
  
    static 
uint8_t oldValue 0;
    
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);
    if (
stepENC >0){if((millis() - prevTimeE >120)){if (stepENC>6){stepENC=6;}/*НАДО ОбНУЛЯТЬРАЗ В 420*/ if((millis() - prevTimeE 130)) {prevTimeE millis(); stepENC--;}}} //это обнуляет "ускоение" энкодера, суммарно около секунды
                        
                    

  
if (value == 0// Энкодер вращается
      

         
    if (
oldValue == 3) { /*  вращение по часовой стрелке // увеличиваем громкость, не более чем до 80*/
                                            
if (MENUmode == 0)  {   // то регулируем громкость     
                                                                
if (MasterVolume == 80){stepENC 1;} else {stepENC++;}   /* Serial.println(stepENC);*/
                                                                
if( stepENC ) {stepVOLamount 1;}
                                                                else  if( 
stepENC 10 ) {stepVOLamount 4;}
                                                                else  if( 
stepENC 14 ) {stepVOLamount 6;}
                                                                else  if( 
stepENC 24 ) {stepVOLamount 8;}
                                                                
prevTimeE millis();
                                                                if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                                }
                                             if (
MENUmode == 1) {//то лазим по меню
                                                                
timerMENU millis();
                                                                
vibor_nomera_punkta_v_MENU--;
                                                                 
                                                                }
                                             if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                                                 
timerMENU millis();
                                                                if  (
MasterVolume<=79){MasterVolume++;}
                                                                }                                                                 
                      if (
MENUmode == 3)  
                                {
                                 
timerMENU millis();
                                }   
                                                        
                                                      
                       }

                       
    else if (
oldValue == 1) { // Влево
                      
if (MENUmode == 0)  { // то регулируем громкость  
                                          
if (MasterVolume == 0){stepENC 1;} else {stepENC++;}    /*Serial.println(stepENC);*/
                                          
if( stepENC ) {stepVOLamount 1;}
                                          else  if( 
stepENC ) {stepVOLamount 4;}
                                          else  if( 
stepENC 12 ) {stepVOLamount 6;}
                                          else  if( 
stepENC 18 ) {stepVOLamount 10;}
                                          
prevTimeE millis();
                                          if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                                          
}
                       if (
MENUmode == 1) { //выбор в корне основного меню
                                           
timerMENU millis();
                                           
vibor_nomera_punkta_v_MENU++;  
                                          } 
                       if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                           
timerMENU millis();
                                           if  (
MasterVolume>=1){MasterVolume--;}
                                          } 


                       if (
MENUmode == 3) {
                                 
timerMENU millis();
                      }                   
                             
                            }
      }
     
 

 
  
oldValue value;

          

 
  
}

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
  

 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTE_or_MENU_button.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTE_or_MENU_button.click_down){timerMENU millis();}
 if (
MENUmode == 0)
                 {
                 if (
MUTE_or_MENU_button.click_down)//если кнопка MUTE однократно нажата
                        

                        if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
                        
MuteActiv = (!MuteActiv); 
                        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
                        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
                        }
                 }    
 
 
 
 if (
MENUmode == 1)//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
{
                        if(
vibor_nomera_punkta_v_MENU<=0)   { vibor_nomera_punkta_v_MENU=4;}          //ограничим количество режимов 
                        
if(vibor_nomera_punkta_v_MENU>=5)   { vibor_nomera_punkta_v_MENU=1;}          //переключать режимы будем циклично
    
                        
sprintf(strokaI,"setup mode      "); //запись в буфер текста и значений
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 1){sprintf(strokaII,"EXIT            ");  }    
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==1){MENUmode 0;}//если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_1( EXIT setup), то => закрыть меню и выйти в обычный режим
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 2){sprintf(strokaII,"vol on Pon  -   ") ; IntToChar(EEPROM.read(80), &strokaII[13]);}   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==2){MENUmode 2MasterVolume EEPROM.read(80);}// //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_2 (setup vol on Pon) , то надо бы включить подменю выбора значения 0-80 для записи в еепром атмеги
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 3){sprintf(strokaII,"podmenu3        ") ;}   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==3){}
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 4){sprintf(strokaII,"podmenu4        ") ;} 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==4){}
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                   
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
 
if (MENUmode == 2)//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
{
                    
sprintfstrokaI,"vol on Power on ") ;
                    
                    
sprintf(strokaII,"eeprom80    -   ") ; IntToChar(MasterVolume, &strokaII[13]);
                    if (
MUTE_or_MENU_button.click_down)  
                                                       { if (
EEPROM.read(80)==MasterVolume){ sprintfstrokaI,"eeprom = mastVOL") ;} else { sprintfstrokaI,"eeprom !=mastVOL") ;MENUmode 1;EEPROM.write(80,MasterVolume);}
                                                       }
                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   //Serial.print("vibor_nomera_punkta_v_MENU = " );Serial.print(vibor_nomera_punkta_v_MENU);Serial.print("   MENUmode = "); Serial.println(MENUmode);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//======================================================обработка MENU===================================================================================================
//===========================================================================================================================================================================

if (MUTE_or_MENU_button.retention) {                                           // если удерживаем нажатой кнопку MUTE  
                            //Serial.println("MUTE_or_MENU_button = uderjanie");
                            
MENUmode = (!MENUmode); //инвертируем признак того, что мы в меню
                            
timerMENU millis();
                            
MuteActiv = (!MuteActiv); //возвращаем состояние MUTE на предидущее ( потому что нажав кнопку меню мы сначела жмём MUTE, а только потом активируется меню)
                            
if (MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }  // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
                            
if (MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                          }            


if( 
millis() - timerMENU >= 10000 && MENUmode >= 1// в режиме меню ждем 10 сек
                                   
{
                                    
MENUmode 0;
                                   }
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================



/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(30b00011111);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





 
  
  
  
  
 








printDISPLAY(120); // выводим на дисплей раз в 100( запуская фушкцию)






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


oleg707 25.11.2016 15:37

товарищи, подскажите момент
Сделал регулировку басов, но нет реакции.
То есть меняю команду tda7442(3, BASSlevelBYTE);
А басы не меняются. Я так понял, нужно активировать эквалайзер, вопрос что прописать
даташит

разобрался
tda7442(1, 0b00000001); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)

tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, 0b00000110); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, 0b01111110); //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000); //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000); //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать 0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE
tda7442(5, MasterVolume); //0 - макс громкость, 80-255 - MUTE .
tda7442(6, MasterVolume);
tda7442(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, 6/*0b00000110*/); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4 2-in3 0-in2)


Вот текущий скетч:
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442
int ver 70;
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода   при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//без активации внутреннего эквалайзера TDA7442D 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
// Bitwise NOT (~) https://www.arduino.cc/en/Reference/BitwiseXorNot
// abs() Возвращает модуль числа. http://arduino.ru/Reference/Abs
#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347 
#include <EEPROM.h>
char  strokaI[32] = "                ";// Массив для вывода 1 строки на дисплей
char strokaII[32] = "                ";// Массив для вывода 2 строки на дисплей




  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTE_or_MENU_button(8);   //назначаем кнопке MUTE_or_MENU ножку D8

#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MENUmode 0// Признак включённого режима MENU
unsigned long timerMENU =  millis(); // время до того, как мы выйдем из режима меню в обычный режим.
byte vibor_nomera_punkta_v_MENU=1// выбор режима меню
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
byte MasterVolume EEPROM.read(80); //Значение громкости во время первого включения атмеги, надо читать из еепром. - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
byte  BASSlevelBYTE =EEPROM.read(81);  // значение уровня басов в двоичном виде, для прямого управления tda7442.  
int   BASSlevelDEC 0//значение уровня басов в десятичном виде, Может быть от -14 до +14 (-7-0-+7)


int TREBLElevel =  EEPROM.read(82); // считываем уровень высоких частот из внутренней еепром с 82го адреса.

//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
byte stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;
  for (
bin 0graygray >>= 1)
    
bin ^= gray;
  return 
bin;
}
//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея

//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(250000); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.print("   ver s"); Serial.println(ver);

//MasterVolume = 80;//mute
lcd.noBacklight();

Serial.println("perexodim k osnovnoy programme ");
lcd.backlight();
if (
MasterVolume == 255) {EEPROM.write(80,24); MasterVolume 24;} //если считанное значение громкости_при_включении за рамками диапазона (0-80), то берём среднее значение 24 и пишем его в еепром по адресу 80 (0x80)
if (BASSlevelBYTE == 255) {EEPROM.write(81,0b00011111);} //если считанное значение уровня басов за рамками диапазона, то пишем туда значение 0b00011111 ( в двоичной системе счисления - 8 байт)(0dB)
 

 

//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void IntToChar(int numchar *text)
{
  
text[0] = (num/100) + '0';
  
text[1] = ((num/10)%10) + '0';
  
text[2] = (num%10) + '0';
}
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


void printDISPLAY(unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
                                     
prevTime=millis();
                                     if (
13,1){digitalWrite(13,0);} 
                                     if (
MENUmode == 0) {
                                                        
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
                                                        
lcd.setCursor(00);
                                                        
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value вывод полоски громкости в первой строке
                                                        //-------------------2 строка---------------------------------
                                                        
lcd.setCursor(01); //2строка 0символ 
                                                        
if (MasterVolume==80)
                                                              {
lcd.print      ("      MUTE      ");  }
                                                              else  {
lcd.print("VOLUME     -");  }
                                                        
lcd.print(MasterVolume);
                                                        
lcd.print("dB ");
                                                        
                                                       }
                                      else 
//if (MENUmode == 1)
                                                        
{
                                                          
                                                          

                              

                                                          
lcd.setCursor(00);
                                                          
lcd.print(strokaI);
                                                          
                                                          
lcd.setCursor(01); //2строка 0символ 
                                                          
lcd.print(strokaII);
    
                                                        }

                                  
                              }
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER (){
  
    static 
uint8_t oldValue 0;
    
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);
    if (
stepENC >0){if((millis() - prevTimeE >120)){if (stepENC>6){stepENC=6;}/*НАДО ОбНУЛЯТЬРАЗ В 420*/ if((millis() - prevTimeE 130)) {prevTimeE millis(); stepENC--;}}} //это обнуляет "ускоение" энкодера, суммарно около секунды
                        
                    

  
if (value == 0// Энкодер вращается
      

         
    if (
oldValue == 3) { /*  вращение влево // увеличиваем громкость, не более чем до 80*/
                                            
timerMENU millis();
                      if (
MENUmode == 0)  {   // то регулируем громкость     
                                                                
if (MasterVolume == 80){stepENC 1;} else {stepENC++;}   /* Serial.println(stepENC);*/
                                                                
if( stepENC ) {stepVOLamount 1;}
                                                                else  if( 
stepENC 10 ) {stepVOLamount 4;} else  if( stepENC 14 ) {stepVOLamount 6;} else  if( stepENC 24 ) {stepVOLamount 8;}
                                                                
prevTimeE millis();
                                                                if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                                }
                                             if (
MENUmode == 1) {//то лазим по меню
                                                                
vibor_nomera_punkta_v_MENU--;
                                                                 
                                                                }
                                             if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                                                
if  (MasterVolume<=79){MasterVolume++;}
                                                                }                                                                 
                                               if (
MENUmode == 3)  
                                                                { 
                                                                  if (
BASSlevelBYTE==31 ){BASSlevelBYTE 23;} 
                                                                  if (
BASSlevelBYTE<=23 && BASSlevelBYTE>16){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                                                                  if (
BASSlevelBYTE>=24 && BASSlevelBYTE<=31){BASSlevelBYTE BASSlevelBYTE+0b00000001;}

                      
                              

                                } 
                                
                                                                  
                                               if (
MENUmode == 4)
                                                                {
                                                                }                                  
                                                      
                       }

                       
    else if (
oldValue == 1) { // вправо
                      
timerMENU millis();
            if (
MENUmode == 0)  // то регулируем громкость  
                    

                                          if (
MasterVolume == 0){stepENC 1;} else {stepENC++;}    /*Serial.println(stepENC);*/
                                          
if( stepENC ) {stepVOLamount 1;}
                                          else  if( 
stepENC ) {stepVOLamount 4;}    else  if( stepENC 12 ) {stepVOLamount 6;}  else  if( stepENC 18 ) {stepVOLamount 10;}
                                          
prevTimeE millis();
                                          if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                                        
}
            if (
MENUmode == 1)  { //выбор в корне основного меню
                                           
vibor_nomera_punkta_v_MENU++;  
                      } 
                       if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                           
if  (MasterVolume>=1){MasterVolume--;}
                                          } 


                       if (
MENUmode == 3)
                                       {
                                if (
BASSlevelBYTE>24 && BASSlevelBYTE<31){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                if (
BASSlevelBYTE==23 ){BASSlevelBYTE 30;}  
                                if (
BASSlevelBYTE==31 ){BASSlevelBYTE 30;}                              
                                if (
BASSlevelBYTE<=23 && BASSlevelBYTE>=16){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                                
                                        
                                        
                                       }
      }
     
      }

 
  
oldValue value;

 
// if (BASSlevelDEC > 0){BASSlevel_character = 1;} else {BASSlevel_character = 0;}
 /*if(1<=BASSlevelDEC<=7)    { BASSlevelBYTE =    map (BASSlevelDEC,    1, 7,  30,24);       }
 
 if(-7<=BASSlevelDEC<=-1)  { BASSlevelBYTE =    map (BASSlevelDEC,  -1, -7,  16,22);       }
 if (BASSlevelDEC == 0){BASSlevelBYTE = 0b00011111;} 
 Serial.print("~BASSlevelDEC = "); Serial.print(~BASSlevelDEC); Serial.print("((~BASSlevelDEC)+1) = "); Serial.println(((~BASSlevelDEC)+1)); 
 Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print("     ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");
*/
//конвертация басов из байт в десятичную
if (24<=BASSlevelBYTE && BASSlevelBYTE<=31) {  BASSlevelDEC = (map (BASSlevelBYTE30,24,   17))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) {  BASSlevelDEC = (map (BASSlevelBYTE16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC 0;}
          
Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print("     ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");

 
  
}

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
 

 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTE_or_MENU_button.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTE_or_MENU_button.click_down){timerMENU millis();}
 if (
MENUmode == 0)
                 {
                 if (
MUTE_or_MENU_button.click_down)//если кнопка MUTE однократно нажата
                        

                        if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
                        
MuteActiv = (!MuteActiv); 
                        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
                        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
                        }
                 }    
 
 
 
 if (
MENUmode == 1)//зашли в режим меню и настроек  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
{
                        if(
vibor_nomera_punkta_v_MENU<=0)   { vibor_nomera_punkta_v_MENU=4;}          //ограничим количество режимов 
                        
if(vibor_nomera_punkta_v_MENU>=5)   { vibor_nomera_punkta_v_MENU=1;}          //переключать режимы будем циклично
    
                        
sprintf(strokaI,"-- SETUP MODE --"); //запись в буфер текста и значений
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 1){sprintf(strokaII,"<   exit setup  ");  }    
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==1){MENUmode 0;}//если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_1( EXIT setup), то => закрыть меню и выйти в обычный режим
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 2){//настройка громкости при первом включении (с записью в еепром 80 адрес)
                                                             
sprintfstrokaI,"SETUP volume on ");
                                                             
sprintf(strokaII,"power ON  -___dB") ; IntToChar(EEPROM.read(80), &strokaII[11]);
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==2){MENUmode 2MasterVolume EEPROM.read(80);}// //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_2 (setup vol on Pon) , то надо бы включить подменю выбора значения 0-80 для записи в еепром атмеги
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 3)
                                                            {
                                                            
sprintfstrokaI,"SETUP bass      ");  
                                                            
//sprintf(strokaII,"bass       ___dB") ;
                              
if (BASSlevelDEC >=0){sprintf(strokaII,"bass      +___dB") ;IntToChar(BASSlevelDEC , &strokaII[11]);} else {sprintf(strokaII,"bass      -___dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                              
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==3){MENUmode 3; }
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 4)
                                                            {
                                                            
sprintfstrokaI,"SETUP treble    "); 
                                                            
sprintf(strokaII,"treble     ___dB") ;IntToChar(EEPROM.read(82), &strokaII[11]);
                                                            } 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==4){MENUmode 4; }
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                   
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
                                 
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                                                    
sprintf(  strokaI,"select volume on");
                                                    
sprintfstrokaII,"power ON    -   ");  IntToChar(MasterVolume, &strokaII[13]);
                                                    
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(80)==MasterVolume){ } else { EEPROM.write(80,MasterVolume); MENUmode 1; }
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                
if (MENUmode == 3)//SETUP bass - настройка басов ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                                                    
sprintf(  strokaI,"select bass     ");
                                                    if (
BASSlevelDEC >=0){sprintf(strokaII,"level     +___  ") ;IntToChar(BASSlevelDEC, &strokaII[11]);} else {sprintf(strokaII,"level     -___  ") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(81)==BASSlevelBYTE){ } else { MENUmode 1;EEPROM.write(81,BASSlevelBYTE);}
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~            
                                                   //Serial.print("vibor_nomera_punkta_v_MENU = " );Serial.print(vibor_nomera_punkta_v_MENU);Serial.print("   MENUmode = "); Serial.println(MENUmode);
           
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//======================================================обработка MENU===================================================================================================
//===========================================================================================================================================================================

if (MUTE_or_MENU_button.retention) {                                           // если удерживаем нажатой кнопку MUTE  
                            //Serial.println("MUTE_or_MENU_button = uderjanie");
                            
MENUmode = (!MENUmode); //инвертируем признак того, что мы в меню 
              //MENUmode = 2 - есть и такая строка, тогда MENUmode = (!MENUmode); должно работать некорректно
                            
timerMENU millis();
                            
MuteActiv = (!MuteActiv); //возвращаем состояние MUTE на предидущее ( потому что нажав кнопку меню мы сначела жмём MUTE, а только потом активируется меню)
                            
if (MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }  // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
                            
if (MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                          }            


if( 
millis() - timerMENU >= 10000 && MENUmode >= 1// в режиме меню ждем 10 сек
                                   
{
                                    
MENUmode 0;
                                   }
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================



/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(10b00000110);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3BASSlevelBYTE);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





 
  
  
  
  
 







//BASSconvertBYTEtoDEC;
printDISPLAY(120); // выводим на дисплей раз в 100( запуская фушкцию)
 


 //Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print(" dB    ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");
                                                            //Serial.println(curr_bit_data,BIN); - тогда число выведется в двоичном виде


}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


oleg707 25.11.2016 18:26

PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442
int ver 77;
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода   при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) - только басы
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
// Bitwise NOT (~) https://www.arduino.cc/en/Reference/BitwiseXorNot
// abs() Возвращает модуль числа. http://arduino.ru/Reference/Abs
#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347 
#include <EEPROM.h>
char  strokaI[32] = "                ";// Массив для вывода 1 строки на дисплей
char strokaII[32] = "                ";// Массив для вывода 2 строки на дисплей




  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTE_or_MENU_button(8);   //назначаем кнопке MUTE_or_MENU ножку D8

#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MENUmode 0// Признак включённого режима MENU
unsigned long timerMENU =  millis(); // время до того, как мы выйдем из режима меню в обычный режим.
byte vibor_nomera_punkta_v_MENU=1// выбор режима меню
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
byte MasterVolume EEPROM.read(80); //Значение громкости во время первого включения атмеги, надо читать из еепром. - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
byte  BASSlevelBYTE =EEPROM.read(81);  // значение уровня басов в двоичном виде, для прямого управления tda7442.  
int   BASSlevelDEC 0//значение уровня басов в десятичном виде, Может быть от -14 до +14 (-7-0-+7)
byte EQstate =  EEPROM.read(79); //логическое состояние эквалайзера. 1 - включен, !1( НЕ 1) - выключен


int TREBLElevel =  EEPROM.read(82); // считываем уровень высоких частот из внутренней еепром с 82го адреса.

//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
byte stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;
  for (
bin 0graygray >>= 1)
    
bin ^= gray;
  return 
bin;
}
//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея

//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(250000); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.print("   ver s"); Serial.println(ver);

//MasterVolume = 80;//mute
lcd.noBacklight();

Serial.println("perexodim k osnovnoy programme ");
lcd.backlight();
if (
MasterVolume == 255) {EEPROM.write(80,24); MasterVolume 24;} //если считанное значение громкости_при_включении за рамками диапазона (0-80), то берём среднее значение 24 и пишем его в еепром по адресу 80 (0x80)
if (BASSlevelBYTE == 255) {EEPROM.write(81,0b00011111);} //если считанное значение уровня басов за рамками диапазона, то пишем туда значение 0b00011111 ( в двоичной системе счисления - 8 байт)(0dB)
if (EQstate == 255) {EEPROM.write(79,0b00000001);} //  = EQ_ON

 

//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void IntToChar(int numchar *text)
{
  
text[0] = (num/100) + '0';
  
text[1] = ((num/10)%10) + '0';
  
text[2] = (num%10) + '0';
}
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


void printDISPLAY(unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
                                     
prevTime=millis();
                                     if (
13,1){digitalWrite(13,0);} 
                                     if (
MENUmode == 0) {
                                                        
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
                                                        
lcd.setCursor(00);
                                                        
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value вывод полоски громкости в первой строке
                                                        //-------------------2 строка---------------------------------
                                                        
lcd.setCursor(01); //2строка 0символ 
                                                        
if (MasterVolume==80)
                                                              {
lcd.print      ("      MUTE      ");  }
                                                              else  {
lcd.print("VOLUME     -");  }
                                                        
lcd.print(MasterVolume);
                                                        
lcd.print("dB ");
                                                        
                                                       }
                                      else 
//if (MENUmode == 1)
                                                        
{
                                                          
                                                          

                              

                                                          
lcd.setCursor(00);
                                                          
lcd.print(strokaI);
                                                          
                                                          
lcd.setCursor(01); //2строка 0символ 
                                                          
lcd.print(strokaII);
    
                                                        }

                                  
                              }
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER (){
  
    static 
uint8_t oldValue 0;
    
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);
    if (
stepENC >0){if((millis() - prevTimeE >120)){if (stepENC>6){stepENC=6;}/*НАДО ОбНУЛЯТЬРАЗ В 420*/ if((millis() - prevTimeE 130)) {prevTimeE millis(); stepENC--;}}} //это обнуляет "ускоение" энкодера, суммарно около секунды
                        
                    

  
if (value == 0// Энкодер вращается
      

         
    if (
oldValue == 3) { /*  вращение влево // увеличиваем громкость, не более чем до 80*/
                                            
timerMENU millis();
                      if (
MENUmode == 0)  {   // то регулируем громкость     
                                                                
if (MasterVolume == 80){stepENC 1;} else {stepENC++;}   /* Serial.println(stepENC);*/
                                                                
if( stepENC ) {stepVOLamount 1;}
                                                                else  if( 
stepENC 10 ) {stepVOLamount 4;} else  if( stepENC 14 ) {stepVOLamount 6;} else  if( stepENC 24 ) {stepVOLamount 8;}
                                                                
prevTimeE millis();
                                                                if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                                }
                                             if (
MENUmode == 1) {//то лазим по меню
                                                                
vibor_nomera_punkta_v_MENU--;
                                                                 
                                                                }
                                             if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                                                
if  (MasterVolume<=79){MasterVolume++;}
                                                                }                                                                 
                                               if (
MENUmode == 3)  
                                                                { 
                                                                  if (
BASSlevelBYTE==31 ){BASSlevelBYTE 23;} 
                                                                  if (
BASSlevelBYTE<=23 && BASSlevelBYTE>16){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                                                                  if (
BASSlevelBYTE>=24 && BASSlevelBYTE<=31){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                                } 
                                
                                                                  
                                               if (
MENUmode == 4// EQstate
                                                                
{EQstate =0b00000110//0b00000110 eq вЫключён
                                                                
}                                  
                                                      
                       }

                       
    else if (
oldValue == 1// вправо
    

                      
timerMENU millis();
            if (
MENUmode == 0)  // то регулируем громкость  
                    

                                          if (
MasterVolume == 0){stepENC 1;} else {stepENC++;}    /*Serial.println(stepENC);*/
                                          
if( stepENC ) {stepVOLamount 1;}
                                          else  if( 
stepENC ) {stepVOLamount 4;}    else  if( stepENC 12 ) {stepVOLamount 6;}  else  if( stepENC 18 ) {stepVOLamount 10;}
                                          
prevTimeE millis();
                                          if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                                        
}
                    if (
MENUmode == 1)  { //выбор в корне основного меню
                                   
vibor_nomera_punkta_v_MENU++;  
                      } 
                       if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                           
if  (MasterVolume>=1){MasterVolume--;}
                                          } 


                       if (
MENUmode == 3)  {
                      if (
BASSlevelBYTE>24 && BASSlevelBYTE<31){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                      if (
BASSlevelBYTE==23 ){BASSlevelBYTE 30;}  
                      if (
BASSlevelBYTE==31 ){BASSlevelBYTE 30;}                              
                      if (
BASSlevelBYTE<=23 && BASSlevelBYTE>=16){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                       }
                       if (
MENUmode == 4// EQstate
                                                                
{EQstate =0b11111001//0b00000001 eq включён - есть подмешивание каналов ??? 0b11111001
                                                                
}      
    }
     
      }

 
  
oldValue value;

 
// if (BASSlevelDEC > 0){BASSlevel_character = 1;} else {BASSlevel_character = 0;}
 /*if(1<=BASSlevelDEC<=7)    { BASSlevelBYTE =    map (BASSlevelDEC,    1, 7,  30,24);       }
 
 if(-7<=BASSlevelDEC<=-1)  { BASSlevelBYTE =    map (BASSlevelDEC,  -1, -7,  16,22);       }
 if (BASSlevelDEC == 0){BASSlevelBYTE = 0b00011111;} 
 Serial.print("~BASSlevelDEC = "); Serial.print(~BASSlevelDEC); Serial.print("((~BASSlevelDEC)+1) = "); Serial.println(((~BASSlevelDEC)+1)); 
 Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print("     ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");
*/
//конвертация басов из байт в десятичную
if (24<=BASSlevelBYTE && BASSlevelBYTE<=31) {  BASSlevelDEC = (map (BASSlevelBYTE30,24,   17))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) {  BASSlevelDEC = (map (BASSlevelBYTE16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC 0;}
          
//Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print("     ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");

 
  
}

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
 

 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTE_or_MENU_button.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTE_or_MENU_button.click_down){timerMENU millis();}
 if (
MENUmode == 0)
                 {
                 if (
MUTE_or_MENU_button.click_down)//если кнопка MUTE однократно нажата
                        

                        if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
                        
MuteActiv = (!MuteActiv); 
                        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
                        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
                        }
                 }    
 
 
 
 if (
MENUmode == 1)//зашли в режим меню и настроек  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
{
                        if(
vibor_nomera_punkta_v_MENU<=0)   { vibor_nomera_punkta_v_MENU=5;}          //ограничим количество режимов 
                        
if(vibor_nomera_punkta_v_MENU>=6)   { vibor_nomera_punkta_v_MENU=1;}          //переключать режимы будем циклично
    
                        
sprintf(strokaI,"-- SETUP MODE --"); //запись в буфер текста и значений
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 1){sprintf(strokaII,"<   exit setup  ");  }    
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==1){MENUmode 0;}//если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_1( EXIT setup), то => закрыть меню и выйти в обычный режим
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 2){//настройка громкости при первом включении (с записью в еепром 80 адрес)
                                                             
sprintfstrokaI,"SETUP volume on ");
                                                             
sprintf(strokaII,"power ON  -___dB") ; IntToChar(EEPROM.read(80), &strokaII[11]);
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==2){MENUmode 2MasterVolume EEPROM.read(80);}// //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_2 (setup vol on Pon) , то надо бы включить подменю выбора значения 0-80 для записи в еепром атмеги
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 3)//SETUP bass - настройка басов
                                                            
{
                                                          
//sprintf                            ( strokaI,"SETUP bass      ");  
                                                            
if (EQstate == 0b11111001) {sprintfstrokaI,"SETUP bass EQ_ON") ;}
                                                            if (
EQstate == 0b00000110) {sprintfstrokaI,"SETUP bass EQoff") ;}
                              if (
BASSlevelDEC >=0){sprintf(strokaII,"bass      +___dB") ;IntToChar(BASSlevelDEC , &strokaII[11]);} else {sprintf(strokaII,"bass      -___dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                              
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==3){MENUmode 3; }
                      
            
          
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 4// выбор включен ли эквалайзер 
                                                            
{
                                                            
sprintfstrokaI,"SETUP  EQ state "); 
                                                            if (
EQstate == 0b11111001) {sprintf(strokaII,"   EQ  ON       ") ;}
                                                            else              {
sprintf(strokaII,"   EQ  OFF      ") ;}                  
                                                            } 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==4){MENUmode 4; }
          
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
              
            
if (vibor_nomera_punkta_v_MENU == 5// настройка пищалок
                                                            
{
                                                            
sprintfstrokaI,"SETUP treble    "); 
                                                            
sprintf(strokaII,"treble     ___dB") ;IntToChar(EEPROM.read(82), &strokaII[11]);
                                                            } 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==5){MENUmode 5; }
            
            
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                   
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
                                 
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                                                    
sprintf(  strokaI,"select volume on");
                                                    
sprintfstrokaII,"power ON    -   ");  IntToChar(MasterVolume, &strokaII[13]);
                                                    
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(80)==MasterVolume){ } else { EEPROM.write(80,MasterVolume); MENUmode 1; }
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                 
if (MENUmode == 3)//SETUP bass - настройка басов ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                                                    if (
EQstate == 0b00000110) {sprintfstrokaI,"set bass  EQ OFF") ;} 
                                                    if (
BASSlevelDEC >=0){sprintf(strokaII,"level     +___dB") ;IntToChar(BASSlevelDEC, &strokaII[11]);} else {sprintf(strokaII,"level     -___dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(81)==BASSlevelBYTE){ } else { MENUmode 1;EEPROM.write(81,BASSlevelBYTE);}
                                                                                       }
                                                   }
                if (
MENUmode == 4)  // выбор включен ли эквалайзер 
                          
{
                          
sprintf                           (  strokaI,"select EQ state ");  
                          if (
EQstate == 0b11111001) {sprintf(strokaII,"EQ now is ON    ") ;}
                          else                       {
sprintf(strokaII,"EQ now is OFF   ") ;}
                          if (
MUTE_or_MENU_button.click_down
                                            { if (
EEPROM.read(79) == EQstate) {} else { MENUmode 1;EEPROM.write(79,EQstate);}
                                            }
                                  
                      
                          }
                if (
MENUmode == 5)// настройка пищалок
                        
{
                          if (
EQstate == 0b00000110) {sprintfstrokaI,"set treb  EQ OFF") ;}
                        }                         
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~            
           
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//======================================================обработка MENU===================================================================================================
//===========================================================================================================================================================================

if (MUTE_or_MENU_button.retention) {                                           // если удерживаем нажатой кнопку MUTE  
                            //Serial.println("MUTE_or_MENU_button = uderjanie");
                            
MENUmode = (!MENUmode); //инвертируем признак того, что мы в меню 
              //MENUmode = 2 - есть и такая строка, тогда MENUmode = (!MENUmode); должно работать некорректно
                            
timerMENU millis();
                            
MuteActiv = (!MuteActiv); //возвращаем состояние MUTE на предидущее ( потому что нажав кнопку меню мы сначела жмём MUTE, а только потом активируется меню)
                            
if (MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }  // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
                            
if (MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                          }            


if( 
millis() - timerMENU >= 10000 && MENUmode >= 1// в режиме меню ждем 10 сек
                                   
{
                                    
MENUmode 0;
                                   }
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================



/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1EQstate);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3BASSlevelBYTE);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(40b01111110);  //BXXX0100 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





 
  
  
  
  
 







//BASSconvertBYTEtoDEC;
printDISPLAY(120); // выводим на дисплей раз в 100( запуская фушкцию)
 


 //Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print(" dB    ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");
                                                            //Serial.println(curr_bit_data,BIN); - тогда число выведется в двоичном виде


}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


oleg707 26.11.2016 02:28

басы, пищалки, меню ресета
 
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442
int ver 85;
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода   при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) -  басы и пищалки
// Добавил меню сброса на настройки по умолчанию ( заодно восстанавливает неправильно записанный еепром на нужные значения), работает только один раз, потом надо передёрнуть питание. 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
// Bitwise NOT (~) https://www.arduino.cc/en/Reference/BitwiseXorNot
// abs() Возвращает модуль числа. http://arduino.ru/Reference/Abs
#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347 
#include <EEPROM.h>
char  strokaI[32] = "                ";// Массив для вывода 1 строки на дисплей
char strokaII[32] = "                ";// Массив для вывода 2 строки на дисплей




  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTE_or_MENU_button(8);   //назначаем кнопке MUTE_or_MENU ножку D8

#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MENUmode 0// Признак включённого режима MENU
unsigned long timerMENU =  millis(); // время до того, как мы выйдем из режима меню в обычный режим.
byte vibor_nomera_punkta_v_MENU=1// выбор режима меню
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
byte MasterVolume EEPROM.read(80); //Значение громкости во время первого включения атмеги, надо читать из еепром. - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
byte  BASSlevelBYTE =EEPROM.read(81);  // значение уровня басов в двоичном виде, для прямого управления tda7442.  
int   BASSlevelDEC 0//значение уровня басов в десятичном виде, Может быть от -14 до +14 (-7-0-+7)
byte  TREBlevelBYTE EEPROM.read(82); // считываем уровень высоких частот из внутренней еепром с 82го адреса.
int   TREBlevelDEC 0//значение уровня пищалок в десятичном виде, Может быть от -14 до +14 (-7-0-+7)
byte EQstate =  EEPROM.read(79); //логическое состояние эквалайзера. 0b11111001 - включен,  0b00000110 eq вЫключён
byte DEFAULT_RESETstate 0// если 1 , то ресет всех значений и еепрома на значеня по умолчанию. 



//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
byte stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;
  for (
bin 0graygray >>= 1)
    
bin ^= gray;
  return 
bin;
}
//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея

//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(250000); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.print("   ver s"); Serial.println(ver);

//MasterVolume = 80;//mute
lcd.noBacklight();

Serial.println("perexodim k osnovnoy programme ");
lcd.backlight();
if (
MasterVolume == 255) {EEPROM.write(80,24); MasterVolume 24;} //если считанное значение громкости_при_включении за рамками диапазона (0-80), то берём среднее значение 24 и пишем его в еепром по адресу 80 (0x80)
if (BASSlevelBYTE == 255) {EEPROM.write(81,0b00011111);} //если считанное значение уровня басов за рамками диапазона, то пишем туда значение 0b00011111 ( в двоичной системе счисления - 8 байт)(0dB)
if (TREBlevelBYTE == 255) {EEPROM.write(82,0b11111110);} //если считанное значение уровня верхов за рамками диапазона,0b11111110 ( в двоичной системе счисления - 8 байт)(+0dB)
if (EQstate == 255) {EEPROM.write(79,0b11111001);} //  = EQ_ON
/*
 * 
EEPROM.write(81,0b00011111); BASSlevelBYTE = 0b00011111; //по умолчанию басы
EEPROM.write(82,0b11111110); TREBlevelBYTE = 0b11111110; //по умолчанию пищалки
EEPROM.write(79,0b11111001); EQstate = 0b11111001;     //по умолчанию EQ ON
EEPROM.write(80,24);         MasterVolume = 24;      //по умолчанию громкость
*/
 

//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0){Serial.print ("I tak VOLUME MAX (0dB)  "); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB");  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){Serial.print ("I tak VOLUME MIN (80dB-MUTE)   ");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); digitalWrite(13,!digitalRead(13)); }// если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void IntToChar(int numchar *text)//функция, возвращающая число в текстовый вид 000 111
{
  
//text[0] = (num/100) + '0'; // первое значение _00
  
text[1] = ((num/10)%10) + '0';// второе значение __0
  
text[2] = (num%10) + '0'// третее значение ___
}
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


void printDISPLAY(unsigned long interval){
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
                                     
prevTime=millis();
                                     if (
13,1){digitalWrite(13,0);} 
                                     if (
MENUmode == 0) {
                                                        
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
                                                        
lcd.setCursor(00);
                                                        
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value вывод полоски громкости в первой строке
                                                        //-------------------2 строка---------------------------------
                                                        
lcd.setCursor(01); //2строка 0символ 
                                                        
if (MasterVolume==80)
                                                              {
lcd.print      ("      MUTE      ");  }
                                                              else  {
lcd.print("VOLUME     -");  }
                                                        
lcd.print(MasterVolume);
                                                        
lcd.print("dB ");
                                                        
                                                       }
                                      else 
//if (MENUmode == 1)
                                                        
{
                                                          
                                
//конвертация басов из байт в десятичную_____________________________________________________________________________________
                                
if (24<=BASSlevelBYTE && BASSlevelBYTE<=31) {  BASSlevelDEC = (map (BASSlevelBYTE30,24,   17))*2; }// положительное значение
                                
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) {  BASSlevelDEC = (map (BASSlevelBYTE16,22, -7, -1))*2; }// отрицательное значение
                                
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC 0;}
                                
//конвертация верхов из байт в десятичную
                                
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) {  TREBlevelDEC = (map (TREBlevelBYTE238,142,   17))*2; }// положительное значение
                                
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126)  {  TREBlevelDEC = (map (TREBlevelBYTE14,110, -7, -1))*2; }// отрицательное значение
                                
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC 0;}
                                
//_____________________________________________________________________________________________________________________________

                              

                                                          
lcd.setCursor(00);
                                                          
lcd.print(strokaI);
                                                          
                                                          
lcd.setCursor(01); //2строка 0символ 
                                                          
lcd.print(strokaII);
    
                                                        }

                                  
                              }
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER (){
  
    static 
uint8_t oldValue 0;
    
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);
    if (
stepENC >0){if((millis() - prevTimeE >120)){if (stepENC>6){stepENC=6;}/*НАДО ОбНУЛЯТЬРАЗ В 420*/ if((millis() - prevTimeE 130)) {prevTimeE millis(); stepENC--;}}} //это обнуляет "ускоение" энкодера, суммарно около секунды
                        
                    

  
if (value == 0// Энкодер вращается
      

         
    if (
oldValue == 3) { /*  вращение влево // увеличиваем громкость, не более чем до 80*/
                                            
timerMENU millis();
                      if (
MENUmode == 0)  {   // то регулируем громкость     
                                                                
if (MasterVolume == 80){stepENC 1;} else {stepENC++;}   /* Serial.println(stepENC);*/
                                                                
if( stepENC ) {stepVOLamount 1;}
                                                                else  if( 
stepENC 10 ) {stepVOLamount 4;} else  if( stepENC 14 ) {stepVOLamount 6;} else  if( stepENC 24 ) {stepVOLamount 8;}
                                                                
prevTimeE millis();
                                                                if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                                }
                                             if (
MENUmode == 1) {//то лазим по меню
                                                                
vibor_nomera_punkta_v_MENU--;
                                                                 
                                                                }
                                             if (
MENUmode == 2) {//настройка громкости при включении и потом запись в еепром (80)
                                                                
if  (MasterVolume<=79){MasterVolume++;}
                                                                }                                                                 
                                               if (
MENUmode == 3)  //настройка басов
                                                                

                                                                  if (
BASSlevelBYTE==31 ){BASSlevelBYTE 23;} 
                                                                  if (
BASSlevelBYTE<=23 && BASSlevelBYTE>16){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                                                                  if (
BASSlevelBYTE>=24 && BASSlevelBYTE<=31){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                                } 
                                
                                                                  
                                               if (
MENUmode == 4)  //настройка пищалок
                                                                

                                                                  if (
TREBlevelBYTE==254 ){TREBlevelBYTE 126;} 
                                                                  if (
TREBlevelBYTE<=126 && TREBlevelBYTE>14){TREBlevelBYTE TREBlevelBYTE-16;}
                                                                  if (
TREBlevelBYTE>=142 && TREBlevelBYTE<=254){TREBlevelBYTE TREBlevelBYTE+16;}
                                } 
                         if (
MENUmode == 5// EQstate
                                                                
{EQstate =0b00000110//0b00000110 eq вЫключён
                                                                
}
                         if (
MENUmode == 6)
                                {
                                  
DEFAULT_RESETstate 1;
                                }
                                                      
                       }

                       
    else if (
oldValue == 1// вправо
    

                      
timerMENU millis();
                    if (
MENUmode == 0)  // то регулируем громкость  
                              

                              if (
MasterVolume == 0){stepENC 1;} else {stepENC++;}    /*Serial.println(stepENC);*/
                              
if( stepENC ) {stepVOLamount 1;}
                              else  if( 
stepENC ) {stepVOLamount 4;}    else  if( stepENC 12 ) {stepVOLamount 6;}  else  if( stepENC 18 ) {stepVOLamount 10;}
                              
prevTimeE millis();
                              if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                              
}
                    if (
MENUmode == 1//выбор в корне основного меню
                                

                                   
vibor_nomera_punkta_v_MENU++;  
                                  } 
                    if (
MENUmode == 2//настройка громкости при включении и потом запись в еепром (80)
                                
{
                                 if  (
MasterVolume>=1){MasterVolume--;}
                                } 


                    if (
MENUmode == 3)    {//настройка басов
                                  
if (BASSlevelBYTE>24 && BASSlevelBYTE<31){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                                  if (
BASSlevelBYTE==23 ){BASSlevelBYTE 30;}  
                                  if (
BASSlevelBYTE==31 ){BASSlevelBYTE 30;}                              
                                  if (
BASSlevelBYTE<=23 && BASSlevelBYTE>=16){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                                }
                    if (
MENUmode == 4//настройка пищалок
                              
{
                                if (
TREBlevelBYTE>142 && TREBlevelBYTE<254){TREBlevelBYTE TREBlevelBYTE-16;}
                                if (
TREBlevelBYTE==126 ){TREBlevelBYTE 238;}  
                                if (
TREBlevelBYTE==254 ){TREBlevelBYTE 238;}                              
                                if (
TREBlevelBYTE<=126 && TREBlevelBYTE>=14){TREBlevelBYTE TREBlevelBYTE+16;}
                              }
                    if (
MENUmode == 5// EQstate
                                  
{
                                  
EQstate =0b11111001//0b00000001 eq включён - есть подмешивание каналов ??? 0b11111001
                                  
}  
                    if (
MENUmode == 6){DEFAULT_RESETstate 2;}   
    }
     
      }

 
  
oldValue value;

 
  
}

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
 

 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTE_or_MENU_button.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTE_or_MENU_button.click_down){timerMENU millis();}
 if (
MENUmode == 0)
                 {
                 if (
MUTE_or_MENU_button.click_down)//если кнопка MUTE однократно нажата
                        

                        if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
                        
MuteActiv = (!MuteActiv); 
                        if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
                        if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                        
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
                        }
                 }    
 
 
 
 if (
MENUmode == 1)//зашли в режим меню и настроек  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
{
                        if(
vibor_nomera_punkta_v_MENU<=0)   { vibor_nomera_punkta_v_MENU=6;}          //ограничим количество режимов 
                        
if(vibor_nomera_punkta_v_MENU>=7)   { vibor_nomera_punkta_v_MENU=1;}          //переключать режимы будем циклично
    
                        
sprintf(strokaI,"-- SETUP MODE --"); //запись в буфер текста и значений
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 1){sprintf(strokaII,"<   exit setup  ");  }    
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==1){MENUmode 0;}//если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_1( EXIT setup), то => закрыть меню и выйти в обычный режим
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 2){//настройка громкости при первом включении (с записью в еепром 80 адрес)
                                                             
sprintfstrokaI,"SETUP volume on ");
                                                             
sprintf(strokaII,"power ON   -__dB") ; IntToChar(EEPROM.read(80), &strokaII[11]);
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==2){MENUmode 2MasterVolume EEPROM.read(80);}// //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_2 (setup vol on Pon) , то надо бы включить подменю выбора значения 0-80 для записи в еепром атмеги
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 3)//SETUP bass - настройка басов
                                                            
{
                                                            if (
EQstate == 0b11111001) {sprintfstrokaI,"SETUP BASS  eqON") ;}
                                                            if (
EQstate == 0b00000110) {sprintfstrokaI,"SETUP BASS eqOFF") ;}
                                                            if (
BASSlevelDEC >=0)      {sprintf(strokaII,"now bass=  +__dB") ;IntToChar(BASSlevelDEC , &strokaII[11]);} 
                                                            else                       {
sprintf(strokaII,"now bass=  -__dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                                  
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==3){MENUmode 3; }
                      
            
          
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 5// выбор включен ли эквалайзер 
                                                            
{
                                                            
sprintfstrokaI,"SETUP  EQ state "); 
                                                            if (
EQstate == 0b11111001) {sprintf(strokaII,"   EQ  ON       ") ;}
                                                            else              {
sprintf(strokaII,"   EQ  OFF      ") ;}                  
                                                            } 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==5){MENUmode 5; }
          
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
              
            
if (vibor_nomera_punkta_v_MENU == 4// настройка пищалок
                                                            
{
                              if (
EQstate == 0b11111001) {sprintfstrokaI,"SETUP TREB  eqON") ;}
                                                            if (
EQstate == 0b00000110) {sprintfstrokaI,"SETUP TREB eqOFF") ;}
                                  if (
TREBlevelDEC >=0){sprintf(strokaII,"now treb=  +__dB") ;IntToChar(TREBlevelDEC , &strokaII[11]);}   
                                                                      else             {
sprintf(strokaII,"now treb=  -__dB") ;IntToChar(((~TREBlevelDEC)+1), &strokaII[11]);}  
                                                            } 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==4){MENUmode 4; }
            
      if (
vibor_nomera_punkta_v_MENU == 6// сброс на начальные установки
                        
{
                          
sprintfstrokaI,"RESET ALL PARAMS") ;
                          
sprintf(strokaII,"   TO DEFAULT   ") ;
                        } 
            if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==6){MENUmode 6; }
            
            
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                   
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
                                 
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                                                    
sprintf(  strokaI,"select volume on");
                                                    
sprintfstrokaII,"power ON   -__dB");  IntToChar(MasterVolume, &strokaII[11]);
                                                    
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(80)==MasterVolume){ } else { EEPROM.write(80,MasterVolume); MENUmode 1; }
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                 
if (MENUmode == 3)//SETUP bass - настройка басов ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                          
                          if (
EQstate == 0b11111001) {sprintfstrokaI,"set bass    eqON") ;}
                                                    if (
EQstate == 0b00000110) {sprintfstrokaI,"set bass   eqOFF") ;}
                              if (
BASSlevelDEC >=0){sprintf(strokaII,"level      +__dB") ;IntToChar(BASSlevelDEC, &strokaII[11]);} 
                                          else {
sprintf(strokaII,"level      -__dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(81)==BASSlevelBYTE){ } else { MENUmode 1;EEPROM.write(81,BASSlevelBYTE);}
                                                                                       }
                                                   }
                if (
MENUmode == 5)  // выбор включен ли эквалайзер 
                      
{
                      
sprintf                           (  strokaI,"select EQ state ");  
                      if (
EQstate == 0b11111001) {sprintf(strokaII,"EQ now is ON    ") ;}
                      else                       {
sprintf(strokaII,"EQ now is OFF   ") ;}
                      if (
MUTE_or_MENU_button.click_down
                              { if (
EEPROM.read(79) == EQstate) {} else { MENUmode 1;EEPROM.write(79,EQstate);}
                              }
                          
                    
                      }
                if (
MENUmode == 4)// настройка пищалок
                        
{
                         
                            
                          if (
EQstate == 0b11111001) {sprintfstrokaI,"set treb    eqON") ;}
                                                    if (
EQstate == 0b00000110) {sprintfstrokaI,"set treb   eqOFF") ;}
                              if (
TREBlevelDEC >=0){sprintf(strokaII,"level      +__dB") ;IntToChar(TREBlevelDEC, &strokaII[11]);} 
                                          else {
sprintf(strokaII,"level      -__dB") ;IntToChar(((~TREBlevelDEC)+1), &strokaII[11]);}
                                                    if (
MUTE_or_MENU_button.click_down)  
                                                                                       { if (
EEPROM.read(82)==TREBlevelBYTE){ } else { MENUmode 1;EEPROM.write(82,TREBlevelBYTE);}
                                                                                       }
                        }   
        if (
MENUmode == 6)// сброс на начальные установки
                  
{
                    
sprintfstrokaI,                           "reset ALL       ") ;
                    if (
DEFAULT_RESETstate==1){sprintf(strokaII,"params     <NO> ") ;  if (MUTE_or_MENU_button.click_down) {MENUmode 0;}}
                    if (
DEFAULT_RESETstate==2){
                                   
sprintf(strokaII,"params    <YES> ") ; 
                                   if (
MUTE_or_MENU_button.click_down
                                                  {
                                                  
DEFAULT_RESETstate=0
                                                  
EEPROM.write(81,0b00011111); BASSlevelBYTE 0b00011111//по умолчанию басы
                                                  
EEPROM.write(82,0b11111110); TREBlevelBYTE 0b11111110//по умолчанию пищалки
                                                  
EEPROM.write(79,0b11111001); EQstate 0b11111001;     //по умолчанию EQ ON
                                                  
EEPROM.write(80,24);         MasterVolume 24;      //по умолчанию громкость
                                                  
MENUmode 0;
                                                  } 
                                  }
                    
                        
                  }
            
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~            
           
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//======================================================обработка MENU===================================================================================================
//===========================================================================================================================================================================

if (MUTE_or_MENU_button.retention) {                                           // если удерживаем нажатой кнопку MUTE  
                            //Serial.println("MUTE_or_MENU_button = uderjanie");
                            
MENUmode = (!MENUmode); //инвертируем признак того, что мы в меню 
              //MENUmode = 2 - есть и такая строка, тогда MENUmode = (!MENUmode); должно работать некорректно
                            
timerMENU millis();
                            
MuteActiv = (!MuteActiv); //возвращаем состояние MUTE на предидущее ( потому что нажав кнопку меню мы сначела жмём MUTE, а только потом активируется меню)
                            
if (MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }  // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
                            
if (MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                          }            


if( 
millis() - timerMENU >= 10000 && MENUmode >= 1// в режиме меню ждем 10 сек
                                   
{
                                    
MENUmode 0;
                  
DEFAULT_RESETstate=0
                                   }
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================



/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1EQstate);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3BASSlevelBYTE);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(4TREBlevelBYTE);  //BXXX0100  0b01111110 TREBLE (0dB)
//tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
//tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
// регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE  
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  
tda7442(6,  MasterVolume);
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(96/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





 
  
  
  
  
 







//BASSconvertBYTEtoDEC;
printDISPLAY(120); // выводим на дисплей раз в 100( запуская фушкцию)
 

//Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print(" dB    ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");
                                                            //Serial.println(curr_bit_data,BIN); - тогда число выведется в двоичном виде
//Serial.print("TREBlevel DEC = "); Serial.print(TREBlevelDEC); Serial.print(" dB    ");  Serial.print("TREBlevelBYTE = "); Serial.print(TREBlevelBYTE,BIN); Serial.println(" ");

}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 


oleg707 26.11.2016 02:55

ребят, вопрос. Кому нить вообще надо выбор источника ( типа IN1 - IN4) в этой штуке ?
А то немного лениво кодить:blush:

demtro 26.11.2016 22:48

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

oleg707 26.11.2016 23:08

Цитата:

Сообщение от demtro (Сообщение 375459)
Мне) я вообще очень слежу за этой темой, планирую дальше переделывать свой проект с использованием твоей этой разработки

тогда тут другой вопрос возникнет, функций микшера захочется :spiteful:

demtro 26.11.2016 23:17

думаю нет, планирую радио со звукойвухой объединить через сумматор, а переключение источников надо для громкой связи, чтоб лишние звуки полностью отключались

oleg707 27.11.2016 00:22

добавил выбор источника IN1 - IN4 с записью в еепром. По умолчанию стоит IN1
 
PHP код:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442D
int ver 89;
// с подавлением дребезга кнопок 
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера) 
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода   при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) -  басы и пищалки
// Добавил меню сброса на настройки по умолчанию ( заодно восстанавливает неправильно записанный еепром на нужные значения), работает только один раз, потом надо передёрнуть питание. 
// добавил выбор источника IN1 - IN4 с записью в еепром. По умолчанию стоит IN1 (3 и 4 контакты TDA7442D). 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
// Bitwise NOT (~) https://www.arduino.cc/en/Reference/BitwiseXorNot
// abs() Возвращает модуль числа. http://arduino.ru/Reference/Abs
#include <Arduino.h>
#include <Wire.h> /*добавление библиотеки I2C шины*/
#include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A014561611121314POSITIVE);  // для newE  описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347 
#include <EEPROM.h>
char  strokaI[32] = "                ";// Массив для вывода 1 строки на дисплей
char strokaII[32] = "                ";// Массив для вывода 2 строки на дисплей




  


class BUTTON {
public:
//============================================================================================
// константы настроек класса.
static const byte bounce_            =   50// длительность отслеживания дребезга.
static const byte doubleclick_       =  250// длительность отслеживания двойного нажатия.
static const unsigned long timer_    5000// длительность отслеживания неактивности.
static const unsigned int retention_ 500// длительность отслеживания нажатия и удержания.
//============================================================================================
unsigned long start// старт отсчёта времени.
boolean p;           // состояние пина кнопки.
boolean s;           // программное состояние кнопки.
boolean b;           // состояние таймера фильтра дребезга.
byte    c;           // переменная счётчика двойного нажатия.
boolean t;           // состояние таймера неактивности.
boolean r;           // состояние таймера нажатия и удержания.
//============================================================
boolean click_down;  // событие нажатия.
boolean click_up;    // событие отпускания.
boolean doubleclick// событие двойного нажатия.
boolean timer;       // событие неактивности.
boolean retention;   // событие нажатия и удержания.
//============================================================
byte _pb;
//============================================================
BUTTON(byte pb) {
_pb pb;
pinMode(_pbINPUT);
digitalWrite(_pb1);
//===================
start millis();
p     digitalRead(_pb);
// p     = !digitalRead(_pb); // отключить тихий старт.
s     p;
b     0;
c     0;
t     0;
r     0;
//==============
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============
}

void read() {
//==============================================================================
boolean np digitalRead(_pb); // текущее состояние пина кнопки.
unsigned long stop millis(); // стоп отсчёта времени.
//==============================================================================
click_down  0;
click_up    0;
doubleclick 0;
timer       0;
retention   0;
//==============================================================================
if (np != p) {npclick(); start stop111;} // состояние цифрового пина изменилось.
//==============================================================================
if (!= 0          ) {if (stop start bounce_     ) {0click();      }} // фильтр дребезга.
if (!= 0          ) {if (stop start doubleclick_) {0;               }} // обнуление счётчика двойного клика.
if (!= && == 1) {if (stop start timer_      ) {0timer     1;}} // неактивность.
if (!= && == 0) {if (stop start retention_  ) {0retention 1;}} // нажатие и удержание.
//==============================================================================
}

void click() {                       // нажатие, отпускание, двойное нажатие.
if (== && != p) {p;
if (
== 0) {click_down 1; ++c; if (== 2) {0doubleclick 1;}}
if (
== 1) {click_up   1;}
}
}

};
// конец class BUTTON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//конец кода для чтения состояний кнопок ~
//=====================================================================================================================================================================================================================================================










//Подтяжку для кнопок на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм

//                 ТУТ НАЗНАЧАЕМ ИМЕНА НАШИХ КНОПОК И К КАКИМ ПИНАМ ОНИ ПОДКЛЮЧЕНЫ           (также сюда пишем имена переменных, то, что обычно пишется ДО void setup().
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//BUTTON REDbutton(31);     //назначаем красной кнопке ножку 31. То есть один конец конпки подключён на пин 31 ардуины меги, а второй  конец конпки подключён на массу (GND)     Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
//BUTTON BLACKbutton (33);  //назначаем красной кнопке ножку 33. То есть один конец конпки подключён на пин 33 ардуины меги, а второй  конец конпки подключён на массу (GND)    Подтяжку на +5В делать не надо,  код для чтения состояний кнопок включает внутренний подтягивающий резистор на 20кОм
BUTTON VOLUPbutton(6);   //назначаем кнопке ГРОМКОСТИ++ ножку D6
BUTTON VOLDNbutton(7);   //назначаем кнопке ГРОМКОСТИ-- ножку D7
BUTTON MUTE_or_MENU_button(8);   //назначаем кнопке MUTE_or_MENU ножку D8

#define  VOLUME_INTERVAL  100UL  // интервал(время) между изменениями уровня громкости (0,05 секунд)
boolean Vupupup 0//переменная, показывающая надо ли увеличивать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
boolean Vdndndn 0//переменная, показывающая надо ли уменьшать громкость раз в #define  VOLUME_INTERVAL  100UL (0,1Сек)
byte USCORENIE 0//переменная, ускорение изменения громкости при удержании кнопок VOL+ и VOL-
boolean MuteActiv 0// Признак включённого режима MUTE (временное отключение громкости)
byte MENUmode 0// Признак включённого режима MENU
unsigned long timerMENU =  millis(); // время до того, как мы выйдем из режима меню в обычный режим.
byte vibor_nomera_punkta_v_MENU=1// выбор режима меню
byte MasterVolumeDoMUTE 80//Значение грмкости во время того, как включаем MUTE
byte MasterVolume EEPROM.read(80); //Значение громкости во время первого включения атмеги, надо читать из еепром. - переменная, хранящая в себе громкость выходного звука, 0 - макс громкость, 79- минимальная, 80-255 MUTE http://arduino.ru/Reference/Byte Тип данных byte 8-ми битное беззнаковое целое число, Если DEC - в диапазоне 0..255
byte  BASSlevelBYTE =EEPROM.read(81);  // значение уровня басов в двоичном виде, для прямого управления tda7442.  
int   BASSlevelDEC 0//значение уровня басов в десятичном виде, Может быть от -14 до +14 (-7-0-+7)
byte  TREBlevelBYTE EEPROM.read(82); // считываем уровень высоких частот из внутренней еепром с 82го адреса.
int   TREBlevelDEC 0//значение уровня пищалок в десятичном виде, Может быть от -14 до +14 (-7-0-+7)
byte EQstate =  EEPROM.read(79); //логическое состояние эквалайзера. 0b11111001 - включен,  0b00000110 eq вЫключён
byte DEFAULT_RESETstate 0// если 1 , то ресет всех значений и еепрома на значеня по умолчанию. 
byte selectINPUT EEPROM.read(78);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2) поскольку физические номера входов ( по даташиту) и программные различаются, для облегчения кода придётся  поменять номера входов



//====================================================================================
//для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

byte stepVOLamount 0// шаг изменения громкости энкодером. Логика меняется в строках 310
byte stepENC 0// шаг изменения громкости энкодером в режиме ускорения (постоянное вращение)

unsigned long currentTimeVoumeControl;
unsigned long loopTimeVoumeControl;
unsigned long prevTimeE millis(); // время когда последний раз переключали энкодер

enum {ENC_PIN1 9ENC_PIN2 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
  
unsigned bin;
  for (
bin 0graygray >>= 1)
    
bin ^= gray;
  return 
bin;
}
//  grayValue - Значение Грея
//  value     - Преобразованное значение Грея
//  oldValue  - Старое преобразованное значение Грея

//конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
//====================================================================================
//=====================================================================================================================================================================================================================================================





 
void setup()    
 { 
Serial.begin(250000); // ком порт     
pinMode(13OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)        
Wire.begin(); // включение библиотеки I2C шины 
lcd.begin(162);//initialize the lcd newE

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN11);       // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2INPUT);
digitalWrite(ENC_PIN21);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
Serial.println("   S E T U P  ok   ");
Serial.print("   ver s"); Serial.println(ver);
lcd.noBacklight();
Serial.println("perexodim k osnovnoy programme ");
lcd.backlight();
if (
MasterVolume == 255) {EEPROM.write(80,24); MasterVolume 24;} //если считанное значение громкости_при_включении за рамками диапазона (0-80), то берём среднее значение 24 и пишем его в еепром по адресу 80 (0x80)
if (BASSlevelBYTE == 255) {EEPROM.write(81,0b00011111); BASSlevelBYTE 0b00011111; } //если считанное значение уровня басов за рамками диапазона, то пишем туда значение 0b00011111 ( в двоичной системе счисления - 8 байт)(0dB)
if (TREBlevelBYTE == 255) {EEPROM.write(82,0b11111110); TREBlevelBYTE 0b11111110; } //если считанное значение уровня верхов за рамками диапазона,0b11111110 ( в двоичной системе счисления - 8 байт)(+0dB)
if (EQstate == 255) {EEPROM.write(79,0b11111001); EQstate 0b11111001;} //  = EQ_ON
if (selectINPUT ==255 ){EEPROM.write(78,6); selectINPUT 6;} // AUX SELECT

 

//=====================================================================================================================================================================================================================================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
  static 
unsigned long prevTime 0// время когда последний раз увеличивали или уменьшали громкость
  
if(millis() - prevTime interval-USCORENIE) {
                                       
prevTime millis();  // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
                                       
if (Vupupup == && Vdndndn == 0) {if(interval-USCORENIE>8+20){USCORENIE USCORENIE 8;} if (MasterVolume==0)  { } else (MasterVolume--);  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вверх, то увеличиваем громкость на один шаг (1dB) с периодичностью interval.
                                       
if (Vdndndn == 1)                 {if(interval-USCORENIE>10+20){USCORENIE USCORENIE 10;} if (MasterVolume==80){} else (MasterVolume++);  digitalWrite(13,!digitalRead(13)); } // если зажата громкость вниз, то уменьшаем громкость на один шаг (1dB) с периодичностью interval.
  
  
                                      
}
}
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



/* функция void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void tda7442(byte subaddressbyte data)  //Вызов данных tda7442

Wire.beginTransmission(0x40); /*СТАРТ (посылается бит старта по I2C шине) и Адрес микросхемы  tda7442  (посылается 7бит адреса по I2C шине и еще один нолик)*/
/*после beginTransmission дуина ждёт по линии ДАТА ответа от tda7442 ( присаживание линии на землю во время 8 бита синхросигнала)и потом передает*/
Wire.write(subaddress);       //Подадрес команды 
Wire.write(data);             //Команда 
Wire.endTransmission();       //СТОП 
/* То есть когда есть связь с tda7442, то функция (void tda7442) посылает сначала первый пакет tda7442(0), потом данные этого пакета 0b01000000
   Потом функция (void tda7442) посылает  второй пакет tda7442(1), потом данные этого пакета 0b00000110
   и так до конца: tda7442(9, 0b00000110); */
}
/*конец void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void IntToChar(int numchar *text)//функция, возвращающая число в текстовый вид 000 111
{
  
//text[0] = (num/100) + '0'; // первое значение _00 - эта строчка нужна для 3хзначного числа.
  
text[1] = ((num/10)%10) + '0';// второе значение __0
  
text[2] = (num%10) + '0'// третее значение ___
}
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


void printDISPLAY(unsigned long interval//функция вывода информации на дисплей и конвертации басов и высоких частот из байт в десятичную систему.
{
  static 
unsigned long prevTime=0;
  if(
millis()-prevTime>interval){
                                     
prevTime=millis();
                                     if (
13,1){digitalWrite(13,0);} 
                                     if (
MENUmode == 0) {
                                                        
int Mdisp =map(MasterVolume080800);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
                                                        
lcd.setCursor(00);
                                                        
lcd.printHorizontalGraph('v'0Mdisp80); //name of the bar, first  row, current value, max. value вывод полоски громкости в первой строке
                                                        //-------------------2 строка---------------------------------
                                                        
lcd.setCursor(01); //2строка 0символ 
                                                        
if (MasterVolume==80)
                                                              {
lcd.print      ("      MUTE      ");  }
                                                              else  {
lcd.print("VOLUME     -");  }
                                                        
lcd.print(MasterVolume);
                                                        
lcd.print("dB ");
                                                        
                                                       }
                                      else 
//if (MENUmode == 1-6)
                                                        
{
                                                          
//конвертация басов из байт в десятичную_____________________________________________________________________________________
                                                          
if (24<=BASSlevelBYTE && BASSlevelBYTE<=31) {  BASSlevelDEC = (map (BASSlevelBYTE30,24,   17))*2; }// положительное значение
                                                          
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) {  BASSlevelDEC = (map (BASSlevelBYTE16,22, -7, -1))*2; }// отрицательное значение
                                                          
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC 0;}
                                                          
//конвертация верхов из байт в десятичную
                                                          
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) {  TREBlevelDEC = (map (TREBlevelBYTE238,142,   17))*2; }// положительное значение
                                                          
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126)  {  TREBlevelDEC = (map (TREBlevelBYTE14,110, -7, -1))*2; }// отрицательное значение
                                                          
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC 0;}
                                                          
//_____________________________________________________________________________________________________________________________

                                                          
lcd.setCursor(00);
                                                          
lcd.print(strokaI);
                                                          
                                                          
lcd.setCursor(01); //2строка 0символ 
                                                          
lcd.print(strokaII);
                                                        }

                                  
                              }
}



//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================

void ENCODER () //функция обработки энкодера
{
  
    static 
uint8_t oldValue 0;
    
uint8_t grayValue digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), value graydecode(grayValue);
    if (
stepENC >0){if((millis() - prevTimeE >120)){if (stepENC>6){stepENC=6;}/*НАДО ОбНУЛЯТЬРАЗ В 420*/ if((millis() - prevTimeE 130)) {prevTimeE millis(); stepENC--;}}} //это обнуляет "ускоение" энкодера при регулировке громкости, суммарно около секунды
                        
                    

  
if (value == 0// Энкодер вращается
                

                   
                        if (
oldValue == 3)  /*  вращение влево // увеличиваем громкость, не более чем до 80*/
                                          
{
                                                                
timerMENU millis();
                                                                if (
MENUmode == 0)  // то регулируем громкость   
                                                                                    
{     
                                                                                    if (
MasterVolume == 80){stepENC 1;} else {stepENC++;}   /* Serial.println(stepENC);*/
                                                                                    
if( stepENC ) {stepVOLamount 1;}
                                                                                    else  if( 
stepENC 10 ) {stepVOLamount 4;} else  if( stepENC 14 ) {stepVOLamount 6;} else  if( stepENC 24 ) {stepVOLamount 8;}
                                                                                    
prevTimeE millis();
                                                                                    if(
MasterVolume stepVOLamount <= 80) {(MasterVolume += stepVOLamount);}else {MasterVolume 80;}
                                                                                    }
                                                                if (
MENUmode == 1//то лазим по меню
                                                                                    
{
                                                                                    
vibor_nomera_punkta_v_MENU--;
                                                                                    }
                                                                                    
                                                                if (
MENUmode == 2//настройка громкости при включении и потом запись в еепром (80)
                                                                                    
{
                                                                                    if  (
MasterVolume<=79){MasterVolume++;}
                                                                                    }
                                                                                                                                                     
                                                                if (
MENUmode == 3)  //настройка басов
                                                                                    

                                                                                      if (
BASSlevelBYTE==31 ){BASSlevelBYTE 23;} 
                                                                                      if (
BASSlevelBYTE<=23 && BASSlevelBYTE>16){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                                                                                      if (
BASSlevelBYTE>=24 && BASSlevelBYTE<=31){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                                                                                     } 
                                                    
                                                                if (
MENUmode == 4)  //настройка пищалок
                                                                                    

                                                                                      if (
TREBlevelBYTE==254 ){TREBlevelBYTE 126;} 
                                                                                      if (
TREBlevelBYTE<=126 && TREBlevelBYTE>14){TREBlevelBYTE TREBlevelBYTE-16;}
                                                                                      if (
TREBlevelBYTE>=142 && TREBlevelBYTE<=254){TREBlevelBYTE TREBlevelBYTE+16;}
                                                                                    } 
                                                                if (
MENUmode == 5// EQstate
                                                                                    
{
                                                                                      
EQstate =0b00000110//0b00000110 eq вЫключён
                                                                                    
}
                                                                if (
MENUmode == 6// РЕСЕТ настроек
                                                                                    
{
                                                                                      
DEFAULT_RESETstate 1;
                                                                                    }
                                if (
MENUmode == 7// выбор источника
                                                                                    
{
                                                                                      if (
selectINPUT<6) {selectINPUT selectINPUT+2;}
                                                                                    }
                                          
                                                                          
                                           }
// конец вращение влево
                    
                                           
                        
else if (oldValue == 1//  вращение вправо
                                                                

                                                                
timerMENU millis();
                                                                if (
MENUmode == 0)  // то регулируем громкость  
                                                                                   

                                                                                   if (
MasterVolume == 0){stepENC 1;} else {stepENC++;}    /*Serial.println(stepENC);*/
                                                                                   
if( stepENC ) {stepVOLamount 1;}
                                                                                   else  if( 
stepENC ) {stepVOLamount 4;}    else  if( stepENC 12 ) {stepVOLamount 6;}  else  if( stepENC 18 ) {stepVOLamount 10;}
                                                                                   
prevTimeE millis();
                                                                                   if(
MasterVolume stepVOLamount >= 0){ (MasterVolume -= stepVOLamount);} else{ MasterVolume 0/*Serial.println(MasterVolume);*/ }  /* уменьшаем громкость, но не ниже 0*/
                                                                                   
}
                                                                if (
MENUmode == 1//выбор в корне основного меню
                                                                                   

                                                                                   
vibor_nomera_punkta_v_MENU++;  
                                                                                   } 
                                                                if (
MENUmode == 2//настройка громкости при включении и потом запись в еепром (80)
                                                                                  
{
                                                                                   if  (
MasterVolume>=1){MasterVolume--;}
                                                                                  } 
                                            
                                            
                                                                if (
MENUmode == 3)    //настройка басов
                                                                                  
{
                                                                                  if (
BASSlevelBYTE>24 && BASSlevelBYTE<31){BASSlevelBYTE BASSlevelBYTE-0b00000001;}
                                                                                  if (
BASSlevelBYTE==23 ){BASSlevelBYTE 30;}  
                                                                                  if (
BASSlevelBYTE==31 ){BASSlevelBYTE 30;}                              
                                                                                  if (
BASSlevelBYTE<=23 && BASSlevelBYTE>=16){BASSlevelBYTE BASSlevelBYTE+0b00000001;}
                                                                                  }
                                                                if (
MENUmode == 4//настройка пищалок
                                                                                  
{
                                                                                    if (
TREBlevelBYTE>142 && TREBlevelBYTE<254){TREBlevelBYTE TREBlevelBYTE-16;}
                                                                                    if (
TREBlevelBYTE==126 ){TREBlevelBYTE 238;}  
                                                                                    if (
TREBlevelBYTE==254 ){TREBlevelBYTE 238;}                              
                                                                                    if (
TREBlevelBYTE<=126 && TREBlevelBYTE>=14){TREBlevelBYTE TREBlevelBYTE+16;}
                                                                                  }
                                                                if (
MENUmode == 5// EQstate
                                                                                  
{
                                                                                  
EQstate =0b11111001//0b00000001 eq включён - есть подмешивание каналов ??? 0b11111001
                                                                                  
}  
                                                                if (
MENUmode == 6){DEFAULT_RESETstate 2;}   
                                if (
MENUmode == 7// выбор источника
                                                                                    
{
                                                                                      if (
selectINPUT>0) {selectINPUT selectINPUT-2;}
                                                                                    }
                        }
// конец вращение вправо
                         
                
}//конец Энкодер вращается

 
  
oldValue value;

 
  
//конец функции обработки энкодера

//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================


 
void loop() //~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~

 

  
 

 
VOLUPbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
VOLDNbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки громкости 
MUTE_or_MENU_button.read();     // читаем фильтрованное значение СТАТУСА кнопки MUTE

                          /*               Примеры
                           REDbutton.read();      // читаем фильтрованное значение СТАТУСА кнопки
                           BLACKbutton.read();    // читаем фильтрованное значение СТАТУСА кнопки
                           if (REDbutton.click_down) {Serial.println("REDbutton = najata"); }             //нажатие кнопки  
                           if (REDbutton.click_up) {Serial.println("REDbutton = otpustily"); }            //отпускание кнопки 
                           if (REDbutton.doubleclick) {Serial.println("REDbutton = doubleclick"); }       //двойной клик 
                           if (REDbutton.timer) {Serial.println("REDbutton = neaktivnost knopki"); }      //неактивность 
                           if (REDbutton.retention) {Serial.println("REDbutton = uderjanie");}            // нажатие и удержание  
                           */


 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~обработка MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
if (MasterVolume<80&&MuteActiv ==1){MuteActiv 0;}
 if (
MUTE_or_MENU_button.click_down){timerMENU millis();}
 if (
MENUmode == 0)
                   {
                   if (
MUTE_or_MENU_button.click_down)//если кнопка MUTE однократно нажата
                          

                          if (
MuteActiv == 0){MasterVolumeDoMUTE MasterVolume;}
                          
MuteActiv = (!MuteActiv); 
                          if (
MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }
                          if (
MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                          
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print("   MasterVolume = "); Serial.println(MasterVolume);
                          }
                   }    
 
 
 
 if (
MENUmode == 1)//зашли в режим меню и настроек (главное меню)  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                   
{
                        if(
vibor_nomera_punkta_v_MENU<=0)   { vibor_nomera_punkta_v_MENU=7;}          //ограничим количество режимов меню (всего 7 пунктов)
                        
if(vibor_nomera_punkta_v_MENU>=8)   { vibor_nomera_punkta_v_MENU=1;}          //переключать режимы будем циклично
    
                        
sprintf(strokaI,"-- SETUP MODE --"); //запись в буфер текста и значений
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 1){sprintf(strokaII,"<   exit setup  ");  }    
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==1){MENUmode 0;} //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_1( EXIT setup), то => закрыть меню и выйти в обычный режим
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 2){//настройка громкости при первом включении (с записью в еепром 80 адрес)
                                                             
sprintfstrokaI,"SETUP volume on ");
                                                             
sprintf(strokaII,"power ON   -__dB") ; IntToChar(EEPROM.read(80), &strokaII[11]);
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==2){MENUmode 2MasterVolume EEPROM.read(80);}// //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_2 (setup vol on Pon) , то надо бы включить подменю выбора значения 0-80 для записи в еепром атмеги
                      //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 3)//SETUP bass - настройка басов
                                                            
{
                                                            if (
EQstate == 0b11111001) {sprintfstrokaI,"SETUP BASS  eqON") ;}
                                                            if (
EQstate == 0b00000110) {sprintfstrokaI,"SETUP BASS eqOFF") ;}
                                                            if (
BASSlevelDEC >=0)      {sprintf(strokaII,"now bass=  +__dB") ;IntToChar(BASSlevelDEC , &strokaII[11]);} 
                                                            else                       {
sprintf(strokaII,"now bass=  -__dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                                  
                                                            }   
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==3){MENUmode 3; }
                      
            
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                        
if (vibor_nomera_punkta_v_MENU == 5// выбор включен ли эквалайзер 
                                                            
{
                                                            
sprintfstrokaI,"SETUP  EQ state "); 
                                                            if (
EQstate == 0b11111001) {sprintf(strokaII,"   EQ  ON       ") ;}
                                                            else              {
sprintf(strokaII,"   EQ  OFF      ") ;}                  
                                                            } 
                        if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==5){MENUmode 5; }
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
              
                      
if (vibor_nomera_punkta_v_MENU == 4// настройка пищалок
                                                            
{
                                                             if (
EQstate == 0b11111001) {sprintfstrokaI,"SETUP TREB  eqON") ;}
                                                             if (
EQstate == 0b00000110) {sprintfstrokaI,"SETUP TREB eqOFF") ;}
                                                                   if (
TREBlevelDEC >=0){sprintf(strokaII,"now treb=  +__dB") ;IntToChar(TREBlevelDEC , &strokaII[11]);}   
                                                                       else             {
sprintf(strokaII,"now treb=  -__dB") ;IntToChar(((~TREBlevelDEC)+1), &strokaII[11]);}  
                                                            } 
                      if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==4){MENUmode 4; }
                     
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         

                      
if (vibor_nomera_punkta_v_MENU == 6// сброс на начальные установки
                                                            
{
                                                              
sprintfstrokaI,"RESET ALL PARAMS") ;
                                                              
sprintf(strokaII,"   TO DEFAULT   ") ;
                                                            } 
                      if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==6){MENUmode 6; }
                      
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                      
if (vibor_nomera_punkta_v_MENU == 7// ВЫБОР ВХОДА ( IN1 - IN4)
                                                            
{
                                                             
sprintfstrokaI,"INPUT SELECT    ") ;
                                                             
sprintf(strokaII,"        AUX __  ") ; IntToChar( (map (selectINPUT06,   41)) , &strokaII[11]   );  
                                                            }
                      if (
MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==7){MENUmode 7; }
                   
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------         
                   
}//КОНЕЦ режима меню и настроек  ( конец главного меню)  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
// ворая ступень меню ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`                   
                                 
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                                   
{
                                                    
sprintf(  strokaI,"select volume on");
                                                    
sprintfstrokaII,"power ON   -__dB");  IntToChar(MasterVolume, &strokaII[11]);
                                                    
                                                    if (
MUTE_or_MENU_button.click_down){  
                                                                                        if (
EEPROM.read(80)==MasterVolume){ } else { EEPROM.write(80,MasterVolume); MENUmode 1; }
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                 
if (MENUmode == 3)//SETUP bass - настройка басов 
                                                   
{
                                                    if (
EQstate == 0b11111001) {sprintfstrokaI,"set bass    eqON") ;}
                                                    if (
EQstate == 0b00000110) {sprintfstrokaI,"set bass   eqOFF") ;}
                                                          if (
BASSlevelDEC >=0){sprintf(strokaII,"level      +__dB") ;IntToChar(BASSlevelDEC, &strokaII[11]);} 
                                                                          else {
sprintf(strokaII,"level      -__dB") ;IntToChar(((~BASSlevelDEC)+1), &strokaII[11]);}
                                                    if (
MUTE_or_MENU_button.click_down){  
                                                                                        if (
EEPROM.read(81)==BASSlevelBYTE){ } else { MENUmode 1;EEPROM.write(81,BASSlevelBYTE);}
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                 
if (MENUmode == 5)  // выбор включен ли эквалайзер 
                                                   
{
                                                    
sprintf                           (  strokaI,"select EQ state ");  
                                                    if (
EQstate == 0b11111001) {sprintf(strokaII,"EQ now is ON    ") ;}
                                                    else                       {
sprintf(strokaII,"EQ now is OFF   ") ;}
                                                    if (
MUTE_or_MENU_button.click_down) {
                                                                                         if (
EEPROM.read(79) == EQstate) {} else { MENUmode 1;EEPROM.write(79,EQstate);}
                                                                                        }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                 
if (MENUmode == 4)// настройка пищалок
                                                   
{
                                                    if (
EQstate == 0b11111001) {sprintfstrokaI,"set treb    eqON") ;}
                                                    if (
EQstate == 0b00000110) {sprintfstrokaI,"set treb   eqOFF") ;}
                                                          if (
TREBlevelDEC >=0){sprintf(strokaII,"level      +__dB") ;IntToChar(TREBlevelDEC, &strokaII[11]);} 
                                                                          else {
sprintf(strokaII,"level      -__dB") ;IntToChar(((~TREBlevelDEC)+1), &strokaII[11]);}
                                                    if (
MUTE_or_MENU_button.click_down){   
                                                                                        if (
EEPROM.read(82)==TREBlevelBYTE){ } else { MENUmode 1;EEPROM.write(82,TREBlevelBYTE);}
                                                                                       }
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~    
                                 
if (MENUmode == 6)// сброс на начальные установки
                                                   
{
                                                      
sprintfstrokaI,                           "reset ALL       ") ;
                                                      if (
DEFAULT_RESETstate==1){sprintf(strokaII,"params     <NO> ") ;  if (MUTE_or_MENU_button.click_down) {MENUmode 0;}}
                                                      if (
DEFAULT_RESETstate==2){sprintf(strokaII,"params    <YES> ") ;  if (MUTE_or_MENU_button.click_down//если выбрали в меню сброс на начальные установки, то 
                                                                                                                                                            
{
                                                                                                                                                            
DEFAULT_RESETstate=0// обнуляем переменную сброса ( сбросить или НЕ сбросить можно только один раз, потом надо передёргивать питание атмеги)
                                                                                                                                                            
EEPROM.write(81,0b00011111); BASSlevelBYTE 0b00011111//по умолчанию басы
                                                                                                                                                            
EEPROM.write(82,0b11111110); TREBlevelBYTE 0b11111110//по умолчанию пищалки
                                                                                                                                                            
EEPROM.write(79,0b11111001); EQstate 0b11111001;     //по умолчанию статус EQ  = EQ ON
                                                                                                                                                            
EEPROM.write(80,24);         MasterVolume 24;      //по умолчанию громкость при включении
                                                                              
EEPROM.write(78,6); // //по умолчанию выбор входа AUX
                                                                                                                                                            
MENUmode 0// вышли в корень меню. 
                                                                                                                                                            

                                                                    }
                                                      
                                                          
                                                   }
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
                                  
if (MENUmode == 7)  // // ВЫБОР ВХОДА ( IN1 - IN4)
                                                   
{
                                                    
sprintf  strokaI,"select AUX      ");  
                                                    
//sprintf  (strokaII,"                ") ;IntToChar(selectINPUT, &strokaII[11]);} //map (selectINPUT, 0, 6,   1, 4); 
                          
sprintf  (strokaII,"                ") ;IntToChar((map (selectINPUT06,   41)), &strokaII[11]);} //map (selectINPUT, 0, 6,   1, 4); 
                                                    
if (MUTE_or_MENU_button.click_down) {
                                                                                         if (
EEPROM.read(78) == selectINPUT) {} else { MENUmode 1;EEPROM.write(78,selectINPUT);}
                                                                                        }             
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~            
           
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~конец обработки MUTE_or_MENU_button~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

//===========================================================================================================================================================================
//======================================================обработка MENU===================================================================================================
//===========================================================================================================================================================================

if (MUTE_or_MENU_button.retention) {                                           // если удерживаем нажатой кнопку MUTE  
                            //Serial.println("MUTE_or_MENU_button = uderjanie");
                            
MENUmode = (!MENUmode); //инвертируем признак того, что мы в меню //MENUmode = 2 - есть и такая строка, тогда MENUmode = (!MENUmode); должно работать некорректно. НО работает так, как надо
                            
timerMENU millis(); 
                            
MuteActiv = (!MuteActiv); //возвращаем состояние MUTE на предидущее ( потому что нажав кнопку меню мы сначела жмём MUTE, а только потом активируется меню)
                            
if (MuteActiv == 1){ MasterVolumeDoMUTE MasterVolumeMasterVolume=80; }  // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
                            
if (MuteActiv==) { MasterVolume MasterVolumeDoMUTEMuteActiv 0; }
                          }            


if( 
millis() - timerMENU >= 10000 && MENUmode >= 1// в режиме меню ждем 10 сек
                                   
{
                                    
MENUmode 0;
                                    
DEFAULT_RESETstate=0// обнулили переменную сброса настроек. Теперь настройки сбросить нельзя до перезапуска атмеги
                                   
}
//===========================================================================================================================================================================
//===========================================================================================================================================================================
//===========================================================================================================================================================================



/*~~~~~~~~~~~~~~~~~~~~~~обработка нажатия кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
if (VOLUPbutton.click_down/*если кнопка VOL+ однократно нажата  то ДЕЛАЕМ ШАГ(1 РАЗ): включаем светик, уменьшаем переменную громкости (для увеличения звука)выводим значение громкости в порт.*/
        
{                                                       
           if (
MasterVolume==0){Serial.println ("I tak VOLUME MAX (0dB)"); } else (MasterVolume--);  Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
  if (
VOLDNbutton.click_down/*если кнопка VOL- однократно нажата то ДЕЛАЕМ ШАГ(1 РАЗ): увеличиваем переменную громкости (для уменьшения звука)выводим значение громкости в порт*/
        
{  
           if (
MasterVolume==80){Serial.println ("I tak VOLUME MIN (80dB-MUTE)");}  else (MasterVolume++);    Serial.print("MasterVolume = "); Serial.print(MasterVolume); Serial.println("dB"); // выводим значение громкости в ком порт
           
digitalWrite(13,!digitalRead(13)); 
        }
/*===================================================================================================================*/

/*~~~~~~~~~~~~~~~~~~~~~~обработка удержания кнопок громкости~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (VOLUPbutton.retention==1){Vupupup 1;}                  //если кнопка нажата  и удерживается //надо бы увеличивать громкость по шагам
if (VOLDNbutton.retention==1){Vdndndn 1; }                 //если кнопка нажата  и удержмвается //надо бы уменьшать громкость по шагам
  
if (VOLUPbutton.click_up) { Vupupup 0USCORENIE 0;}   //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
  
if (VOLDNbutton.click_up) { Vdndndn 0USCORENIE 0;}       
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая  ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.   
/*===================================================================================================================*/



/*для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ENCODER(); // опрос энкодера раз в 0 миллисекунду
/*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




/*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

tda7442(00b01000000);  //INPUT ATTENUATION    приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1EQstate);  //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(20b00000011);  //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3BASSlevelBYTE);  //BXXX0011 BASS SELECTION (0dB)-14dB  (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB) 
tda7442(4TREBlevelBYTE);  //BXXX0100  0b01111110 TREBLE (0dB)
tda7442(5,  MasterVolume); //0 - макс громкость, 80-255 - MUTE .  // регулировку громкости можно делать  0dB ~ -79dB в DEC c шагом 1. если (80-255) - то MUTE    //tda7442(5, 0b00000000);  //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER SELECTION = 0dB ~ -79dB) громкость правого канала
tda7442(6,  MasterVolume); //tda7442(6, 0b00000000);  //BXXX0110 SPEAKER ATTENUATION "R" (0dB) громкость левого канала
tda7442(70b00000000);  //BXXX0111 NOT ALLOWED
tda7442(80b00000000);  //BXXX1000 NOT ALLOWED         
tda7442(9selectINPUT/*0b00000110*/);  //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4  2-in3 0-in2 по даташиту)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/






 
  
  
  
  
 








printDISPLAY(120); // выводим на дисплей раз в 120( запуская фушкцию)
 
//для отладки:
//byte digit=10; http://arduino.ru/forum/programmirovanie/hex-bin
//Serial.println(digit); // "Представляем" в десятчной"
//Serial.println(digit,HEX); // "Представляем" в шестднацатеричной"
//Serial.println(digit,BIN); // "Представляем" в двоичной"
//Serial.print("BASSlevel DEC = "); Serial.print(BASSlevelDEC); Serial.print(" dB    ");  Serial.print("BASSlevelBYTE = "); Serial.print(BASSlevelBYTE,BIN); Serial.println(" ");
                                                            //Serial.println(curr_bit_data,BIN); - тогда число выведется в двоичном виде
//Serial.print("TREBlevel DEC = "); Serial.print(TREBlevelDEC); Serial.print(" dB    ");  Serial.print("TREBlevelBYTE = "); Serial.print(TREBlevelBYTE,BIN); Serial.println(" ");

//Serial.print("selectINPUT  = "); Serial.println(selectINPUT);
}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//=====================================================================================================================================================================================================================================================
//__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 



Часовой пояс GMT +4, время: 10:06.

Работает на vBulletin® версия 3.8.4.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot