R2A15908SP — стерео аудиопроцессор (Arduino)

R2A15908SP — простой но высококачественный аудиопроцессор с микроконтроллерным управлением (I2C).

Основные характеристики аудиопроцессора R2A15908SP:

  • Регулировка громкости от -87 до 0 дБ (шаг 1 дБ)
  • 5-и канальный коммутатор входов
  • Режим MUTE
  • Независимый для каждого входа предусилитель с диапазоном регулировки от 0 до 20 дБ (шаг 2 дБ)
  • Регуляторы тембра ВЧ и НЧ с диапазоном регулировки от -14 до +14 дБ (шаг 2 дБ)
  • Режимы: Surround Low / High
  • Напряжение питания от 4,75 до 9,7 В (9 В — рекомендуемое)
  • Ток потребления 15 мА
  • Максимальное входное напряжение 2,5 Vrms
  • Коэффициент нелинейных искажений 0.01 %
  • Разделение каналов 100 дБ

Тестовый скетч:

#include <Wire.h> 
#include <R2A15908SP.h> // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=765&download=1
R2A15908SP ra;
 
void setup(){
   audio();
  delay(1000);
  }
 
void loop(){}
 
void audio(){
  ra.setVolume_left(80); // -87...0 dB === int 0...87
  ra.setVolume_right(80);// -87...0 dB === int 0...87 
  ra.setIn_Gain(0,0);    // IN 1...5 === byte 0...4 /// int 7 === mute
                         // GAIN 0...20 dB step 2 dB === int 0...10
  ra.setStereo(0,1);     // 0 = stereo / 1 = Lch / 2 = Rch
                         // 0 = bypass / 1 = tone / 2 = tone&surround_hi / 3 = tone&surround_low
  ra.setTone(0,0);     // bass and treb -14...14 dB step 2 dB === int -7...7
  }

На R2A15908SP совместно с Arduino Nano можно собрать простой регулятор громкости и тембра. Для управления регулятором будет использоваться энкодер KY-040 и ИК-датчик для управления функциями регулятора при помощи ИК пульта. Вся информация о состоянии регулятора будет выводится на LCD дисплей 1602 (I2C).

Меню регулятора состоит 6-и категорий:

Регулировка громкости

Регулировка НЧ

Регулировка ВЧ

Регулировка баланса

Режим стерео/моно

Режим Tone & Surround

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

#define IR_1 0x2FDD02F // Кнопка вверх
#define IR_2 0x2FD32CD // Кнопка вниз
#define IR_3 0x2FD906F // Кнопка >
#define IR_4 0x2FDF20D // Кнопка <
#define IR_5 0x2FD708F // Кнопка IN
#define IR_6 0x2FD00FF // Кнопка POWER
#define IR_7 0x2FD2AD5 // Кнопка MUTE

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

Все изменяемые параметры регулятора записываются в энергонезависимую память.

#define IR_1 0x2FDD02F // Кнопка вверх
#define IR_2 0x2FD32CD // Кнопка вниз
#define IR_3 0x2FD906F // Кнопка >
#define IR_4 0x2FDF20D // Кнопка <
#define IR_5 0x2FD708F // Кнопка IN
#define IR_6 0x2FD00FF // Кнопка POWER
#define IR_7 0x2FD2AD5 // Кнопка MUTE
 
#include <Wire.h> 
#include <EEPROM.h>
#include <R2A15908SP.h>        // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=765&download=1
#include <boarddefs.h>
#include <IRremote.h>          // http://rcl-radio.ru/wp-content/uploads/2019/06/IRremote.zip
#include <Encoder.h>           // http://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip
#include <LiquidCrystal_I2C.h> // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
  R2A15908SP ra;
  Encoder myEnc(8, 9);//  D8, D9 = CLK, DT
  IRrecv irrecv(12);  //  D12 = IR
  decode_results ir; 
  LiquidCrystal_I2C lcd(0x27,16,2); // SDA, SCL
  byte a1[8] = {0b00000,0b10101,0b10101,0b10101,0b10101,0b10101,0b10101,0b00000};
  byte a2[8] = {0b00000,0b10100,0b10100,0b10100,0b10100,0b10100,0b10100,0b00000};
  byte a3[8] = {0b00000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b00000}; 
  unsigned long oldPosition  = -999,newPosition,times,times1;
  byte z,z0,z1,w,w2,power,gr1,gr2,in,in_old,xd,www,mute;
  int mode,menu,vol,menu_in,x,gain0,gain1,gain2,gain3,gain4,gain5,bas,treb,ball,stereo;
 
 
