PDA

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


oleg707
27.09.2016, 13:58
Поскольку уже со всем разобрался и сделал рабочую модель скетч для TDA7442D можно посмотреть здесь (http://pccar.ru/showpost.php?p=375794&postcount=52)

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



ПЕЧАТКА + скетч
45875


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

oleg707
27.09.2016, 23:11
Сделал тестовую печатку.
44888

Запаял железо согласно даташиту и подключил ардуину мегу 2560 (https://duino.ru/arduino-mega-2560-rev3.html)
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)

В скетч заливаю:
#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), то форма красной линии меняется.

Если я загружаю другой скетч, то осциллограмма не меняется:
//Для запуска 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(0, 0b11100000); //Конфигурация входа/выбора источника :Input Configuration / Main Source Selector
tda7719(1, 0b00011111); //2-й выбор источника / Прямой Путь :2nd Source Selector / Direct Path
tda7719(2, 0b00011111); //Смешивание Источников / Смешивание Gain :Mixing Source / Mixing Gain
tda7719(3, 0b00011111); //Контроль смешивания и т.д :Mix Control / Level Meter / DC Offset Detector Config
tda7719(4, 0b00000000); //Soft Mute / Others
tda7719(5, 0b00000000); //Soft Step I
tda7719(6, 0b00000000); //Soft Step II / DC-detector
tda7719(7, 0b10000000); //Громкость :Loudness
tda7719(8, 0b00010000); //Объем / Output Gain :Volume / Output Gain
tda7719(9, 0b01110000); //Treble filter
tda7719(10, 0b01110000); //Middle filter
tda7719(11, 0b01110000); //Bass filter
tda7719(12, 0b01111000); //Настройки Сабвуфер/Средний/Басс :Subwoofer / Middle / Bass
tda7719(13, 0b00010000); //Настройки динамика передний левый :Speaker Attenuator Left Front
tda7719(14, 0b00010000); //Настройки динамика передний правый :Speaker Attenuator Right Front
tda7719(15, 0b00010000); //Настройки динамика задний Левый :Speaker Attenuator Left Rear
tda7719(16, 0b00010000); //Настройки динамика задний правый :Speaker Attenuator Right Front
tda7719(17, 0b00010000); //Настройки сабвуфера Левый :Subwoofer Attenuator Left
tda7719(18, 0b00010000); //Настройки сабвуфера Правый :Subwoofer Attenuator Right

}

void tda7719(int subaddress, int 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


//Для запуска 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(0, 0b01100000); //INPUT ATTENUATION (-16dB )
tda7442(1, 0b00000110); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF)
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, 0b00011111); //BXXX0011 BASS SELECTION (0dB)
tda7442(4, 0b01111110); //BXXX0100 TREBLE (0dB)
tda7442(5, 0b00000000); //BXXX0101 SPEAKER ATTENUATION "L" (0dB)( SPEAKER ATTENUATION = 0dB ~ -79dB)
tda7442(6, 0b00000000); //BXXX0110 SPEAKER ATTENUATION "R" (0dB)
tda7442(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, 0b00000110); //BXXX1001 INPUT MULTIPLEXER


}

void tda7442(int subaddress, int 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);
}

в мониторе ком порта тоже видим реакцию - наши данные в десятичном виде
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
6

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

oleg707
28.09.2016, 00:14
Молодец!!! Хотел написать чтоб попробовал 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
Очень помог yuriy m:yes2:
Адрес в мануале явно указан, так что ХЗ.

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

oleg707
28.09.2016, 11:11
Вот теперь я вспомнил,ардуиновская библиотека "су**"в адресе 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/starters/IIC/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!

//Для запуска 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
pinMode(volUPbutton, INPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости +
pinMode(volDNbutton, INPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости -
digitalWrite(volUPbutton, HIGH); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
digitalWrite(volDNbutton, HIGH); // включить подтягивающий резистор

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

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

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(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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER


}

void tda7442(int subaddress, int 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. Никаких плюшек, только громкость!

//Для запуска 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
pinMode(volUPbutton, INPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости +
pinMode(volDNbutton, INPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости -
digitalWrite(volUPbutton, HIGH); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
digitalWrite(volDNbutton, HIGH); // включить подтягивающий резистор

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

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

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(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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4


}

void tda7442(int subaddress, int 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
И тут Остапа понесло...:big: в хорошем смысле:smile1:
Когда я искал хоть какую нибудь инфу, чтобы делать самому с нуля - нифига нету, только на одном сайте печатка+HEX прошивка, так только за деньги ( с платного аккаунта).
А тут простая схема, ардуину любую цеплять, пины только переназначить.
Бери и повторяй.


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

//Для запуска 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
pinMode(volUPbutton, INPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости +
pinMode(volDNbutton, INPUT); //настройка порта ардуины на вход - приём данных от кнопки громкости -
digitalWrite(volUPbutton, HIGH); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
digitalWrite(volDNbutton, HIGH); // включить подтягивающий резистор

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

pinMode(pin_A, INPUT); //настройка пинов энкодера
digitalWrite(pin_A, HIGH); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(pin_B, INPUT);
digitalWrite(pin_B, HIGH);
currentTimeVoumeControl = millis(); //для энкодера
loopTimeVoumeControl = currentTimeVoumeControl;//для энкодера

}
void loop(){

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

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(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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4


}

void tda7442(byte subaddress, byte 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
без энкодера, без ДЕЛАЕВ, с подавлением дребезга кнопок и с увеличением/уменьшением громкости при удержании кнопок.

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
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==1 )//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)

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




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

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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddress, byte 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 == 1 && 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.


}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~








то же самое, но с УСКОРЕНИЕМ при удержании
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
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 = 0; USCORENIE = 0;}
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
//================================================== =================================
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.



if(REDbutton.click_down==1)//если кнопка REDbutton нажата ... (статус нажатой кнопки == 1)
{
digitalWrite(13,0); //выключили диодик
}
if (REDbutton.click_up==1 )//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)

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




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

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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddress, byte 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 == 1 && 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.


}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~







то же самое, но еще и с энкодером.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
Wire.begin(); // включение библиотеки I2C шины
//~~~~~~~~ для энкодера~~~~~~~~~~
pinMode(pin_A, INPUT); //настройка пинов энкодера
digitalWrite(pin_A, HIGH); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(pin_B, INPUT);
digitalWrite(pin_B, HIGH);
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 = 0; USCORENIE = 0;}
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 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==1 )//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)

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




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

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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






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

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddress, byte 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 == 1 && 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

//~~~~~~~~~~~~Описание начнется с 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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(13, OUTPUT); // настройка пина встроенного светодиода на выход (чтоб моргать мог)
Wire.begin(); // включение библиотеки I2C шины
//~~~~~~~~ для энкодера~~~~~~~~~~
pinMode(pin_A, INPUT); //настройка пинов энкодера
digitalWrite(pin_A, HIGH); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(pin_B, INPUT);
digitalWrite(pin_B, HIGH);
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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;}
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 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==1 )//если кнопка REDbutton отпущена .. (статус отпущенной кнопки == 1)

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




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

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, 0b00011111); //BXXX0011 BASS SELECTION (0dB)-14dB
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, 0b00000110); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4
//конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~






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

// void tda7442 вызов управления по I2C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void tda7442(byte subaddress, byte 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 == 1 && 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
Когда с андрюши управлять будишь ?

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

oleg707
06.10.2016, 19:25
Если можно схему подключения выложи.
а чего её выкладывать то, в даташите (http://pdf.eepw.com.cn/720090724/df66ec375f0ec2db9b80724e3949c8b9.pdf)есть.
Когда сделаю рабочую версию с 8 атмегой - тогда печатку и выложу.

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

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

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

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

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

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

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

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

oleg707
18.10.2016, 00:25
45184
схема в диптрейсе - исходники45185

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


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч 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_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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;

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

return bin;
}

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


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





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

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1, INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN1, 1); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2, INPUT);
digitalWrite(ENC_PIN2, 1);
/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 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(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, 0b00011111); //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)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





lcd.backlight();
lcd.setCursor(0, 0);
lcd.print((millis() )/1000); // вывод кол-ва сек работы блока ( 1 строка 1 символ)

lcd.setCursor(7, 0);
/*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(0, 1);
lcd.print("VOLUME -");
lcd.setCursor(8, 1);
lcd.print(MasterVolume);
lcd.setCursor(11, 1);
lcd.print("dB");


















}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________















вот еще для другой библиотеки для I2C дисплея (https://github.com/enjoyneering/LiquidCrystal_I2C)
тут я вывел ползунок текущей громкости на дисплей, приведя его к удобному виду (больше полоска = громче)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч 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_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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;

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

return bin;
}

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


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





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

/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1, INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN1, 1); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2, INPUT);
digitalWrite(ENC_PIN2, 1);
/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 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,!digi talRead(13));}
}
else if (oldValue == 1) { // Влево
if(MasterVolume - stepVOLamount >= 0){ (MasterVolume -= stepVOLamount); Serial.println(MasterVolume);digitalWrite(13,!digi talRead(13)); } /* уменьшаем громкость, но не ниже 0*/
}
}



oldValue = value;


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





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

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, 0b00011111); //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)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/





lcd.backlight();




int Mdisp =map(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map





lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value
lcd.setCursor(0, 0);
//lcd.print((millis() )/1000); // вывод кол-ва сек работы блока ( 1 строка 1 символ)

lcd.setCursor(7, 0);
/*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(0, 1);
lcd.print("VOLUME -");
lcd.setCursor(8, 1);
if (MasterVolume==80){ lcd.print("MUTE");} else {lcd.print(MasterVolume); }
lcd.setCursor(11, 1);
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
Если не трудно в диптрейсе укажите номиналы элементов, какую атмегу используете? Планирую повторить вашу схему с небольшими доработками и добавлением необходимых мне частей

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

oleg707
21.10.2016, 01:24
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч 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_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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia


unsigned graydecode(unsigned gray) {
unsigned bin;

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

return bin;
}

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


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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map





lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value
lcd.setCursor(0, 0);
//lcd.print((millis() )/1000); // вывод кол-ва сек работы блока ( 1 строка 1 символ)

lcd.setCursor(7, 0);

//-------------------2 строка---------------------------------
lcd.setCursor(0, 1);
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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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





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

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, 0b00011111); //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)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/



















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






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

oleg707
24.10.2016, 22:28
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч 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_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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia


unsigned graydecode(unsigned gray) {
unsigned bin;

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

return bin;
}

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


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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map


// lcd.setCursor(0, 0); не надо явно указывать, т.к. отсчет все равно с 0,0
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке

//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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





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

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, 0b00011111); //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)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/



















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






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

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

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

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;
for (bin = 0; gray; gray >>= 1)
bin ^= gray;
return bin;
}
// grayValue - Значение Грея
// value - Преобразованное значение Грея
// oldValue - Старое преобразованное значение Грея

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //2строка 0символ
if (MasterVolume==80)
{lcd.print(" MUTE "); }
else {lcd.print("VOLUME -"); }
lcd.print(MasterVolume);
lcd.print("dB ");

}
else //if (MENUmode == 1)
{





lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 2; MasterVolume = 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)//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
{
sprintf( strokaI,"vol on Power on ") ;

sprintf(strokaII,"eeprom80 - ") ; IntToChar(MasterVolume, &strokaII[13]);
if (MUTE_or_MENU_button.click_down)
{ if (EEPROM.read(80)==MasterVolume){ sprintf( strokaI,"eeprom = mastVOL") ;} else { sprintf( strokaI,"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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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




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

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, 0b00011111); //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)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/



















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






}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

oleg707
25.11.2016, 15:37
товарищи, подскажите момент
Сделал регулировку басов, но нет реакции.
То есть меняю команду tda7442(3, BASSlevelBYTE);
А басы не меняются. Я так понял, нужно активировать эквалайзер, вопрос что прописать
даташит (http://pdf.eepw.com.cn/720090724/df66ec375f0ec2db9b80724e3949c8b9.pdf)

разобрался
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)


Вот текущий скетч:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;
for (bin = 0; gray; gray >>= 1)
bin ^= gray;
return bin;
}
// grayValue - Значение Грея
// value - Преобразованное значение Грея
// oldValue - Старое преобразованное значение Грея

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //2строка 0символ
if (MasterVolume==80)
{lcd.print (" MUTE "); }
else {lcd.print("VOLUME -"); }
lcd.print(MasterVolume);
lcd.print("dB ");

}
else //if (MENUmode == 1)
{





lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = EEPROM.read(80);}// //если кнопка MUTE однократно нажата в режиме vibor_nomera_punkta_v_MENU_2 (setup vol on Pon) , то надо бы включить подменю выбора значения 0-80 для записи в еепром атмеги
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if (vibor_nomera_punkta_v_MENU == 3)
{
sprintf( strokaI,"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)
{
sprintf( strokaI,"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");
sprintf( strokaII,"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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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




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

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)
/*конец конфигурации 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
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;
for (bin = 0; gray; gray >>= 1)
bin ^= gray;
return bin;
}
// grayValue - Значение Грея
// value - Преобразованное значение Грея
// oldValue - Старое преобразованное значение Грея

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //2строка 0символ
if (MasterVolume==80)
{lcd.print (" MUTE "); }
else {lcd.print("VOLUME -"); }
lcd.print(MasterVolume);
lcd.print("dB ");

}
else //if (MENUmode == 1)
{





lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP bass EQ_ON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) // настройка пищалок
{
sprintf( strokaI,"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");
sprintf( strokaII,"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) {sprintf( strokaI,"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) {sprintf( strokaI,"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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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




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

tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
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)
/*конец конфигурации 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
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;
for (bin = 0; gray; gray >>= 1)
bin ^= gray;
return bin;
}
// grayValue - Значение Грея
// value - Преобразованное значение Грея
// oldValue - Старое преобразованное значение Грея

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC = 0;}
//конвертация верхов из байт в десятичную
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) { TREBlevelDEC = (map (TREBlevelBYTE, 238,142, 1, 7))*2; }// положительное значение
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126) { TREBlevelDEC = (map (TREBlevelBYTE, 14,110, -7, -1))*2; }// отрицательное значение
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC = 0;}
//__________________________________________________ __________________________________________________ _________________________



lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP BASS eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) {sprintf( strokaI,"SETUP TREB eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // сброс на начальные установки
{
sprintf( strokaI,"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");
sprintf( strokaII,"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) {sprintf( strokaI,"set bass eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) {sprintf( strokaI,"set treb eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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)// сброс на начальные установки
{
sprintf( strokaI, "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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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




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

tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, TREBlevelBYTE); //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(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)
/*конец конфигурации 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
Мне) я вообще очень слежу за этой темой, планирую дальше переделывать свой проект с использованием твоей этой разработки

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

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

oleg707
27.11.2016, 00:22
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 = 9, ENC_PIN2 = 10};
// Преобразование значения Грея в двоичный код
// без изменений прямиком из wilipedia
unsigned graydecode(unsigned gray) {
unsigned bin;
for (bin = 0; gray; gray >>= 1)
bin ^= gray;
return bin;
}
// grayValue - Значение Грея
// value - Преобразованное значение Грея
// oldValue - Старое преобразованное значение Грея

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC = 0;}
//конвертация верхов из байт в десятичную
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) { TREBlevelDEC = (map (TREBlevelBYTE, 238,142, 1, 7))*2; }// положительное значение
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126) { TREBlevelDEC = (map (TREBlevelBYTE, 14,110, -7, -1))*2; }// отрицательное значение
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC = 0;}
//__________________________________________________ __________________________________________________ _________________________

lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP BASS eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) {sprintf( strokaI,"SETUP TREB eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // сброс на начальные установки
{
sprintf( strokaI,"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)
{
sprintf( strokaI,"INPUT SELECT ") ;
sprintf(strokaII," AUX __ ") ; IntToChar( (map (selectINPUT, 0, 6, 4, 1)) , &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");
sprintf( strokaII,"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) {sprintf( strokaI,"set bass eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) {sprintf( strokaI,"set treb eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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)// сброс на начальные установки
{
sprintf( strokaI, "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 (selectINPUT, 0, 6, 4, 1)), &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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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




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

tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, TREBlevelBYTE); //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(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, selectINPUT/*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//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

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

тогда надо на проц сделать вход с громкой связи и добавить в код типа такого
if (pinX==1) {selectINPUT_OLD = selectINPUT; selectINPUT = 2;}
else {selectINPUT = selectINPUT_OLD ;}

Тогда будет переключать на громкую связь при логической единице на пине pinX и возвращать обратно на источник( IN1-IN4), который играл до этого.

объединить через сумматор
Я когда эквалайзер активирую в TDA7442, то слышу лёгкое искажение звучания ( да на акустике за 2 килобакса, но всё же!), потому и ввёл отдельный пункт меню EQ OFF.
Так что объединить через сумматор может для качества не самая хорошая мысль... Хотя смотря какой сумматор.

Az0m@
27.11.2016, 00:27
ребят, вопрос. Кому нить вообще надо выбор источника ( типа IN1 - IN4) в этой штуке ?
А то немного лениво кодить:blush:
тоже слежу...но считаю проект будет более интересен если будет возможность прикрутить сюда вход от блюпуп соединения с телефоном для громкой связи.. думаю тода многие к проекту подтянуться

oleg707
27.11.2016, 00:36
тоже слежу...но считаю проект будет более интересен если будет возможность прикрутить сюда вход от блюпуп соединения с телефоном для громкой связи.. думаю тода многие к проекту подтянуться

а что его крутить, AUX 2 выбрали, подключили к нему аудиовыход блютуз модуля и вперед.
Поскольку никакого блютуз модуля громкой связи у меня нет в наличии ( хотя на Китае подумывал его заказать) Этот функционал прикручивать пока не буду. :dntknw:

Az0m@
27.11.2016, 11:10
а что его крутить, AUX 2 выбрали, подключили к нему аудиовыход блютуз модуля и вперед.
Поскольку никакого блютуз модуля громкой связи у меня нет в наличии ( хотя на Китае подумывал его заказать) Этот функционал прикручивать пока не буду. :dntknw:

когда с отладкой БП окончательно закончу...думаю по реализации этого функционала я еще возвращусь с вопросами к тебе -)

oleg707
27.11.2016, 15:02
когда с отладкой БП окончательно закончу...думаю по реализации этого функционала я еще возвращусь с вопросами к тебе -)

Хочу в 6й версии БП делать хаб, звуковую и регулировку звука. Походу этот проект - это тренировка для более сложного проекта.:blink2: Но это если и будет, то может и через год, и через 2. Зависит от свободного времени, желания и работоспособности текущей версии.

oleg707
27.11.2016, 15:29
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442D
int ver = 92;
// с подавлением дребезга кнопок
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера)
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) - басы и пищалки
// Добавил меню сброса на настройки по умолчанию ( заодно восстанавливает неправильно записанный еепром на нужные значения), работает только один раз, потом надо передёрнуть питание.
// добавил выбор источника IN1 - IN4 с записью в еепром. По умолчанию стоит IN1 (3 и 4 контакты TDA7442D).
// добавил автоматическое переключение текущего аудиовхода на заданный. Например, для громкой связи через колонки. переменная (autoAUX2 = 0;) Нужна для автоматического включения какого-либо входа IN1-4, если (autoAUX2 ==1) .
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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) поскольку физические номера входов ( по даташиту) и программные различаются, для облегчения кода придётся поменять номера входов
bool autoAUX2 = 0; // эта переменная нужна для автоматического включения какого-либо входа IN1-4 . Например, для громкой связи через колонки.
byte selectINPUT_OLD = selectINPUT; // выбор источника, на который переключаться после окончания "сеанса громкой связи "


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

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

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

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

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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 == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC = 0;}
//конвертация верхов из байт в десятичную
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) { TREBlevelDEC = (map (TREBlevelBYTE, 238,142, 1, 7))*2; }// положительное значение
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126) { TREBlevelDEC = (map (TREBlevelBYTE, 14,110, -7, -1))*2; }// отрицательное значение
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC = 0;}
//__________________________________________________ __________________________________________________ _________________________

lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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 < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP BASS eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) {sprintf( strokaI,"SETUP TREB eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // сброс на начальные установки
{
sprintf( strokaI,"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)
{
sprintf( strokaI,"INPUT SELECT ") ;
sprintf(strokaII," AUX __ ") ; IntToChar( (map (selectINPUT, 0, 6, 4, 1)) , &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");
sprintf( strokaII,"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) {sprintf( strokaI,"set bass eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) {sprintf( strokaI,"set treb eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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)// сброс на начальные установки
{
sprintf( strokaI, "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 (selectINPUT, 0, 6, 4, 1)), &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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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



/*ДЛЯ активации другого входа по сообытию */
if (autoAUX2 ==1) {selectINPUT_OLD = selectINPUT; selectINPUT = 2;} // если сработало сообытие ( например на пин autoAUX2 пришла 1), то сохраняем текущий звуковой вход в selectINPUT_OLD, и включаем ВХОД 2 ( если нужен другой вход, то вместо 2 поставить 0 2 4 6)(6 - вход звука по умолчанию 3,4 пины)
else {if (MENUmode == 0) {selectINPUT = selectINPUT_OLD ;}} // если сообытие прошло, то возвращаемся на звуковой вход, который играл до этого.
/* конец активации другого входа по сообытию*/



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

tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, TREBlevelBYTE); //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(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, selectINPUT/*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//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

