1

Тема: Регулятор громкости и тембра LC75342 на Atmega88 (Arduino IDE)

Основная статья - http://rcl-radio.ru/?p=120528

http://forum.rcl-radio.ru/uploads/images/2022/03/44612db35714c55cb79c74767ebb8773.gif

//  ATMEGA88 12 MHz

#define CE    PD0
#define DI    PD1
#define CL    PD2

#define DT    PD5
#define CLK   PD6
#define SW    PD7

#define IN    PB1
#define MUTE  PB2


#include <avr/io.h>
#include <util/delay.h>
#include <Wire_low.h>         // http://forum.rcl-radio.ru/viewtopic.php?pid=5521#p5521
#include <Lcd1602_i2c_low.h>  // http://rcl-radio.ru/wp-content/uploads/2022/03/Lcd1602_i2c_low.zip
Lcd1602_i2c_low lcd(0x27);// адрес I2C

volatile uint8_t _prevValueAB = 0;    
volatile uint8_t _currValueAB = 0;
volatile int16_t newPosition = 0;
int position = -999;

int menu,vol_reg,mute_reg,in_reg,vol_old,treb_reg,treb_print,bass_reg,bass_print,ball,chl,chr,i;
byte a[6],d1,d2,d3,d4,d5,d6,e1,e2,e3,w,w2,x,www;
int gain0,gain1,gain2,gain3,gain4,gain5,gain0_print;
unsigned long millis_times,times;


int main(){ 
  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  OCR1A = 46874;
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12);
  TIMSK1 |= (1 << OCIE1A);
  sei();
  wire_set(12000000,100000); // тактовая частота контроллера, частота шины I2C
  lcd.setInit();
  lcd.Clear(); // очистка экрана
  lcd.led(1);  // включение и отключение подсветки экрана
  lcd.Write(0,    0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111);
  lcd.Write(1,    0b00111,0b00111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000);
  lcd.Write(2,    0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111);
  lcd.Write(3,    0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111);
  lcd.Write(4,    0b11100,0b11100,0b00000,0b00000,0b00000,0b00000,0b11100,0b11100);
  lcd.Write(5,    0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100);
  lcd.Write(6,    0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00111,0b00111);
  lcd.Write(7,    0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000);
  DDRD |=(1<<CE)|(1<<DI)|(1<<CL);
  PORTD &=~(1<<CE)|(1<<DI)|(1<<CL);
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT21)|(1 << PCINT22); 
  PORTB |=(1<<IN)|(1<<MUTE);
  if(EEPROM_read(100)!=0){for(int i=0;i<101;i++){EEPROM_write(i,0);}}// очистка памяти при первом включении  
  vol_reg = EEPROM_read(0);treb_reg = EEPROM_read(1)-5;bass_reg = EEPROM_read(2)-10;gain1 = EEPROM_read(4);
  gain2 = EEPROM_read(5);gain3 = EEPROM_read(6);gain4 = EEPROM_read(7);gain5 = EEPROM_read(8);
  in_reg = EEPROM_read(9);ball = EEPROM_read(10)-4;
    switch(in_reg){
     case 0: gain0 = gain1;break;
     case 1: gain0 = gain2;break;
     case 2: gain0 = gain3;break;
     case 3: gain0 = gain4;break;
     }
  audio_L();
  audio_R();
            
   