void setup(){
  Serial.begin(9600);
  pinMode(7,INPUT); // кнопка энкодера
  pinMode(13,OUTPUT); // выход управления Standby
  OCR2A = 200; TCCR1B |= (1 << WGM22)|(1 << CS20)|(1 << CS21); TIMSK2 |= (1 << OCIE2A); // timer2
  Wire.begin();lcd.init();lcd.backlight();irrecv.enableIRIn();
  lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
  lcd.setCursor(0,0);lcd.print(F("   R2A15908SP   "));
  delay(2000);lcd.clear();
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}
  vol = EEPROM.read(0);in = EEPROM.read(1);bas = EEPROM.read(2)-7;treb = EEPROM.read(3)-7;ball = EEPROM.read(4)-6;
  stereo = EEPROM.read(5);mode = EEPROM.read(6);
  gain1 = EEPROM.read(10);gain2 = EEPROM.read(11);gain3 = EEPROM.read(12);gain4 = EEPROM.read(13);gain5 = EEPROM.read(14);
  switch(in){
     case 0: gain0 = gain1;break;
     case 1: gain0 = gain2;break;
     case 2: gain0 = gain3;break;
     case 3: gain0 = gain4;break;
     case 4: gain0 = gain5;break;}
  audio();
  }
 
 
 
void loop(){
  if(power==0){digitalWrite(13,HIGH);}else{digitalWrite(13,LOW);}
  /////////////////// IR ///////////////////////////////////
 
  if ( irrecv.decode( &ir )) {Serial.print("0x");Serial.println( ir.value,HEX);irrecv.resume();times=millis();w=1;}// IR приемник - чтение, в мониторе порта отображаются коды кнопок
  if(ir.value==0){gr1=0;gr2=0;}// запрет нажатий не активных кнопок пульта
 
  if(power==0){
  if(ir.value==IR_2 && mute==0){menu++;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;if(menu>5){menu=0;}}// меню кнопка вверх 
  if(ir.value==IR_1 && mute==0){menu--;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;if(menu<0){menu=5;}}// меню кнопка вниз
 
  if(ir.value==IR_5){menu=0;in++;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;if(in>4){in = 0;}audio();}// IN
 
  if(ir.value==IR_7 && mute==0){mute=1;menu=100;;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;in_old=in;in=7;audio();lcd.setCursor(0,0);lcd.print(F("      MUTE      "));delay(300);}// MUTE
  if(ir.value==IR_7 && mute==1){mute=0;menu=0;;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;in=in_old;audio();delay(300);}// MUTE
  }
 
  if(ir.value==IR_6 && power==0){power=1;menu=100;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;in_old=in;in=7;audio();lcd.setCursor(0,0);lcd.print(F("   POWER OFF    "));delay(3000);lcd.noBacklight();}//  кнопка POWER OFF
  if(ir.value==IR_6 && power==1){power=0;menu=0;gr1=0;gr2=0;cl2();times=millis();w=1;w2=1;in=in_old;audio();lcd.setCursor(0,0);lcd.backlight();lcd.print(F("   POWER  ON    "));delay(1000);lcd.clear();}//  кнопка POWER OFF
 
 //////////////// INPUT MENU //////////////////////////////////////////////////////////
  if(power==0){
  if(digitalRead(7)==LOW && menu_in==0 && mute==0){x++;xd=1;delay(200);}
  if(digitalRead(7)==HIGH && menu_in==0 && x>0 && mute==0){xd=1;x=0;times=millis();times1=millis();w=1;w2=1;}
  if(x > 5){menu_in=1;lcd.clear();lcd.setCursor(0,0);lcd.print(F("   INPUT MENU    "));delay(1000);lcd.clear(); times1 = millis();}
  if(menu_in==1){menu=0;x=0;if(digitalRead(7)==LOW){times=millis();times1=millis();w=1;w2=1;in++;www=1;if(in>4){in = 0;}delay(200); }
  //gain
     switch(in){
     case 0: gain0 = gain1;break;
     case 1: gain0 = gain2;break;
     case 2: gain0 = gain3;break;
     case 3: gain0 = gain4;break;
     case 4: gain0 = gain5;break;}
     if (newPosition != oldPosition) {
    oldPosition = newPosition;
    gain0=gain0+newPosition;myEnc.write(0);newPosition=0;times=millis();times1=millis();w=1;w2=1;www=1;gain_func();audio();} 
   switch(in){
     case 0: gain1 = gain0;break;
     case 1: gain2 = gain0;break;
     case 2: gain3 = gain0;break;
     case 3: gain4 = gain0;break;
     case 4: gain5 = gain0;break;} 
    if(www==1){audio();www=0;}
    lcd.setCursor(5,1);lcd.print(" ");lcd.print(gain0*2);lcd.print(" ");lcd.setCursor(8,1);lcd.print(F(" dB"));
     // end gain
    lcd.setCursor(3,0);lcd.print(F("INPUT "));
    switch(in){
      case 0: lcd.print(F("AUX1"));break;
      case 1: lcd.print(F("AUX2"));break;
      case 2: lcd.print(F("AUX3"));break;
      case 3: lcd.print(F("AUX4"));break;
      case 4: lcd.print(F("AUX5"));break;}}  
  if(digitalRead(7)==HIGH && millis()-times1>3000 && menu_in==1){x=0;menu=-1;menu_in=0;times=millis();times1=millis();w=1;w2=1;lcd.clear();}
  if(digitalRead(7)==HIGH && xd == 1 && menu_in==0){menu++;times=millis();w=1;w2=1;xd=0;lcd.clear();if(menu>5){menu=0;}}
  }
  ///////////////// END INPUT MENU /////////////////////////////////////////////////////// 
 
 
 //////////////////// VOLUME /////////////////////////////////
 if(menu==0 && menu_in==0 && power==0){
     if(ir.value==IR_3){vol++;gr1=1;gr2=0;cl();times=millis();w=1;w2=1;vol_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){vol++;gr2=0;cl();times=millis();w=1;w2=1;vol_func();audio();}// кнопка >>>>>>
     if(ir.value==IR_4){vol--;gr1=0;gr2=1;cl();times=millis();w=1;w2=1;vol_func();audio();}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){vol--;gr1=0;cl();times=millis();w=1;w2=1;vol_func();audio();}// кнопка <<<<<<
 
   if (newPosition != oldPosition){oldPosition = newPosition;
     vol=vol+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w2=1;vol_func();audio();} 
     lcd.setCursor(0,0);lcd.print(F("VOLUME "));
     if(vol<10){lcd.setCursor(8,0);}else{lcd.setCursor(7,0);}lcd.print(" ");lcd.print(vol-12);lcd.print(" ");
     lcd.setCursor(12,0);
     switch(in){
      case 0: lcd.print(F("AUX1"));break;
      case 1: lcd.print(F("AUX2"));break;
      case 2: lcd.print(F("AUX3"));break;
      case 3: lcd.print(F("AUX4"));break;
      case 4: lcd.print(F("AUX5"));break;} 
 
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=map(vol, 12,87, 0, 48);z++,z1++){if(z1>2){z1=0;z0++;}
   if(z1==1){lcd.setCursor(z0,1);lcd.write((uint8_t)0);lcd.setCursor(z0+1,1);lcd.print(F("   "));}}
   if(z1==3){lcd.setCursor(z0,1);lcd.write((uint8_t)1);}
   if(z1==2){lcd.setCursor(z0,1);lcd.write((uint8_t)2);}w2=0;}}
 
 ///////////////////////// BASS +/-14 dB /////////////////////////////////////////////////////////
   if(menu==1){
     if(ir.value==IR_3){bas++;gr1=1;gr2=0;cl3();times=millis();w=1;w2=1;bass_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){bas++;gr2=0;cl3();times=millis();w=1;w2=1;bass_func();audio();}// кнопка >>>>>>
     if(ir.value==IR_4){bas--;gr1=0;gr2=1;cl3();times=millis();w=1;w2=1;bass_func();audio();}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){bas--;gr1=0;cl3();times=millis();w=1;w2=1;bass_func();audio();}// кнопка <<<<<<
 
   if (newPosition != oldPosition) {
    oldPosition = newPosition;
    bas=bas+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w2=1;bass_func();audio();} 
   lcd.setCursor(0,0);lcd.print(F("BASS    "));
   if(bas>=0){lcd.print(F("+"));}lcd.print(bas*2);lcd.print(" ");lcd.setCursor(13,0);lcd.print(F("dB"));
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=(bas*2+14+1);z++,z1++){if(z1>2){z1=0;z0++;}
   if(z1==1){lcd.setCursor(z0+3,1);lcd.write((uint8_t)0);lcd.setCursor(z0+1+3,1);lcd.print(F("   "));}}
   if(z1==3){lcd.setCursor(z0+3,1);lcd.write((uint8_t)1);}
   if(z1==2){lcd.setCursor(z0+3,1);lcd.write((uint8_t)2);}w2=0;}} 
  /////////////////////// END BASS //////////////////////////////////    
 