demtro
27.11.2016, 15:38
самый дешевый вариант БТ модуля :-) (https://ru.aliexpress.com/item/New-XS3868-Bluetooth-Stereo-Audio-Module-OVC3860-Supports-A2DP-AVRCP-Good/32642371695.html?spm=2114.30010708.3.10.0CS3Xz&ws_ab_test=searchweb0_0,searchweb201602_4_10065_10 068_10000007_10084_10083_10080_10082_10081_10060_1 0061_10062_10056_10055_10037_10054_10033_10059_100 32_10099_10078_10079_10077_10093_10073_10097_10100 _10096_10070_10052_10050_424_10051,searchweb201603 _2&btsid=783d9eaa-4c7e-4e21-91b4-8036c23cb2d5)

oleg707
27.11.2016, 15:50
самый дешевый вариант БТ модуля :-) (https://ru.aliexpress.com/item/New-XS3868-Bluetooth-Stereo-Audio-Module-OVC3860-Supports-A2DP-AVRCP-Good/32642371695.html?spm=2114.30010708.3.10.0CS3Xz&ws_ab_test=searchweb0_0,searchweb201602_4_10065_10 068_10000007_10084_10083_10080_10082_10081_10060_1 0061_10062_10056_10055_10037_10054_10033_10059_100 32_10099_10078_10079_10077_10093_10073_10097_10100 _10096_10070_10052_10050_424_10051,searchweb201603 _2&btsid=783d9eaa-4c7e-4e21-91b4-8036c23cb2d5)

хм, ну давай разбирать
Питание - надо городить своё
микрофон - надо городить свой, возможно с предусилителем
управление - надо вешать на проц, который TDAшкой управляет (там Rx и Tx), опять же стоит вопрос синхронизации подключения телефон - эта хрень.
Плюсы - заимеем программные кнопки по блютузу
vol+
vol-
next
prev

Не стоит потерянное время эти $2.70.
На сегодняшний день я склоняюсь к покупке готового устройства (10-15$) и подключении его аудиовыхода на один из звуковых входов TDAшки.

ВОТ (https://ru.aliexpress.com/item/Wireless-Bluetooth-Receiver-Speaker-Headphone-Adapter-3-5MM-Audio-Stereo-Music-Receiver-Home-Hands-free-Bluetooth/32733011517.html?spm=2114.30010708.3.199.C7OriW&ws_ab_test=searchweb0_0,searchweb201602_1_116_1006 5_117_10068_114_115_113_10000007_10084_10083_10080 _10082_10081_10060_10061_10062_10056_10055_10037_1 0054_10059_10032_10099_10078_10079_10077_10093_100 73_10097_10100_10096_10070_10052_10050_424_10051,s earchweb201603_1&btsid=b35ccb87-8691-492f-b61f-b97c93d6e9fc) вариант блютуз аудиовыхода ( брать музыку из телефона друзей по блютузу) (или даже полноценной ХЕНДСфрии)

demtro
27.11.2016, 15:57
хм, ну давай разбирать
Питание - надо городить своё
микрофон - надо городить свой, возможно с предусилителем
управление - надо вешать на проц, который TDAшкой управляет (там Rx и Tx), опять же стоит вопрос синхронизации подключения телефон - эта хрень.
Плюсы - заимеем программные кнопки по блютузу
vol+
vol-
next
prev

Не стоит потерянное время эти $2.70.
На сегодняшний день я склоняюсь к покупке готового устройства (10-15$) и подключении его аудиовыхода на один из звуковых входов TDAшки.

ВОТ (https://ru.aliexpress.com/item/Wireless-Bluetooth-Receiver-Speaker-Headphone-Adapter-3-5MM-Audio-Stereo-Music-Receiver-Home-Hands-free-Bluetooth/32733011517.html?spm=2114.30010708.3.199.C7OriW&ws_ab_test=searchweb0_0,searchweb201602_1_116_1006 5_117_10068_114_115_113_10000007_10084_10083_10080 _10082_10081_10060_10061_10062_10056_10055_10037_1 0054_10059_10032_10099_10078_10079_10077_10093_100 73_10097_10100_10096_10070_10052_10050_424_10051,s earchweb201603_1&btsid=b35ccb87-8691-492f-b61f-b97c93d6e9fc) вариант блютуз аудиовыхода ( брать музыку из телефона друзей по блютузу) (или даже полноценной ХЕНДСфрии)
Питание 3.3В и так на плате будет если USB хаб собирать и звуковуху на PCM2704, обвязка микрофона минимум (там пара резисторов кондеров), какое управление надо? там все просто помоему - принять звонок с таблет толка можно, по кнопкам плау паузу забыл/ответ на звонок. Модуль так же воспроизводит звук с телефона по БТ

Az0m@
27.11.2016, 19:08
ВОТ (https://ru.aliexpress.com/item/Wireless-Bluetooth-Receiver-Speaker-Headphone-Adapter-3-5MM-Audio-Stereo-Music-Receiver-Home-Hands-free-Bluetooth/32733011517.html?spm=2114.30010708.3.199.C7OriW&ws_ab_test=searchweb0_0,searchweb201602_1_116_1006 5_117_10068_114_115_113_10000007_10084_10083_10080 _10082_10081_10060_10061_10062_10056_10055_10037_1 0054_10059_10032_10099_10078_10079_10077_10093_100 73_10097_10100_10096_10070_10052_10050_424_10051,s earchweb201603_1&btsid=b35ccb87-8691-492f-b61f-b97c93d6e9fc) вариант блютуз аудиовыхода ( брать музыку из телефона друзей по блютузу) (или даже полноценной ХЕНДСфрии)
сейчас пользуюсь аналогичной хренью... звук отстой... хотя наверно для голосового общения пойдет... но не для прослушивания музыки с телефона

oleg707
27.11.2016, 22:32
не выдержал и добавил, пока всё еще в голове.
INPUT ATTENUATION - приглушение ВХОДНОГО (IN1-IN4) канала, будет полезно для микширования аудиосигнала (8,10 пины TDA7442D - постоянный сигнал; (3,4)(5,2)(6,1)(7,28) пины - подмешиваемый сигнал с регулировкой громкости с шагом 0,5 dB ).
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442D
int ver = 95;
// с подавлением дребезга кнопок
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера)
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода при нажатии-удержании кнопок громкости.( при вращении энкодером пока убрал)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) - басы и пищалки
// Добавил меню сброса на настройки по умолчанию ( заодно восстанавливает неправильно записанный еепром на нужные значения), работает только один раз, потом надо передёрнуть питание.
// добавил выбор источника IN1 - IN4 с записью в еепром. По умолчанию стоит IN1 (3 и 4 контакты TDA7442D).
// добавил автоматическое переключение текущего аудиовхода на заданный. Например, для громкой связи через колонки. переменная (autoAUX2 = 0;) Нужна для автоматического включения какого-либо входа IN1-4, если (autoAUX2 ==1) .
// добавил INPUT ATTENUATION - приглушение ВХОДНОГО (IN1-IN4) канала, будет полезно для микширования аудиосигнала (8,10 пины TDA7442D - постоянный сигнал; (3,4)(5,2)(6,1)(7,28) пины - подмешиваемый сигнал с регулировкой громкости с шагом 0,5 dB ).
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для 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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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) поскольку физические номера входов ( по даташиту) и программные различаются, для облегчения кода придётся поменять номера входов
bool autoAUX2 = 0; // эта переменная нужна для автоматического включения какого-либо входа IN1-4 . Например, для громкой связи через колонки.
byte selectINPUT_OLD = selectINPUT; // выбор источника, на который переключаться после окончания "сеанса громкой связи "
byte INPUT_ATTENUATION = EEPROM.read(77); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 127 = -31.5dB


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

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

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

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

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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
if ( INPUT_ATTENUATION == 255) {EEPROM.write(77,64); INPUT_ATTENUATION = 64;} //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 127 = -31.5dB
}
//================================================== ================================================== ================================================== ================================================== =============================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
static unsigned long prevTime = 0; // время когда последний раз увеличивали или уменьшали громкость
if(millis() - prevTime > interval-USCORENIE) {
prevTime = millis(); // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
if (Vupupup == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC = 0;}
//конвертация верхов из байт в десятичную
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) { TREBlevelDEC = (map (TREBlevelBYTE, 238,142, 1, 7))*2; }// положительное значение
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126) { TREBlevelDEC = (map (TREBlevelBYTE, 14,110, -7, -1))*2; }// отрицательное значение
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC = 0;}
//__________________________________________________ __________________________________________________ _________________________

lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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 < 6 ) {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;}
}
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
if (INPUT_ATTENUATION < 127) {INPUT_ATTENUATION = INPUT_ATTENUATION+1;}
}


}// конец вращение влево


else if (oldValue == 1) // вращение вправо
{
timerMENU = millis();
if (MENUmode == 0) // то регулируем громкость
{
if (MasterVolume == 0){stepENC = 1;} else {stepENC++;} /*Serial.println(stepENC);*/
if( stepENC < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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;}
}
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
if (INPUT_ATTENUATION > 64) {INPUT_ATTENUATION = INPUT_ATTENUATION-1;}
}
}// конец вращение вправо

}//конец Энкодер вращается


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 = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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=8;} //ограничим количество режимов меню (всего 8 пунктов)
if(vibor_nomera_punkta_v_MENU>=9) { 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP BASS eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) {sprintf( strokaI,"SETUP TREB eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // сброс на начальные установки
{
sprintf( strokaI,"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)
{
sprintf( strokaI,"INPUT SELECT ") ;
sprintf(strokaII," AUX __ ") ; IntToChar( (map (selectINPUT, 0, 6, 4, 1)) , &strokaII[11] );
}
if (MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==7){MENUmode = 7; }
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if (vibor_nomera_punkta_v_MENU == 8) // приглушение источника (INPUT_ATTENUATION)
{
sprintf( strokaI,"ATTENUATION ") ;
sprintf(strokaII,"INPUT ") ; IntToChar( (map (INPUT_ATTENUATION, 64, 127, 63, 0)) , &strokaII[11] );
}
if (MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==8){MENUmode = 8; }
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

}//КОНЕЦ режима меню и настроек ( конец главного меню) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
// ворая ступень меню ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
{
sprintf( strokaI,"select volume on");
sprintf( strokaII,"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) {sprintf( strokaI,"set bass eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) {sprintf( strokaI,"set treb eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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)// сброс на начальные установки
{
sprintf( strokaI, "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
EEPROM.write(77,64); INPUT_ATTENUATION = 64;//INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 255 = -31.5dB
MENUmode = 0; // вышли в корень меню.
}
}


}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
if (MENUmode == 7) // // ВЫБОР ВХОДА ( IN1 - IN4)
{
sprintf ( strokaI,"select AUX ");
sprintf (strokaII," ") ;IntToChar((map (selectINPUT, 0, 6, 4, 1)), &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);}
}
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
sprintf ( strokaI,"SET ATTENUATION ");
sprintf (strokaII,"Level = "); IntToChar( (map (INPUT_ATTENUATION, 64, 127, 63, 0)) , &strokaII[11] );
// sprintf (strokaII,"Level = "); IntToChar( INPUT_ATTENUATION , &strokaII[11] );
if (MUTE_or_MENU_button.click_down) {
if (EEPROM.read(77) == INPUT_ATTENUATION) {} else { MENUmode = 1;EEPROM.write(77,INPUT_ATTENUATION);}
}
}
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~конец обработки 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 = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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



/*ДЛЯ активации другого входа по сообытию */
if (autoAUX2 ==1) {selectINPUT_OLD = selectINPUT; selectINPUT = 2;} // если сработало сообытие ( например на пин autoAUX2 пришла 1), то сохраняем текущий звуковой вход в selectINPUT_OLD, и включаем ВХОД 2 ( если нужен другой вход, то вместо 2 поставить 0 2 4 6)(6 - вход звука по умолчанию 3,4 пины)
else {if (MENUmode == 0) {selectINPUT = selectINPUT_OLD ;}} // если сообытие прошло, то возвращаемся на звуковой вход, который играл до этого.
/* конец активации другого входа по сообытию*/



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

//tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(0, INPUT_ATTENUATION); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, TREBlevelBYTE); //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(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, selectINPUT/*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);
//Serial.print("INPUT_ATTENUATION = "); Serial.print(INPUT_ATTENUATION); Serial.print(" "); Serial.println(INPUT_ATTENUATION, BIN);
}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

oleg707
29.11.2016, 01:39
когда нечего больше добавлять, начинают добавлять свистоперделки
еще чуть уменьшил периодичность вывода на дисплей - больше тормозит проц, зато чуть отзывчивее стал экран.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442D
int ver = 98;
// с подавлением дребезга кнопок
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера)
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода при нажатии-удержании кнопок громкости, при вращении энкодером, при нажатии на кнопку энкодера(mute) или при её удержании (меню)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) - басы и пищалки
// Добавил меню сброса на настройки по умолчанию ( заодно восстанавливает неправильно записанный еепром на нужные значения), работает только один раз, потом надо передёрнуть питание.
// добавил выбор источника IN1 - IN4 с записью в еепром. По умолчанию стоит IN1 (3 и 4 контакты TDA7442D).
// добавил автоматическое переключение текущего аудиовхода на заданный. Например, для громкой связи через колонки. переменная (autoAUX2 = 0;) Нужна для автоматического включения какого-либо входа IN1-4, если (autoAUX2 ==1) .
// добавил INPUT ATTENUATION - приглушение ВХОДНОГО (IN1-IN4) канала, будет полезно для микширования аудиосигнала (8,10 пины TDA7442D - постоянный сигнал; (3,4)(5,2)(6,1)(7,28) пины - подмешиваемый сигнал с регулировкой громкости с шагом 0,5 dB ).
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для newE описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347
#include <EEPROM.h>
char strokaI[32] = " ";// Массив для вывода 1 строки на дисплей , объявляем длиннее(32символа), чтобы не было глюков с отображением на экране
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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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) поскольку физические номера входов ( по даташиту) и программные различаются, для облегчения кода придётся поменять номера входов
bool autoAUX2 = 0; // эта переменная нужна для автоматического включения какого-либо входа IN1-4 . Например, для громкой связи через колонки.
byte selectINPUT_OLD = selectINPUT; // выбор источника, на который переключаться после окончания "сеанса громкой связи "
byte INPUT_ATTENUATION = EEPROM.read(77); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 127 = -31.5dB


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

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

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

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

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





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

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

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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
if ( INPUT_ATTENUATION == 255) {EEPROM.write(77,64); INPUT_ATTENUATION = 64;} //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 127 = -31.5dB
}
//================================================== ================================================== ================================================== ================================================== =============================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
static unsigned long prevTime = 0; // время когда последний раз увеличивали или уменьшали громкость
if(millis() - prevTime > interval-USCORENIE) {
prevTime = millis(); // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
if (Vupupup == 1 && 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 subaddress, byte 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 num, char *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(MasterVolume, 0, 80, 80, 0);// переменная, зеркалим значение громкости, чтобы нормально выводить на дисплей(громче-больше)http://arduino.ua/ru/prog/Map
lcd.setCursor(0, 0);
lcd.printHorizontalGraph('v', 0, Mdisp, 80); //name of the bar, first row, current value, max. value вывод полоски громкости в первой строке
//-------------------2 строка---------------------------------
lcd.setCursor(0, 1); //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 (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC = 0;}
//конвертация верхов из байт в десятичную
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) { TREBlevelDEC = (map (TREBlevelBYTE, 238,142, 1, 7))*2; }// положительное значение
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126) { TREBlevelDEC = (map (TREBlevelBYTE, 14,110, -7, -1))*2; }// отрицательное значение
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC = 0;}
//__________________________________________________ __________________________________________________ _________________________

lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //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();
digitalWrite(13,1);
if (MENUmode == 0) // то регулируем громкость
{
if (MasterVolume == 80){stepENC = 1;} else {stepENC++;} /* Serial.println(stepENC);*/
if( stepENC < 6 ) {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;}
}
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
if (INPUT_ATTENUATION < 127) {INPUT_ATTENUATION = INPUT_ATTENUATION+1;}
}


}// конец вращение влево


else if (oldValue == 1) // вращение вправо
{
timerMENU = millis();
digitalWrite(13,1);
if (MENUmode == 0) // то регулируем громкость
{
if (MasterVolume == 0){stepENC = 1;} else {stepENC++;} /*Serial.println(stepENC);*/
if( stepENC < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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;}
}
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
if (INPUT_ATTENUATION > 64) {INPUT_ATTENUATION = INPUT_ATTENUATION-1;}
}
}// конец вращение вправо

}//конец Энкодер вращается


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(); digitalWrite(13,1);}
if (MENUmode == 0)
{//MENUmode == 0
if (MUTE_or_MENU_button.click_down)//если кнопка MUTE однократно нажата
{
if (MuteActiv == 0){MasterVolumeDoMUTE = MasterVolume;}
MuteActiv = (!MuteActiv);
if (MuteActiv == 1){ MasterVolumeDoMUTE = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 0; }
Serial.print("MuteActiv = " );Serial.print(MuteActiv);Serial.print(" MasterVolume = "); Serial.println(MasterVolume);
}
}//MENUmode == 0



if (MENUmode == 1)//зашли в режим меню и настроек (главное меню) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
{
if(vibor_nomera_punkta_v_MENU<=0) { vibor_nomera_punkta_v_MENU=8;} //ограничим количество режимов меню (всего 8 пунктов)
if(vibor_nomera_punkta_v_MENU>=9) { 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP BASS eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) {sprintf( strokaI,"SETUP TREB eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // сброс на начальные установки
{
sprintf( strokaI,"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)
{
sprintf( strokaI,"INPUT SELECT ") ;
sprintf(strokaII," AUX __ ") ; IntToChar( (map (selectINPUT, 0, 6, 4, 1)) , &strokaII[11] );
}
if (MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==7){MENUmode = 7; }
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if (vibor_nomera_punkta_v_MENU == 8) // приглушение источника (INPUT_ATTENUATION)
{
sprintf( strokaI,"ATTENUATION ") ;
sprintf(strokaII,"INPUT ") ; IntToChar( (map (INPUT_ATTENUATION, 64, 127, 63, 0)) , &strokaII[11] );
}
if (MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==8){MENUmode = 8; }
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

}//КОНЕЦ режима меню и настроек ( конец главного меню) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
// ворая ступень меню ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
{
sprintf( strokaI,"select volume on");
sprintf( strokaII,"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) {sprintf( strokaI,"set bass eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) {sprintf( strokaI,"set treb eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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)// сброс на начальные установки
{
sprintf( strokaI, "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
EEPROM.write(77,64); INPUT_ATTENUATION = 64;//INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 255 = -31.5dB
MENUmode = 0; // вышли в корень меню.
}
}


}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
if (MENUmode == 7) // // ВЫБОР ВХОДА ( IN1 - IN4)
{
sprintf ( strokaI,"select AUX ");
sprintf (strokaII," ") ;IntToChar((map (selectINPUT, 0, 6, 4, 1)), &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);}
}
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
sprintf ( strokaI,"set attenuation ");
sprintf (strokaII,"level = "); IntToChar( (map (INPUT_ATTENUATION, 64, 127, 63, 0)) , &strokaII[11] );
if (MUTE_or_MENU_button.click_down) {
if (EEPROM.read(77) == INPUT_ATTENUATION) {} else { MENUmode = 1;EEPROM.write(77,INPUT_ATTENUATION);}
}
}
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

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

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

if (MUTE_or_MENU_button.retention) { // если удерживаем нажатой кнопку MUTE
digitalWrite(13,1);
MENUmode = (!MENUmode); //инвертируем признак того, что мы в меню //MENUmode = 2 - есть и такая строка, тогда MENUmode = (!MENUmode); должно работать некорректно. НО работает так, как надо
timerMENU = millis();
MuteActiv = (!MuteActiv); //возвращаем состояние MUTE на предидущее ( потому что нажав кнопку меню мы сначела жмём MUTE, а только потом активируется меню)
if (MuteActiv == 1){ MasterVolumeDoMUTE = MasterVolume; MasterVolume=80; } // этими двумя строками возвращаем громкость на уровень " ДО НАЖАТИЯ MENU-MUTE"
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 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 = 0; USCORENIE = 0;} //если отпустили кнопку, надо бы перестать увеличивать громкость по шагам
if (VOLDNbutton.click_up) { Vdndndn = 0; USCORENIE = 0;}
VOLFAST(VOLUME_INTERVAL); //заходим в функцию VOLFAST, которая ЕСЛИ удерживаются кнопки регулировки громкости, то увеличивает или уменьшает громкость на один шаг (1dB) с периодичностью VOLUME_INTERVAL.
/*================================================= ================================================== ================*/



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



/*ДЛЯ активации другого входа по сообытию */
if (autoAUX2 ==1) {selectINPUT_OLD = selectINPUT; selectINPUT = 2;} // если сработало сообытие ( например на пин autoAUX2 пришла 1), то сохраняем текущий звуковой вход в selectINPUT_OLD, и включаем ВХОД 2 ( если нужен другой вход, то вместо 2 поставить 0 2 4 6)(6 - вход звука по умолчанию 3,4 пины)
else {if (MENUmode == 0) {selectINPUT = selectINPUT_OLD ;}} // если сообытие прошло, то возвращаемся на звуковой вход, который играл до этого.
/* конец активации другого входа по сообытию*/



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

//tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(0, INPUT_ATTENUATION); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, TREBlevelBYTE); //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(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, selectINPUT/*0b00000110*/); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4 2-in3 0-in2 по даташиту)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




















printDISPLAY(100); // выводим на дисплей раз в 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);
//Serial.print("INPUT_ATTENUATION = "); Serial.print(INPUT_ATTENUATION); Serial.print(" "); Serial.println(INPUT_ATTENUATION, BIN);
}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

Elliot
01.12.2016, 01:49
OVC3860 хороший модуль,функционала дофига и дешевый.Для качества звука запитывать его лучше через DC\DC изолированный преобразователь. Вопрос oleg707 ,а вы прогой FLPROG случаем не пользуетесь?

oleg707
01.12.2016, 12:20
OVC3860 хороший модуль,функционала дофига и дешевый.Для качества звука запитывать его лучше через DC\DC изолированный преобразователь. Вопрос oleg707 ,а вы прогой FLPROG случаем не пользуетесь?

OVC3860 - можно, Поддержка A2DP AVRCP Bluetooth 2.0 есть.
Позже, возможно. Мне нужна была штука, заменяющая переменный резистор, для регулировки громкости.

FLPROG пытался при знакомстве с дуиной, как то не пошло.
Я сейчас код пишу в notepad++ (с++), а потом переношу в ардуино IDE. Там и проверяю, и пишу ( либо через юсб, либо череp ISP-программатор)

yuriy m
01.12.2016, 22:24
Я сейчас код пишу в notepad++ (с++), а потом переношу в ардуино IDE. Там и проверяю, и пишу ( либо через юсб, либо череp ISP-программатор)
+1 хоть и ардуины не люблю,но пишу в notepadе... Только зачем переносить ? если и так на автомате работает,через вкладку внешний редактор...

oleg707
02.12.2016, 00:15
+1 хоть и ардуины не люблю,но пишу в notepadе... Только зачем переносить ? если и так на автомате работает,через вкладку внешний редактор...

тоже можно... давно пробовал, как то не прижилось. Компилировать неудобно, приходится незакрытую скобку искать, прыгая туда сюда. А в notepadе++ у меня и 10 вкладок может быть открыто, с разными кусками кода.
А так ctrl+C ctrl+V наше всё:big:

0617
02.12.2016, 00:37
Прошу прощения, что встреваю в разговор мэтров.
Мне кажется весьма комфортной PlatformIO (http://platformio.org/).

oleg707
02.12.2016, 02:10
Прошу прощения, что встреваю в разговор мэтров.
Мне кажется весьма комфортной PlatformIO (http://platformio.org/).

Нюансы PlatformIO

PlatformIO ускоряет работу, это более гибкий инструмент по сравнению с Arduino IDE и с ним легче автоматизировать рутинные задачи. Есть при этом несколько моментов которые стоит учитывать:
компиляция в PlatformIO не всегда равноценна компиляции в Arduino IDE, то что скопмилировалось в PlatformIO может не компилироваться в Arduino IDE и наоборот
структура папок проекта не совпадает со структурой для Arduino IDE
не все библиотеки доступны для установки через platformio lib.

Тем более нотепеда++ и ардуино 1,6,12 пока хватает, в отличие от знаний и опыта.
Хотя чем больше пишу кода, тем больше волосы дыбом встают по поводу старых проектов.:secret:

demtro
14.12.2016, 16:59
autoAUX2 на какой пин атмеги настроен этот вход?

oleg707
14.12.2016, 18:09
bool autoAUX2 = 0; это переменная. может быть 0 или 1
как хотим, так и обрабатываем.

demtro
19.12.2016, 17:17
чем прошиваешь атмеги через rs232?

oleg707
20.12.2016, 18:33
чем прошиваешь атмеги через rs232?

в основном я по ICP шью. Для этого прогер за 2,5 бакса давно куплен на китае.
Но в текущем проекте для отладки нужен был ком порт.
Сделал просто - атмегу328 выпаял феном с нано, перепаял её на макетную плату. Вывел Rx Tx RST GND
Подключил это на нано соответственно подписям.
Итого имею Юсб-уарт.
А вообще я изначально проект под атмегу 8 планировал.
Если код влезет в память - то один раз прошил, запаял и пользуйся.

demtro
20.12.2016, 19:53
раньше где-то находил код под arduino micro pro (https://duino.ru/arduino-pro-micro.html) для usb uart вчера весь вечер убил - не нашел. По ISP шьешь через Arduino IDE? у меня IDE на мой ISP ругается, якобы не тот вид и пид

oleg707
20.12.2016, 20:45
раньше где-то находил код под arduino micro pro (https://duino.ru/arduino-pro-micro.html) для usb uart вчера весь вечер убил - не нашел. По ISP шьешь через Arduino IDE? у меня IDE на мой ISP ругается, якобы не тот вид и пид

да, прямо из IDE.
Скетч- загрузить через программатор.
В настройках Инструменты - программатор AVR ISP

demtro
20.12.2016, 21:30
хм, все так же, у меня ругается. а IDE какой версии у тебя?

oleg707
20.12.2016, 21:55
хм, все так же, у меня ругается. а IDE какой версии у тебя?

да любой.
1,6,3
1,6,8
1,6,12
w Xp
w 7

oleg707
10.01.2017, 01:41
пришел из Китая 1306 дисплей ( пиксельный 128*64). Надо ли кому программа для отображения и на нём?

oleg707
13.01.2017, 00:31
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Скетч для 7442D
int ver = 109;
// с подавлением дребезга кнопок
// с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
// с энкодером (код грея - коррекция ошибок энкодера)
// динамическое изменение скорости уменьшения\увеличения громкости при долгом воздействии на энкодер++. (требуется тонкая подстройка в реальной машине)
// с функцией MUTE
// дисплей по I2C
// с ползунком громкости на дисплее
// с монитором по ком-порту
//мигание встроенного светодиода при нажатии-удержании кнопок громкости, при вращении энкодером, при нажатии на кнопку энкодера(mute) или при её удержании (меню)
//с выбором в меню, какое значение громкости выставлять при подаче питания на ардуину. С записью этого значения в еепром и чтением при подаче питания на атмегу. ( если не прописано, то пишется громкость по умолчанию -24dB )
//C активацией внутреннего эквалайзера TDA7442D (EQ_ON EQ_OFF) - басы и пищалки
// Добавил меню сброса на настройки по умолчанию ( заодно восстанавливает неправильно записанный еепром на нужные значения), работает только один раз, потом надо передёрнуть питание.
// добавил выбор источника IN1 - IN4 с записью в еепром. По умолчанию стоит IN1 (3 и 4 контакты TDA7442D).
// добавил автоматическое переключение текущего аудиовхода на заданный. Например, для громкой связи через колонки. переменная (autoAUX2 = 0;) Нужна для автоматического включения какого-либо входа IN1-4, если (autoAUX2 ==1) .
// добавил INPUT ATTENUATION - приглушение ВХОДНОГО (IN1-IN4) канала, будет полезно для микширования аудиосигнала (8,10 пины TDA7442D - постоянный сигнал; (3,4)(5,2)(6,1)(7,28) пины - подмешиваемый сигнал с регулировкой громкости с шагом 0,5 dB ).
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки. (версия 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_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); // для newE описание библиотеки http://elchupanibrei.livejournal.com/27443.html#t23347
#include <EEPROM.h>
char strokaI[32] = " ";// Массив для вывода 1 строки на дисплей , объявляем длиннее(32символа), чтобы не было глюков с отображением на экране
char strokaII[32] = " ";// Массив для вывода 2 строки на дисплей



// ЭТО нужно для вывода на 128*64 Adafruit_SSD1306 дисплей
//#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display2(OLED_RESET);

#define XPOS 0
#define YPOS 1
#define DELTAY 2
//ЗАЧЕМ ????
// конец настройки для вывода на 128*64 Adafruit_SSD1306 дисплей



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(_pb, INPUT);
digitalWrite(_pb, 1);
//===================
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) {p = np; click(); start = stop; b = 1; t = 1; r = 1;} // состояние цифрового пина изменилось.
//================================================== ============================
if (b != 0 ) {if (stop - start > bounce_ ) {b = 0; click(); }} // фильтр дребезга.
if (c != 0 ) {if (stop - start > doubleclick_) {c = 0; }} // обнуление счётчика двойного клика.
if (t != 0 && s == 1) {if (stop - start > timer_ ) {t = 0; timer = 1;}} // неактивность.
if (r != 0 && s == 0) {if (stop - start > retention_ ) {r = 0; retention = 1;}} // нажатие и удержание.
//================================================== ============================
}

void click() { // нажатие, отпускание, двойное нажатие.
if (b == 0 && s != p) {s = p;
if (s == 0) {click_down = 1; ++c; if (c == 2) {c = 0; doubleclick = 1;}}
if (s == 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 Mute_vspomogat = 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) поскольку физические номера входов ( по даташиту) и программные различаются, для облегчения кода придётся поменять номера входов
boolean autoAUX2 = 0; // эта переменная нужна для автоматического включения какого-либо входа IN1-4 . Например, для громкой связи через колонки.
byte selectINPUT_OLD = selectINPUT; // выбор источника, на который переключаться после окончания "сеанса громкой связи "
byte INPUT_ATTENUATION = EEPROM.read(77); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 127 = -31.5dB


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

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

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

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

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





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

display2.begin(SSD1306_SWITCHCAPVCC, 0x3C); // display 2 or adres 0x3D
display2.clearDisplay();
display2.setTextColor(WHITE);
/*~~~~~~~~ для энкодера~~~~~~~~~~*/
pinMode(ENC_PIN1, INPUT); //настройка пинов энкодера
digitalWrite(ENC_PIN1, 1); // включить подтягивающий резистор http://arduino.ru/Tutorial/DigitalPins
pinMode(ENC_PIN2, INPUT);
digitalWrite(ENC_PIN2, 1);

/*~~~~~~~~конец для энкодера~~~~~~~~~~*/
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
if ( INPUT_ATTENUATION == 255) {EEPROM.write(77,64); INPUT_ATTENUATION = 64;} //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 127 = -31.5dB
}
//================================================== ================================================== ================================================== ================================================== =============================================



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~
// ЕСЛИ удерживаются кнопки регулировки громкости, то увеличиваем или уменьшаем громкость на один шаг (1dB) с периодичностью (interval - USCORENIE + 8)
void VOLFAST(unsigned long interval )
{
static unsigned long prevTime = 0; // время когда последний раз увеличивали или уменьшали громкость
if(millis() - prevTime > interval-USCORENIE) {
prevTime = millis(); // если зажаты сразу две кнопки, приоритет будет на громкость вниз.
if (Vupupup == 1 && 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 subaddress, byte 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 num, char *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) {


//Формируем строки
byte POLOSA = map(MasterVolume, 0, 80, 15, 0);
byte i = 0; //счетчик
sprintf(strokaI,"................");




//Заполнение строк для 1306 и 1602 индикатора
for (i=0; i<=POLOSA; i++ )
{
strokaI[i]= '\xDB'; // \x означает, что мы выводим символ в хексовом виде, то есть код символа. Для 1306 дисплея кодировка ASCII#858 http://foxtools.ru/ASCII#858 То есть '\xDB' выводит прямоугольник.
}

//-------------------2 строка---------------------------------
if (MasterVolume==80) {sprintf(strokaII," MUTE "); }
else {sprintf(strokaII,"VOLUME - dB"); IntToChar(MasterVolume, &strokaII[11]);} //else {lcd.print("VOLUME -"); }
//>>>>>>>>>>>>>> Сформировали строки, теперь надо их вывести на дисплеи:>>>>>>>>>>>>>>


//вывод на 128*64 дисплей (Adafruit_SSD1306) первой строки
display2.clearDisplay(); // очистили буфер
display2.setTextSize(1); // установили размер текста (1-4)
display2.setCursor(0,0); // начальная точка вывода
display2.println(strokaI); // скинули значение I строки в буфер 128*64 дисплея
//вывод на 128*64 дисплей (Adafruit_SSD1306) второй строки
display2.println(strokaII); // скинули значение II строки в буфер 128*64 дисплея
display2.display(); //эта строка выводит картинку 1306 из буфера на экран!


//вывод на 2хстрочный дисплей LCM 1602 с I2C ( на базе расширителя портов PCF8574)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Это если надо вывести на другой дисплей любые другие символы~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sprintf(strokaI," ");
//Заполнение строк для 1602 индикатора
for (i=0; i<=POLOSA; i++ )
{
strokaI[i]= '\xFF'; // ВЫВОД КВАДРАТИКОВ в 1602, в 1306 квадраты не выводит, выводит пустое место. В ком порт выводит "я" \x означает, что мы выводим символ в хексовом виде, то есть код символа.
} //то есть каждый символ дисплея (i) будет заполняться квадратиком соответственно byte POLOSA, который смасштабирован от значения громкости.
//сформировали любые другие символы ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

lcd.setCursor(0, 0); //1строка 0символ 1602 дисплея
lcd.print(strokaI); //Выводим первую сформированную строку на 1602
lcd.setCursor(0, 1); //2строка 0символ
lcd.print(strokaII);
//вывели на 2хстрочный дисплей LCM 1602 с I2C ( на базе расширителя портов PCF8574)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<








}
else //if (MENUmode == 1-6)
{
//конвертация басов из байт в десятичную________________________________________ _____________________________________________
if (24<=BASSlevelBYTE && BASSlevelBYTE<=31) { BASSlevelDEC = (map (BASSlevelBYTE, 30,24, 1, 7))*2; }// положительное значение
if (16<=BASSlevelBYTE && BASSlevelBYTE<=23) { BASSlevelDEC = (map (BASSlevelBYTE, 16,22, -7, -1))*2; }// отрицательное значение
if (BASSlevelBYTE == 0b00011111 || BASSlevelBYTE == 0b00010111) {BASSlevelDEC = 0;}
//конвертация верхов из байт в десятичную
if (142<=TREBlevelBYTE && TREBlevelBYTE<=254) { TREBlevelDEC = (map (TREBlevelBYTE, 238,142, 1, 7))*2; }// положительное значение
if (14<=TREBlevelBYTE && TREBlevelBYTE<=126) { TREBlevelDEC = (map (TREBlevelBYTE, 14,110, -7, -1))*2; }// отрицательное значение
if (TREBlevelBYTE == 0b01111110 || TREBlevelBYTE == 0b11111110) {TREBlevelDEC = 0;}
//__________________________________________________ __________________________________________________ _________________________

lcd.setCursor(0, 0);
lcd.print(strokaI);

lcd.setCursor(0, 1); //2строка 0символ
lcd.print(strokaII);


//вывод на 128*64 дисплей (Adafruit_SSD1306)
display2.clearDisplay();
display2.setTextSize(1);
display2.setTextColor(WHITE);
display2.setCursor(0,0);
display2.println(strokaI);
display2.println(strokaII);
display2.display();
}


}
}



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

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();
digitalWrite(13,1);
if (MENUmode == 0) // то регулируем громкость
{
if (MasterVolume == 80){stepENC = 1;} else {stepENC++;} /* Serial.println(stepENC);*/
if( stepENC < 6 ) {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;}
}
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
if (INPUT_ATTENUATION < 127) {INPUT_ATTENUATION = INPUT_ATTENUATION+1;}
}


}// конец вращение влево


else if (oldValue == 1) // вращение вправо
{
timerMENU = millis();
digitalWrite(13,1);
if (MENUmode == 0) // то регулируем громкость
{
if (MasterVolume == 0){stepENC = 1;} else {stepENC++;} /*Serial.println(stepENC);*/
if( stepENC < 3 ) {stepVOLamount = 1;}
else if( stepENC < 6 ) {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;}
}
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
if (INPUT_ATTENUATION > 64) {INPUT_ATTENUATION = INPUT_ATTENUATION-1;}
}
}// конец вращение вправо

}//конец Энкодер вращается


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 (MENUmode == 0)
{
if (MUTE_or_MENU_button.click_down && Mute_vspomogat == 0 )//если кнопка MUTE однократно нажата
{Mute_vspomogat = 1;}
if ( MUTE_or_MENU_button. click_up) {
if ( Mute_vspomogat == 1) {
if (MuteActiv == 0){MasterVolumeDoMUTE = MasterVolume;}
MuteActiv = (!MuteActiv);
if (MuteActiv == 1){ MasterVolumeDoMUTE = MasterVolume; MasterVolume=80; }
if (MuteActiv==0 ) { MasterVolume = MasterVolumeDoMUTE; MuteActiv = 0; }
}
else {Mute_vspomogat = 0;}
}
}


if (MENUmode == 1)//зашли в режим меню и настроек (главное меню) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
{
Mute_vspomogat = 2;
if(vibor_nomera_punkta_v_MENU<=0) { vibor_nomera_punkta_v_MENU=8;} //ограничим количество режимов меню (всего 8 пунктов)
if(vibor_nomera_punkta_v_MENU>=9) { 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 адрес)
sprintf( strokaI,"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 = 2; MasterVolume = 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) {sprintf( strokaI,"SETUP BASS eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // выбор включен ли эквалайзер
{
sprintf( strokaI,"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) {sprintf( strokaI,"SETUP TREB eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) // сброс на начальные установки
{
sprintf( strokaI,"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)
{
sprintf( strokaI,"INPUT SELECT ") ;
sprintf(strokaII," AUX __ ") ; IntToChar( (map (selectINPUT, 0, 6, 4, 1)) , &strokaII[11] );
}
if (MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==7){MENUmode = 7; }
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if (vibor_nomera_punkta_v_MENU == 8) // приглушение источника (INPUT_ATTENUATION)
{
sprintf( strokaI,"ATTENUATION ") ;
sprintf(strokaII,"INPUT ") ; IntToChar( (map (INPUT_ATTENUATION, 64, 127, 63, 0)) , &strokaII[11] );
}
if (MUTE_or_MENU_button.click_down && vibor_nomera_punkta_v_MENU==8){MENUmode = 8; }
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

}//КОНЕЦ режима меню и настроек ( конец главного меню) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
// ворая ступень меню ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`
if (MENUmode == 2)//настройка громкости при первом включении ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
{
sprintf( strokaI,"select volume on");
sprintf( strokaII,"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) {sprintf( strokaI,"set bass eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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) {sprintf( strokaI,"set treb eqON") ;}
if (EQstate == 0b00000110) {sprintf( strokaI,"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)// сброс на начальные установки
{
sprintf( strokaI, "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
EEPROM.write(77,64); INPUT_ATTENUATION = 64;//INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения) 64 = 0dB 255 = -31.5dB
MENUmode = 0; // вышли в корень меню.
}
}


}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
if (MENUmode == 7) // // ВЫБОР ВХОДА ( IN1 - IN4)
{
sprintf ( strokaI,"select AUX ");
sprintf (strokaII," ") ;IntToChar((map (selectINPUT, 0, 6, 4, 1)), &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);}
}
}//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
if (MENUmode == 8) // приглушение источника (INPUT_ATTENUATION)
{
sprintf ( strokaI,"set attenuation ");
sprintf (strokaII,"level = "); IntToChar( (map (INPUT_ATTENUATION, 64, 127, 63, 0)) , &strokaII[11] );
if (MUTE_or_MENU_button.click_down) {
if (EEPROM.read(77) == INPUT_ATTENUATION) {} else { MENUmode = 1;EEPROM.write(77,INPUT_ATTENUATION);}
}
}
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

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

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

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


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



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

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



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



/*ДЛЯ активации другого входа по сообытию */
if (autoAUX2 ==1) {selectINPUT_OLD = selectINPUT; selectINPUT = 2;} // если сработало сообытие ( например на пин autoAUX2 пришла 1), то сохраняем текущий звуковой вход в selectINPUT_OLD, и включаем ВХОД 2 ( если нужен другой вход, то вместо 2 поставить 0 2 4 6)(6 - вход звука по умолчанию 3,4 пины)
else {if (MENUmode == 0) {selectINPUT = selectINPUT_OLD ;}} // если сообытие прошло, то возвращаемся на звуковой вход, который играл до этого.
/* конец активации другого входа по сообытию*/



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

//tda7442(0, 0b01000000); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(0, INPUT_ATTENUATION); //INPUT ATTENUATION приглушение ВХОДНОГО (IN1-IN4) канала (0 ~ -31.5dB)(0db-макс громкость, без приглушения)
tda7442(1, EQstate); //SURROUND & OUT & EFFECT CONTROL( -6 FIX OFF) 0b00000001 = EQ_ON
tda7442(2, 0b00000011); //SURROUND PHASE RESISTOR( 37KOm)
tda7442(3, BASSlevelBYTE); //BXXX0011 BASS SELECTION (0dB)-14dB (0b0001100 = 14dB; 0b00011000 + 0b00000001 = 0b00011001 (+12dB)
tda7442(4, TREBlevelBYTE); //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(7, 0b00000000); //BXXX0111 NOT ALLOWED
tda7442(8, 0b00000000); //BXXX1000 NOT ALLOWED
tda7442(9, selectINPUT/*0b00000110*/); //BXXX1001 INPUT MULTIPLEXER выбор источника IN1-4 (6-in1 4-in4 2-in3 0-in2 по даташиту)
/*конец конфигурации void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/




















printDISPLAY(100); // выводим на дисплей раз в 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);
//Serial.print("INPUT_ATTENUATION = "); Serial.print(INPUT_ATTENUATION); Serial.print(" "); Serial.println(INPUT_ATTENUATION, BIN);
}//конец LOOP//~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~`~` ~`~`~`~`~`~`~`~`~`~`~`~`~`~`~
//================================================== ================================================== ================================================== ================================================== =============================================
//__________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ __________________________________________________ ________________________________

SamDon
19.09.2017, 12:19
Привет, подскажи пожалуйста, можно ли при помощи этой штуки реализовать возможность выбора источника звука - планшет или аукс кабель? и что для этого надо сделать?заранее спасибо

oleg707
19.09.2017, 20:05
Привет, подскажи пожалуйста, можно ли при помощи этой штуки реализовать возможность выбора источника звука - планшет или аукс кабель? и что для этого надо сделать?заранее спасибо

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