while(1){
/// BUTTON ///////////////////////////////////  
  if(mute_reg==0){  
    if(((PIND >> SW) & 1)==0){menu++;cl();w2=1;w=1;times=millis_times;if(menu>3){menu=0;}}
    if(((PINB >> IN) & 1)==0){in_reg++;menu=4;cl();w=1;times=millis_times;if(in_reg>3){in_reg=0;}}
    }
    if((((PINB >> MUTE) & 1)==0)&&mute_reg==0){mute_reg=1;menu=100;cl();w=1;times=millis_times;vol_old=vol_reg;vol_reg=79;audio_R();audio_L();lcd.Curs(0,6);lcd.PrintString("MUTE");}
    if((((PINB >> MUTE) & 1)==0)&&mute_reg==1){mute_reg=0;menu=0;cl();w=1;times=millis_times;vol_reg=vol_old;audio_R();audio_L();}

////////////// VOLUME ///////////////////////////////////////////////////////////////////
 if(menu==0){
  if(newPosition != position){position = newPosition;vol_reg = vol_reg+newPosition;newPosition=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}
   a[0]= (79-vol_reg)/10;a[1]=(79-vol_reg)%10;
  for(x=0;x<2;x++){switch(x){case 0: e1=10,e2=11,e3=12;break;case 1: e1=13,e2=14,e3=15;break;}digit();}
  if(mute_reg==0){lcd.Curs(0,0);lcd.PrintString("VOLUME");}else{lcd.Curs(0,0);lcd.PrintString("MUTE");}
   lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1);
}
////////////// TREBLE ///////////////////////////////////////////////////////////////////
 if(menu==1){
  if(newPosition != position){position = newPosition;treb_reg = treb_reg-newPosition;newPosition=0;w=1;times=millis_times;treb_func();audio_R();audio_L();}
   if(treb_reg<0){treb_print = (-treb_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{treb_print = treb_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");}
   a[0]= treb_print/10;a[1]=treb_print%10;
   for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();}
   lcd.Curs(0,0);lcd.PrintString("TREBLE");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB");
   } 
////////////// BASS ///////////////////////////////////////////////////////////////////
 if(menu==2){
  if(newPosition != position){position = newPosition;bass_reg = bass_reg-newPosition;newPosition=0;w=1;times=millis_times;bass_func();audio_R();audio_L();}
   if(bass_reg<0){bass_print = (-bass_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{bass_print = bass_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");}
   a[0]= bass_print/10;a[1]=bass_print%10;
   for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();}
   lcd.Curs(0,0);lcd.PrintString("BASS");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB");
   } 
//////// BALANCE /////////////////////////////////////////////////////////////// 
 if(menu==3){ 
  if(newPosition != position){position = newPosition;ball = ball-newPosition;newPosition=0;w=1;w2=1;times=millis_times;ball_fun();audio_R();audio_L();}
   lcd.Curs(0,4);lcd.PrintString("   <>   ");lcd.Curs(1,4);lcd.PrintString("CHL  CHR");
   chl=(4+ball)-4;chr=(4-ball)-4;
   if(chl<0){lcd.Curs(0,12);chl=(-chl);lcd.PrintChar(2);}else{lcd.Curs(0,12);lcd.PrintString(" ");}
   if(chr<0){lcd.Curs(0,0);chr=(-chr);lcd.PrintChar(2);}else{lcd.Curs(0,0);lcd.PrintString(" ");}
   if(w2==1){w2=0;a[0]=chl;a[1]=chr;
   for(i=0;i<2;i++){
      switch(i){
        case 0: e1=1,e2=2,e3=3;break;
        case 1: e1=13,e2=14,e3=15;break;
        }
      switch(a[i]){
       case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break;
       case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break;
       case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break;
       case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break;
       case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break;
       }
      char_lcd();
 }}}  
 ////////////// INPUT GAIN ///////////////////////////////////////////////////////////////////
 if(menu==4){
  switch(in_reg){
     case 0: gain0 = gain1;break;
     case 1: gain0 = gain2;break;
     case 2: gain0 = gain3;break;
     case 3: gain0 = gain4;break;}
  if(newPosition != position){position = newPosition;gain0 = gain0-newPosition;newPosition=0;w=1;times=millis_times;www=1;gain_func();}
  switch(in_reg){
     case 0: gain1 = gain0;break;
     case 1: gain2 = gain0;break;
     case 2: gain3 = gain0;break;
     case 3: gain4 = gain0;break;}  
   gain0_print = gain0*2;
   a[0]= gain0_print/10;a[1]=gain0_print%10;
   for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();}
   if(www==1){audio_R();audio_L();www=0;}
   lcd.Curs(0,0);lcd.PrintString("IN GAIN");lcd.Curs(0,14);lcd.PrintString("dB");
   lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1);}

////////////////// EEPROM //////////////////////////////////////////////////////////////
 if(millis_times-times>10 && w==1 && mute_reg==0){
     EEPROM_write(0,vol_reg);EEPROM_write(1,treb_reg+5);EEPROM_write(2,bass_reg+10);EEPROM_write(4,gain1);
     EEPROM_write(5,gain2);EEPROM_write(6,gain3);EEPROM_write(7,gain4);EEPROM_write(8,gain5);
     EEPROM_write(9,in_reg);EEPROM_write(10,ball+4);
     if(menu!=0){lcd.Clear();menu=0;}w=0;}               
 
}}// end while


ISR(TIMER1_COMPA_vect){millis_times++;}

void digit(){switch(a[x]){
case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break;
case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break;
case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break;
case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break;
case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break;}
char_lcd();}

void char_lcd(){
  lcd.Curs(0,e1);lcd.PrintChar(d1);lcd.Curs(0,e2);lcd.PrintChar(d2);lcd.Curs(0,e3);lcd.PrintChar(d3);
  lcd.Curs(1,e1); lcd.PrintChar(d4);lcd.Curs(1,e2);lcd.PrintChar(d5);lcd.Curs(1,e3);lcd.PrintChar(d6);
  }

void vol_func(){if(vol_reg<4){vol_reg=4;}if(vol_reg>79){vol_reg=79;}}
void gain_func(){{if(gain0<0){gain0=0;}if(gain0>15){gain0=15;}}}
void ball_fun(){if(ball>4){ball=4;}if(ball<-4){ball=-4;}} 
void bass_func(){if(bass_reg<-10){bass_reg=-10;}if(bass_reg>10){bass_reg=10;}}
void treb_func(){if(treb_reg<-5){treb_reg=-5;}if(treb_reg>5){treb_reg=5;}}
void cl(){_delay_ms(300);lcd.Clear();}   

ISR(PCINT2_vect){ 
  bool pinA = ((PIND >> DT) & 1);
  bool pinB = ((PIND >> CLK) & 1);
   _currValueAB  = (pinA << 1) | pinB;
   switch(_prevValueAB | _currValueAB){
    case 0b0001: newPosition++;break;
    case 0b0100: newPosition--;break;
  }
  _prevValueAB = _currValueAB << 2;     
  }     

