| 
			
			
			
			 Гуру 
			
		
			
				
			
			
			
				 
				Регистрация: 16.04.2014 
				
				Возраст: 41 
				
Город: Gdynia 
Регион: другой - для добавления сообщить ab 
					Сообщений: 2,548
				 
				
				
				     
			 					
		
	 | 
	
	
	
	
		
			
			
				 
				пока я не полез в дебри
			 
			 
			
		
		
		
		 
схема в диптрейсе - исходники 12 2407+7808C+Atmega+ tda7442.zip
С удовольствием выслушаю критику и предложения 
	PHP код: 
	
		
			
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //Скетч v22 i7442
 // с подавлением дребезга кнопок 
 // с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
 // с энкодером (код грея)
 // с функцией MUTE
 // дисплей по I2C
 //без активации внутреннего эквалайзера TDA7442D 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
 // фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
 
 #include <Arduino.h>
 #include <Wire.h> /*добавление библиотеки I2C шины*/
 #include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
 LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display для 0x27 - настройка экрана для библиотеки LiquidCrystal_I2C2004V1
 //LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_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 дисплея
тут я вывел ползунок текущей громкости на дисплей, приведя его к удобному виду (больше полоска = громче)
 
	PHP код: 
	
		
			
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //Скетч v22 i7442
 // с подавлением дребезга кнопок 
 // с динамическим увеличением/уменьшением громкости при удержании кнопок ( с УСКОРЕНИЕМ при удержании)
 // с энкодером (код грея - коррекция ошибок энкодера, но за счёт этого медленно) 
 // с функцией MUTE
 // дисплей по I2C
 //с ползунком громкости
 //без активации внутреннего эквалайзера TDA7442D 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // класс титановый велосипед для тактовой кнопки. (версия 1.0)http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki
 // фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick), нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
 
 #include <Arduino.h>
 #include <Wire.h> /*добавление библиотеки I2C шины*/
 #include <LiquidCrystal_I2C.h>  /*добавление библиотеки для работы с дисплеем по I2C*/
 //LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display для 0x27 - настройка экрана для библиотеки LiquidCrystal_I2C2004V1
 LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_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,!digitalRead(13));}
                        }
     else if (oldValue == 1) { // Влево
                              if(MasterVolume - stepVOLamount >= 0){ (MasterVolume -= stepVOLamount); Serial.println(MasterVolume);digitalWrite(13,!digitalRead(13)); }  /* уменьшаем громкость, но не ниже 0*/
                             }
       }
 
 
 
   oldValue = value;
 
 
 /*конец для энкодера~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
      
 
 
 
 /*конфигурация void tda7442~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 tda7442(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 в 02:13.
				
				
			
		
		
	
	 |