///////////////////////// TREBLE +/-14 dB /////////////////////////////////////////////////////////
   if(menu==2){
     if(ir.value==IR_3){treb++;gr1=1;gr2=0;cl3();times=millis();w=1;w2=1;treb_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){treb++;gr2=0;cl3();times=millis();w=1;w2=1;treb_func();audio();}// кнопка >>>>>>
     if(ir.value==IR_4){treb--;gr1=0;gr2=1;cl3();times=millis();w=1;w2=1;treb_func();audio();}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){treb--;gr1=0;cl3();times=millis();w=1;w2=1;treb_func();audio();}// кнопка <<<<<<
 
   if (newPosition != oldPosition) {
    oldPosition = newPosition;
    treb=treb+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w2=1;treb_func();audio();} 
   lcd.setCursor(0,0);lcd.print(F("TREBLE  "));
   if(treb>=0){lcd.print(F("+"));}lcd.print(treb*2);lcd.print(" ");lcd.setCursor(13,0);lcd.print(F("dB"));
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=(treb*2+14+1);z++,z1++){if(z1>2){z1=0;z0++;}
   if(z1==1){lcd.setCursor(z0+3,1);lcd.write((uint8_t)0);lcd.setCursor(z0+1+3,1);lcd.print(F("   "));}}
   if(z1==3){lcd.setCursor(z0+3,1);lcd.write((uint8_t)1);}
   if(z1==2){lcd.setCursor(z0+3,1);lcd.write((uint8_t)2);}w2=0;}} 
  /////////////////////// END TREBLE //////////////////////////////////
 
 ////////////////// BALANCE /////////////////////////////////////////////////////////////////
   if(menu==3){
     if(ir.value==IR_3){ball++;gr1=1;gr2=0;cl3();times=millis();w=1;w2=1;ball_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){ball++;gr2=0;cl3();times=millis();w=1;w2=1;ball_func();audio();}// кнопка >>>>>>
     if(ir.value==IR_4){ball--;gr1=0;gr2=1;cl3();times=millis();w=1;w2=1;ball_func();audio();}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){ball--;gr1=0;cl3();times=millis();w=1;w2=1;ball_func();audio();}// кнопка <<<<<<
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    ball=ball+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w2=1;ball_func();audio();} 
  lcd.setCursor(0,0);
   if(ball>=0){lcd.print("-");}else{lcd.print("+");}
  lcd.print(abs(ball));lcd.print(" dB ");
  lcd.print(" <>  ");
   if(ball>=0){lcd.print("+");}else{lcd.print("-");}
  lcd.print(abs(ball));lcd.print(" dB ");
  if(w2==1){lcd.setCursor(ball+5,1);lcd.print(F("   "));
  if(ball==0){lcd.setCursor(ball+7,1);lcd.write((uint8_t)0);lcd.write((uint8_t)0);}
  if(ball>0){ lcd.setCursor(ball+8,1);lcd.write((uint8_t)0);}
  if(ball<0){ lcd.setCursor(ball+7,1);lcd.write((uint8_t)0);}
  lcd.print(F("   "));w2=0;}} 
 
 
/////////////// Stereo / Mono //////////////////////////
  if(menu==4){
     if(ir.value==IR_3){stereo++;gr1=1;gr2=0;cl3();times=millis();w=1;w2=1;if(stereo>2){stereo=0;}audio();}// кнопка > 
     if(ir.value==IR_4){stereo--;gr1=0;gr2=1;cl3();times=millis();w=1;w2=1;if(stereo<0){stereo=2;}audio();}// кнопка <
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    stereo=stereo+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w2=1;if(stereo>2){stereo=0;};if(stereo<0){stereo=2;}audio();} 
  lcd.setCursor(0,0);lcd.print(" Stereo / Mono  ");
  lcd.setCursor(0,1);
  switch(stereo){
    case 0: lcd.print("     STEREO     ");break;
    case 1: lcd.print("    Lch Mono    ");break;
    case 2: lcd.print("    Rch Mono    ");break;
    }}
 
///////////////  Mode Selector //////////////////////////
  if(menu==5){
     if(ir.value==IR_3){mode++;gr1=1;gr2=0;cl3();times=millis();w=1;w2=1;if(mode>3){mode=0;}audio();}// кнопка > 
     if(ir.value==IR_4){mode--;gr1=0;gr2=1;cl3();times=millis();w=1;w2=1;if(mode<0){mode=3;}audio();}// кнопка <
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    mode=mode+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w2=1;if(mode>3){mode=0;};if(mode<0){mode=3;}audio();} 
  lcd.setCursor(0,0);lcd.print(" Mode Selector  ");
  lcd.setCursor(0,1);
  switch(mode){
    case 0: lcd.print("     BYPASS     ");break;
    case 1: lcd.print("      TONE      ");break;
    case 2: lcd.print("Tone&Surround Hi");break;
    case 3: lcd.print("Tone&Surround Lo");break;
    }}    
 
 ///////////// EEPROM ////////////////////////////////////////
  if(millis()-times>5000 && w==1){
     EEPROM.write(0,vol);EEPROM.write(1,in);EEPROM.write(2,bas+7);EEPROM.write(3,treb+7);EEPROM.write(4,ball+6);
     EEPROM.write(5,stereo);EEPROM.write(6,mode);
     EEPROM.write(10,gain1);EEPROM.write(11,gain2);EEPROM.write(12,gain3);EEPROM.write(13,gain4);EEPROM.write(14,gain5);
     menu=0;w=0;w2=1;cl2();}
  }// LOOP
 
void ball_func(){if(ball>6){ball=6;}if(ball<-6){ball=-6;}}
void treb_func(){if(treb>7){treb=7;}if(treb<-7){treb=-7;}}
void bass_func(){if(bas>7){bas=7;}if(bas<-7){bas=-7;}}
void gain_func(){if(gain0>10){gain0=10;}if(gain0<0){gain0=0;}}  
void vol_func(){if(vol>87){vol=87;}if(vol<12){vol=12;}}
void cl(){ir.value=0;}
void cl1(){ir.value=0;delay(20);}
void cl2(){ir.value=0;lcd.clear();}
void cl3(){ir.value=0;delay(100);}
 
 
 
void audio(){
  ra.setVolume_left(vol-6+ball); // -87...0 dB === int 0...87
  ra.setVolume_right(vol-6-ball);// -87...0 dB === int 0...87 
  ra.setIn_Gain(in,gain0);    // IN 1...5 === byte 0...4 /// int 7 === mute
                         // GAIN 0...20 dB step 2 dB === int 0...10
  ra.setStereo(stereo,mode);     // 0 = stereo / 1 = Lch / 2 = Rch
                         // 0 = bypass / 1 = tone / 2 = tone&surround_hi / 3 = tone&surround_low
  ra.setTone(bas,treb);     // bass and treb -14...14 dB step 2 dB === int -7...7
  }   
 
ISR (TIMER2_COMPA_vect){newPosition = myEnc.read()/4;}

 

Форум — http://forum.rcl-radio.ru/viewtopic.php?id=200

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

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