void addr(){
    PORTD &=~(1<<CL)|(1<<CE);
    byte addr = 0b01000001;
  for(int i = 7; i >= 0; i--){
    PORTD &=~(1<<CL);
    if(((addr>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
    PORTD |=(1<<CL);
} 
    PORTD |=(1<<CE);  
}
  
void set_input(byte in){
    for(int i = 0; i <= 3; i++){
       PORTD &=~(1<<CL);
    switch(i){
       case 0: if(((in & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 1: if(((in & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 2: if(((in & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 3: if(((in & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
} 
       PORTD |=(1<<CL);
}
}  

void set_gain(byte gain){
    for(int i = 0; i <= 3; i++){
       PORTD &=~(1<<CL);
    switch(i){
       case 0: if(((gain & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 1: if(((gain & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 2: if(((gain & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 3: if(((gain & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
} 
       PORTD |=(1<<CL);
}
}

void set_volume(byte vol){
    for(int i = 0; i <= 7; i++){
       PORTD &=~(1<<CL);
    switch(i){
       case 0: if(((vol & 0b00000001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 1: if(((vol & 0b00000010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 2: if(((vol & 0b00000100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 3: if(((vol & 0b00001000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 4: if(((vol & 0b00010000)>>4)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 5: if(((vol & 0b00100000)>>5)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 6: if(((vol & 0b01000000)>>6)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 7: if(((vol & 0b10000000)>>7)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;        
} 
       PORTD |=(1<<CL);
}
}

void set_treble(int treb){
      switch(treb){
        case 5:  treb = 0b1010;break;//10dB
        case 4:  treb = 0b0010;break;//8dB
        case 3:  treb = 0b1100;break;//6dB
        case 2:  treb = 0b0100;break;//4dB
        case 1:  treb = 0b1000;break;//2dB
        case 0:  treb = 0b0000;break;//0dB
        case -1: treb = 0b1001;break;//-2dB
        case -2: treb = 0b0101;break;//-4dB
        case -3: treb = 0b1101;break;//-6dB
        case -4: treb = 0b0011;break;//-8dB
        case -5: treb = 0b1011;break;//10dB
        }
      for(int i = 3; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((treb>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
}

void set_bass(int bass){
      switch(bass){
        case 10:  bass = 0b010100;break;//20dB
        case 9 :  bass = 0b100100;break;//18dB
        case 8 :  bass = 0b000100;break;//16dB
        case 7 :  bass = 0b111000;break;//14dB
        case 6 :  bass = 0b011000;break;//12dB
        case 5 :  bass = 0b101000;break;//10dB   
        case 4 :  bass = 0b001000;break;//8dB  
        case 3 :  bass = 0b110000;break;//6dB 
        case 2 :  bass = 0b010000;break;//4dB  
        case 1 :  bass = 0b101000;break;//2dB
        case 0 :  bass = 0b000000;break;//0dB
        case -1:  bass = 0b100010;break;//-2dB
        case -2:  bass = 0b010010;break;//-4dB
        case -3:  bass = 0b110010;break;//-6dB
        case -4:  bass = 0b001010;break;//-8dB
        case -5:  bass = 0b101010;break;//-10dB
        case -6:  bass = 0b011010;break;//-12dB
        case -7:  bass = 0b111010;break;//-14dB
        case -8:  bass = 0b000110;break;//-16dB
        case -9:  bass = 0b100110;break;//-18dB
        case -10: bass = 0b010110;break;//-20dB
        }
      for(int i = 5; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((bass>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
}

void set_ch(byte ch){
      switch(ch){
        case 1: ch = 0b01;break;
        case 2: ch = 0b10;break;
        case 3: ch = 0b11;break;
      }
      for(int i = 1; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((ch>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
}

void test(){
      byte test = 0;
      for(int i = 3; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((test>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
      PORTD &=~(1<<CL);
      PORTD &=~(1<<CE); 
}

void audio_L(){
  addr();
  set_input(0);   // input 1...4 = byte 0...3 (byte 4...7 = All switches off)
  set_gain(gain0);    // gain 0...30 dB step 2 dB = byte 0...15
  set_volume(vol_reg-ball);  // volume 0...-79 dB = byte 0...79
  set_treble(treb_reg);  // treble 10...-10 dB step 2 dB = int 5...-5 
  set_bass(bass_reg);    // bass 20...-20 dB step 2 dB = int 10...-10
  set_ch(1);      // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 
  test();
  }

void audio_R(){
  addr();
  set_input(0);   // input 1...4 = byte 0...3 (byte 4...7 = All switches off)
  set_gain(gain0);    // gain 0...30 dB step 2 dB = byte 0...15
  set_volume(vol_reg+ball);  // volume 0...-79 dB = byte 0...79
  set_treble(treb_reg);  // treble 10...-10 dB step 2 dB = int 5...-5 
  set_bass(bass_reg);    // bass 20...-20 dB step 2 dB = int 10...-10
  set_ch(2);      // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 
  test();
  } 

unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));  // проверка готовности EEPROM 
    EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
    EEARL = uiAddress & 0x0F; // регистр адреса L
    EECR |= (1<<EERE);// чтение EEPROM
    return EEDR; // вывод значения
}
 
void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
  while(EECR & (1<<EEPE)); // проверка готовности EEPROM 
    EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
    EEARL = uiAddress & 0x0F; // регистр адреса L
    EEDR = ucData; // регистр данных 
    EECR |= (1<<EEMPE);// Разрешение записи в EEPROM
    EECR |= (1<<EEPE); // Запись в EEPROM
}  
    

2

Re: Регулятор громкости и тембра LC75342 на Atmega88 (Arduino IDE)

Добавлен ИК пульт

http://forum.rcl-radio.ru/uploads/images/2022/03/ac7ef2384434433292ce106f35ca8328.gif

//  ATMEGA88 12 MHz
#define IR2 0x33B820DF // button encoder
#define IR3 0x33B8946B // mute
#define IR4 0x33B810EF // >>>
#define IR5 0x33B8E01F // <<<
#define IR6 0x33B844BB // INPUT

#define CE    PD0
#define DI    PD1
#define CL    PD2

#define DT    PD5
#define CLK   PD6
#define SW    PD7

#define IN    PB1
#define MUTE  PB2

#define IR_IN PC3


#include <avr/io.h>
#include <util/delay.h>
#include <Wire_low.h>         // http://forum.rcl-radio.ru/viewtopic.php?pid=5521#p5521
#include <Lcd1602_i2c_low.h>  // http://rcl-radio.ru/wp-content/uploads/2022/03/Lcd1602_i2c_low.zip
Lcd1602_i2c_low lcd(0x27);// адрес I2C

volatile uint8_t _prevValueAB = 0;    
volatile uint8_t _currValueAB = 0;
volatile int16_t newPosition = 0;
int position = -999;

int menu,vol_reg,mute_reg,in_reg,vol_old,treb_reg,treb_print,bass_reg,bass_print,ball,chl,chr,i;
byte a[6],d1,d2,d3,d4,d5,d6,e1,e2,e3,w,w2,x,www,gr1,gr2;
int gain0,gain1,gain2,gain3,gain4,gain5,gain0_print;
unsigned long millis_times,times,data_ir,d_ir;

bool data[96],st,st1,raz;
uint32_t cod;
byte i1,i2,s;


int main(){ 
  cli();
////////// TIMER_2  
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;
// (12000000/((186+1)x64))=1002.6737967914 Hz
  OCR2A = 186;
  TCCR2A |= (1 << WGM21);
// Prescaler 64
  TCCR2B |= (1 << CS22);
  TIMSK2 |= (1 << OCIE2A);
////////// TIMER_1
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
// (12000000/((6749+1)x1)) = 562.5 mks
  OCR1A = 6749;
  TCCR1B |= (1 << WGM12);
// Prescaler 1
  TCCR1B |= (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);  
  sei();
  wire_set(12000000,100000); // тактовая частота контроллера, частота шины I2C
  lcd.setInit();
  lcd.Clear(); // очистка экрана
  lcd.led(1);  // включение и отключение подсветки экрана
  lcd.Write(0,    0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111);
  lcd.Write(1,    0b00111,0b00111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000);
  lcd.Write(2,    0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111);
  lcd.Write(3,    0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111);
  lcd.Write(4,    0b11100,0b11100,0b00000,0b00000,0b00000,0b00000,0b11100,0b11100);
  lcd.Write(5,    0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100);
  lcd.Write(6,    0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00111,0b00111);
  lcd.Write(7,    0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000);
  DDRD |=(1<<CE)|(1<<DI)|(1<<CL);
  PORTD &=~(1<<CE)|(1<<DI)|(1<<CL);
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT21)|(1 << PCINT22); 
  PORTB |=(1<<IN)|(1<<MUTE);
  if(EEPROM_read(100)!=0){for(int i=0;i<101;i++){EEPROM_write(i,0);}}// очистка памяти при первом включении  
  vol_reg = EEPROM_read(0);treb_reg = EEPROM_read(1)-5;bass_reg = EEPROM_read(2)-10;gain1 = EEPROM_read(4);
  gain2 = EEPROM_read(5);gain3 = EEPROM_read(6);gain4 = EEPROM_read(7);gain5 = EEPROM_read(8);
  in_reg = EEPROM_read(9);ball = EEPROM_read(10)-4;
    switch(in_reg){
     case 0: gain0 = gain1;break;
     case 1: gain0 = gain2;break;
     case 2: gain0 = gain3;break;
     case 3: gain0 = gain4;break;
     }
  audio_L();
  audio_R();
            
   
while(1){
/// IR READ    
 if(raz==1){d_ir=IR();}  
    
/// BUTTON ///////////////////////////////////  
  if(mute_reg==0){  
    if(((PIND >> SW) & 1)==0||d_ir==IR2){menu++;d_ir=0;cl();w2=1;w=1;times=millis_times;if(menu>3){menu=0;}}
    if(((PINB >> IN) & 1)==0||d_ir==IR6){in_reg++;d_ir=0;menu=4;cl();w=1;times=millis_times;if(in_reg>3){in_reg=0;}}
    }
    if((((PINB >> MUTE) & 1)==0||d_ir==IR3)&&mute_reg==0){mute_reg=1;d_ir=0;menu=100;cl();w=1;times=millis_times;vol_old=vol_reg;vol_reg=79;audio_R();audio_L();lcd.Curs(0,6);lcd.PrintString("MUTE");}
    if((((PINB >> MUTE) & 1)==0||d_ir==IR3)&&mute_reg==1){mute_reg=0;d_ir=0;menu=0;cl();w=1;times=millis_times;vol_reg=vol_old;audio_R();audio_L();}

////////////// VOLUME ///////////////////////////////////////////////////////////////////
 if(menu==0){
   if(d_ir==IR5){vol_reg++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка > 
   if(d_ir==0xFFFFFFFF and gr1==1){vol_reg++;gr2=0;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка >>>>>>
   if(d_ir==IR4){vol_reg--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка <
   if(d_ir==0xFFFFFFFF and gr2==1){vol_reg--;gr1=0;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка <<<<<<
  
  if(newPosition != position){position = newPosition;vol_reg = vol_reg+newPosition;newPosition=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}
   a[0]= (79-vol_reg)/10;a[1]=(79-vol_reg)%10;
  for(x=0;x<2;x++){switch(x){case 0: e1=10,e2=11,e3=12;break;case 1: e1=13,e2=14,e3=15;break;}digit();}
  if(mute_reg==0){lcd.Curs(0,0);lcd.PrintString("VOLUME");}else{lcd.Curs(0,0);lcd.PrintString("MUTE");}
   lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1);
}
////////////// TREBLE ///////////////////////////////////////////////////////////////////
 if(menu==1){
   if(d_ir==IR4){treb_reg++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;treb_func();audio_R();audio_L();}// кнопка > 
   if(d_ir==IR5){treb_reg--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;treb_func();audio_R();audio_L();}// кнопка <
  
  if(newPosition != position){position = newPosition;treb_reg = treb_reg-newPosition;newPosition=0;w=1;times=millis_times;treb_func();audio_R();audio_L();}
   if(treb_reg<0){treb_print = (-treb_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{treb_print = treb_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");}
   a[0]= treb_print/10;a[1]=treb_print%10;
   for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();}
   lcd.Curs(0,0);lcd.PrintString("TREBLE");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB");
   } 
////////////// BASS ///////////////////////////////////////////////////////////////////
 if(menu==2){
   if(d_ir==IR4){bass_reg++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;bass_func();audio_R();audio_L();}// кнопка > 
   if(d_ir==IR5){bass_reg--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;bass_func();audio_R();audio_L();}// кнопка <
  
  if(newPosition != position){position = newPosition;bass_reg = bass_reg-newPosition;newPosition=0;w=1;times=millis_times;bass_func();audio_R();audio_L();}
   if(bass_reg<0){bass_print = (-bass_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{bass_print = bass_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");}
   a[0]= bass_print/10;a[1]=bass_print%10;
   for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();}
   lcd.Curs(0,0);lcd.PrintString("BASS");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB");
   } 
//////// BALANCE /////////////////////////////////////////////////////////////// 
 if(menu==3){ 
   if(d_ir==IR4){ball++;gr1=1;gr2=0;d_ir=0;w2=1;w=1;times=millis_times;ball_fun();audio_R();audio_L();}// кнопка > 
   if(d_ir==IR5){ball--;gr1=0;gr2=1;d_ir=0;w2=1;w=1;times=millis_times;ball_fun();audio_R();audio_L();}// кнопка <
  
  if(newPosition != position){position = newPosition;ball = ball-newPosition;newPosition=0;w=1;w2=1;times=millis_times;ball_fun();audio_R();audio_L();}
   lcd.Curs(0,4);lcd.PrintString("   <>   ");lcd.Curs(1,4);lcd.PrintString("CHL  CHR");
   chl=(4+ball)-4;chr=(4-ball)-4;
   if(chl<0){lcd.Curs(0,12);chl=(-chl);lcd.PrintChar(2);}else{lcd.Curs(0,12);lcd.PrintString(" ");}
   if(chr<0){lcd.Curs(0,0);chr=(-chr);lcd.PrintChar(2);}else{lcd.Curs(0,0);lcd.PrintString(" ");}
   if(w2==1){w2=0;a[0]=chl;a[1]=chr;
   for(i=0;i<2;i++){
      switch(i){
        case 0: e1=1,e2=2,e3=3;break;
        case 1: e1=13,e2=14,e3=15;break;
        }
      switch(a[i]){
       case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break;
       case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break;
       case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break;
       case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break;
       case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break;
       }
      char_lcd();
 }}}  
 ////////////// INPUT GAIN ///////////////////////////////////////////////////////////////////
 if(menu==4){
  switch(in_reg){
     case 0: gain0 = gain1;break;
     case 1: gain0 = gain2;break;
     case 2: gain0 = gain3;break;
     case 3: gain0 = gain4;break;}

  if(d_ir==IR4){gain0++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;gain_func();audio_R();audio_L();}// кнопка > 
  if(d_ir==IR5){gain0--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;gain_func();audio_R();audio_L();}// кнопка <  
     
  if(newPosition != position){position = newPosition;gain0 = gain0-newPosition;newPosition=0;w=1;times=millis_times;www=1;gain_func();}
  switch(in_reg){
     case 0: gain1 = gain0;break;
     case 1: gain2 = gain0;break;
     case 2: gain3 = gain0;break;
     case 3: gain4 = gain0;break;}  
   gain0_print = gain0*2;
   a[0]= gain0_print/10;a[1]=gain0_print%10;
   for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();}
   if(www==1){audio_R();audio_L();www=0;}
   lcd.Curs(0,0);lcd.PrintString("IN GAIN");lcd.Curs(0,14);lcd.PrintString("dB");
   lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1);}

////////////////// EEPROM //////////////////////////////////////////////////////////////
 if(millis_times-times>10000 && w==1 && mute_reg==0){
     EEPROM_write(0,vol_reg);EEPROM_write(1,treb_reg+5);EEPROM_write(2,bass_reg+10);EEPROM_write(4,gain1);
     EEPROM_write(5,gain2);EEPROM_write(6,gain3);EEPROM_write(7,gain4);EEPROM_write(8,gain5);
     EEPROM_write(9,in_reg);EEPROM_write(10,ball+4);
     if(menu!=0){lcd.Clear();menu=0;}w=0;}               
}}// end while

ISR(TIMER1_COMPA_vect){
     if(((PINC >> IR_IN) & 1)==0&&st==0&&raz==0){st=1;OCR1A = 6749;}
     if(st==1){s++;}
     if(s>20&&((PINC >> IR_IN) & 1)==0){st1=1;}   
     if(st1==1){data[i1]=((PINC >> IR_IN) & 1);i1++;} 
     if(i1>96){i1=0;s=0;st=0;raz=1;st1=0;TCCR1B &= ~(1 << CS10); }
     }
ISR(TIMER2_COMPA_vect){millis_times++;}

uint32_t IR(){
 _delay_ms(100);
 cod=0;i2=0;
 for(int ai=0;ai<96;ai++){
   if(data[ai] + data[ai+2] == 2){cod += ((uint32_t)0 << 31-i2);i2++;ai=ai+1;}
   if(data[ai] + data[ai+2] == 1){cod += ((uint32_t)1 << 31-i2);i2++;ai=ai+3;}}
 raz=0;
 TCCR1B |= (1 << CS10);OCR1A = 239;//50000 kHz
 if(cod==1||cod>0x7fffffff){cod=0xFFFFFFFF;}
 return cod;}

void digit(){switch(a[x]){
case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break;
case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break;
case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break;
case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break;
case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break;}
char_lcd();}

void char_lcd(){
  lcd.Curs(0,e1);lcd.PrintChar(d1);lcd.Curs(0,e2);lcd.PrintChar(d2);lcd.Curs(0,e3);lcd.PrintChar(d3);
  lcd.Curs(1,e1); lcd.PrintChar(d4);lcd.Curs(1,e2);lcd.PrintChar(d5);lcd.Curs(1,e3);lcd.PrintChar(d6);
  }

void vol_func(){if(vol_reg<4){vol_reg=4;}if(vol_reg>79){vol_reg=79;}}
void gain_func(){{if(gain0<0){gain0=0;}if(gain0>15){gain0=15;}}}
void ball_fun(){if(ball>4){ball=4;}if(ball<-4){ball=-4;}} 
void bass_func(){if(bass_reg<-10){bass_reg=-10;}if(bass_reg>10){bass_reg=10;}}
void treb_func(){if(treb_reg<-5){treb_reg=-5;}if(treb_reg>5){treb_reg=5;}}
void cl(){_delay_ms(200);lcd.Clear();}   

ISR(PCINT2_vect){ 
  bool pinA = ((PIND >> DT) & 1);
  bool pinB = ((PIND >> CLK) & 1);
   _currValueAB  = (pinA << 1) | pinB;
   switch(_prevValueAB | _currValueAB){
    case 0b0001: newPosition++;break;
    case 0b0100: newPosition--;break;
  }
  _prevValueAB = _currValueAB << 2;     
  }     

void addr(){
    PORTD &=~(1<<CL)|(1<<CE);
    byte addr = 0b01000001;
  for(int i = 7; i >= 0; i--){
    PORTD &=~(1<<CL);
    if(((addr>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
    PORTD |=(1<<CL);
} 
    PORTD |=(1<<CE);  
}
  
void set_input(byte in){
    for(int i = 0; i <= 3; i++){
       PORTD &=~(1<<CL);
    switch(i){
       case 0: if(((in & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 1: if(((in & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 2: if(((in & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 3: if(((in & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
} 
       PORTD |=(1<<CL);
}
}  

void set_gain(byte gain){
    for(int i = 0; i <= 3; i++){
       PORTD &=~(1<<CL);
    switch(i){
       case 0: if(((gain & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 1: if(((gain & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 2: if(((gain & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 3: if(((gain & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
} 
       PORTD |=(1<<CL);
}
}

void set_volume(byte vol){
    for(int i = 0; i <= 7; i++){
       PORTD &=~(1<<CL);
    switch(i){
       case 0: if(((vol & 0b00000001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 1: if(((vol & 0b00000010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 2: if(((vol & 0b00000100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 3: if(((vol & 0b00001000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 4: if(((vol & 0b00010000)>>4)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 5: if(((vol & 0b00100000)>>5)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 6: if(((vol & 0b01000000)>>6)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;
       case 7: if(((vol & 0b10000000)>>7)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break;        
} 
       PORTD |=(1<<CL);
}
}

void set_treble(int treb){
      switch(treb){
        case 5:  treb = 0b1010;break;//10dB
        case 4:  treb = 0b0010;break;//8dB
        case 3:  treb = 0b1100;break;//6dB
        case 2:  treb = 0b0100;break;//4dB
        case 1:  treb = 0b1000;break;//2dB
        case 0:  treb = 0b0000;break;//0dB
        case -1: treb = 0b1001;break;//-2dB
        case -2: treb = 0b0101;break;//-4dB
        case -3: treb = 0b1101;break;//-6dB
        case -4: treb = 0b0011;break;//-8dB
        case -5: treb = 0b1011;break;//10dB
        }
      for(int i = 3; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((treb>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
}

void set_bass(int bass){
      switch(bass){
        case 10:  bass = 0b010100;break;//20dB
        case 9 :  bass = 0b100100;break;//18dB
        case 8 :  bass = 0b000100;break;//16dB
        case 7 :  bass = 0b111000;break;//14dB
        case 6 :  bass = 0b011000;break;//12dB
        case 5 :  bass = 0b101000;break;//10dB   
        case 4 :  bass = 0b001000;break;//8dB  
        case 3 :  bass = 0b110000;break;//6dB 
        case 2 :  bass = 0b010000;break;//4dB  
        case 1 :  bass = 0b101000;break;//2dB
        case 0 :  bass = 0b000000;break;//0dB
        case -1:  bass = 0b100010;break;//-2dB
        case -2:  bass = 0b010010;break;//-4dB
        case -3:  bass = 0b110010;break;//-6dB
        case -4:  bass = 0b001010;break;//-8dB
        case -5:  bass = 0b101010;break;//-10dB
        case -6:  bass = 0b011010;break;//-12dB
        case -7:  bass = 0b111010;break;//-14dB
        case -8:  bass = 0b000110;break;//-16dB
        case -9:  bass = 0b100110;break;//-18dB
        case -10: bass = 0b010110;break;//-20dB
        }
      for(int i = 5; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((bass>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
}

void set_ch(byte ch){
      switch(ch){
        case 1: ch = 0b01;break;
        case 2: ch = 0b10;break;
        case 3: ch = 0b11;break;
      }
      for(int i = 1; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((ch>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
}

void test(){
      byte test = 0;
      for(int i = 3; i >= 0; i--){
        PORTD &=~(1<<CL);
        if(((test>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);}
        PORTD |=(1<<CL);
        }
      PORTD &=~(1<<CL);
      PORTD &=~(1<<CE); 
}

void audio_L(){
  addr();
  set_input(0);   // input 1...4 = byte 0...3 (byte 4...7 = All switches off)
  set_gain(gain0);    // gain 0...30 dB step 2 dB = byte 0...15
  set_volume(vol_reg-ball);  // volume 0...-79 dB = byte 0...79
  set_treble(treb_reg);  // treble 10...-10 dB step 2 dB = int 5...-5 
  set_bass(bass_reg);    // bass 20...-20 dB step 2 dB = int 10...-10
  set_ch(1);      // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 
  test();
  }

void audio_R(){
  addr();
  set_input(0);   // input 1...4 = byte 0...3 (byte 4...7 = All switches off)
  set_gain(gain0);    // gain 0...30 dB step 2 dB = byte 0...15
  set_volume(vol_reg+ball);  // volume 0...-79 dB = byte 0...79
  set_treble(treb_reg);  // treble 10...-10 dB step 2 dB = int 5...-5 
  set_bass(bass_reg);    // bass 20...-20 dB step 2 dB = int 10...-10
  set_ch(2);      // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 
  test();
  } 

unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));  // проверка готовности EEPROM 
    EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
    EEARL = uiAddress & 0x0F; // регистр адреса L
    EECR |= (1<<EERE);// чтение EEPROM
    return EEDR; // вывод значения
}
 
void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
  while(EECR & (1<<EEPE)); // проверка готовности EEPROM 
    EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H
    EEARL = uiAddress & 0x0F; // регистр адреса L
    EEDR = ucData; // регистр данных 
    EECR |= (1<<EEMPE);// Разрешение записи в EEPROM
    EECR |= (1<<EEPE); // Запись в EEPROM
}