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

Микроконтроллер Atmega88 может стать отличной заменой сильно подорожавших плат Arduino Nano. Большое кол-во проектов создаваемых на платах Arduino Nano часто используют небольшое объем памяти и применять Arduino Nano в данных проектах нецелесообразно.  Atmega88 имеет 8 кБ программируемой Flash памяти, 1кБ SRAM памяти и 512 байта EEPROM.

Микроконтроллер Atmega88 поддерживается средой программирования Arduino IDE, так же большинство библиотек совместимы с этими контроллерами.

Ранее в http://rcl-radio.ru/?p=120507 рассматривался пример создания регулятора громкости и тембра на LC75342 с использованием платы Arduino Nano, на этой странице будет аналогичный проект, но с использованием микроконтроллера Atmega88.

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

Более подробно об аудиопроцессоре можно узнать из статьи — LC75342 (Arduino)

Основные параметры LC75342

  • Регулировка громкости от -79 до 0 дБ (шаг 1 дБ)
  • Независимая регулировка громкости (баланс)
  • Входной предварительный усилитель входа от 0 до +30 дБ (шаг 2 дБ)
  • 4-х канальный коммутатор входов
  • Регулировка тембра BASS от -20 до +20 дБ (шаг 2 дБ)
  • Регулировка тембра TREBLE от -10 до +10 дБ (шаг 2 дБ)
  • Напряжение питания от 5 до 10 В
  • Управление цифровое 3-Wire (CL, DI, CE) (макс. тактовая частота до 500 кГц)
  • Входное сопротивление 50 кОм
  • Коэффициент нелинейных искажений 0,01% (макс.)

Регулятор громкости содержит два основных блока, первый блок микроконтроллерный (Arduino Nano) с органами управления и индикации, второй блок плата аудиопроцессора.

Регулировка громкости возможна в пределах от -79 до -4 дБ, недостающие 4 дБ отданы регулятору баланса.

Основное управление параметрами аудиопроцессора будет осуществляться при помощи энкодера (KY-040) и 2-х кнопок. Вся информация будет выводится на дисплей LCD1602 + I2C (I2C модуль на базе микросхем PCF8574 позволяют подключить символьный дисплей 1602 к плате Arduino всего по двум проводам SDA и SCL (А4 и А5), что дает возможность не использовать цифровые выходы Arduino при подключении дисплея.)

Регулятор тембра имеет одно меню, которое содержит регуляторы громкости, тембра (TRABLE, BASS) и баланса. Дополнительно при нажатии кнопки INPUT помимо переключения входа будет доступно меню предусилителя входа. (независимое для каждого входа).

Схема регулятора громкости и тембра

Как добавить микроконтроллер Atmega88 в среду программирования Arduino IDE и прошивать микроконтроллер можно узнать из статьи http://rcl-radio.ru/?p=113040.

Перед загрузкой в настройках платы укажите частоту кварцевого резонатора (12 МГц), выбрать программатор  USBasp, в пункте Variant тип контроллера 88P/88PA, 88/88A (для Atmega88 20PU который я используя для этой статьи) или 88PB, в пункте Bootloader выберите No bootloader или Yes (UART0) если планируете загружать скетчи через UART ( USB — TTL ).

Во вкладке «Инструменты»  нажмите «Записать загрузчик«.(делается только один раз)

Для запуска LCD1602 c I2C модулем на PCF8574, Вам понадобятся две библиотеки:

  • Wire_low — библиотека для работы с шиной I2C (тестовая версия)
  • Lcd1602_i2c_low — библиотека для работы с LCD1602 I2C на PCF8574
//  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
}

Скетч использует 5738 байт (70%) памяти устройства. Всего доступно 8192 байт.
Глобальные переменные используют 141 байт (13%) динамической памяти, оставляя 883 байт для локальных переменных. Максимум: 1024 байт.


Доработка

В проект регулятора громкости и тембра на LC75342 добавлен ИК пульт.

ИК пульт дублирует работу энкодера и кнопок. Для управления регулятором подойдет практически любой пульт ИК, для поддержки Вашего пульта необходимо прописать коды кнопок в скетч:

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

Так как проект не использует интерфейс UART, то получение кода кнопок через монитор порта не возможно, поэтому ниже показан скетч который позволяет получить коды кнопок выводя их на LCD1602_I2C. ИК датчик подключается к пину 26 (PC3) микроконтроллера Atmega88.

#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
 
bool data[96],st,st1,raz;
uint32_t cod;
byte i1,i2,s;
unsigned long data_ir;
 
int main(){
  wire_set(12000000,100000); // тактовая частота контроллера, частота шины I2C
  lcd.setInit();
  lcd.Clear(); // очистка экрана
  lcd.led(1);  // включение и отключение подсветки экрана
  ////////// 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();
 
 
while(1){  
    lcd.Curs(0,0);
    lcd.PrintString("IR_CODE");
 if(raz==1){
    lcd.Clear();
    data_ir = IR();
    String stringVar = String(data_ir, HEX);
    char charVar[10];
    stringVar.toCharArray(charVar, 10);
    lcd.Curs(1,0);
    lcd.PrintString(charVar);
    _delay_ms(200);
    }
 
  }}
 
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); }
     }
 
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;}

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

//  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
}

Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=5542#p5542

Добавить комментарий

Войти с помощью: