ИМС TDA7439 – регулятор громкости и трехполосный регулятор тембра, разработан для использования в HI-FI аппаратуре и качественных автомобильных аудиосистемах, обладает низким уровнем шумов и искажений.
Основные технические характеристики ИМС TDA7439:
- Громкость 48 уровней от -48 до 0 дБ
- Регулировка тембра НЧ, СЧ, ВЧ ±14 дБ (±7 уровней)
- Коммутация входов — 4 стерео канала
- Усиление от 0 до 30 дБ независимое для каждого канала
- Регулировка баланса ±8 дБ (ограниченно программно)
- Напряжение питания от 6 до 10,2 В (типовое значение 9 В)
- КНИ на частоте 1 кГц не более 0,01%
Плата микроконтроллера и аудиопроцессор TDA7439 обмениваются данными на шине I2C по линиям SDA (data — данные) и SCL (clock — синхронизация).
В качестве органов управления регулятором громкости и тембра три используются кнопки, энкодер KY-040 и ИК-модуля VS1838B. Информация о настройках выводится на OLED дисплей с разрешением 128 на 64 точки, диагональ дисплея 1,3 дюйма, чип драйвера — SH1106 I2C. В проекте используется плата контроллера LGT8F328, но можно использовать Atduino Nano/
Меню управления регулятором громкости и тембра
Громкость
Тембр ВЧ
Тембр СЧ
Тембр НЧ
Баланс
Выбор входа и усиления
MUTE
STANDBY
Подачи питания регулятор громкости и тембра переходит в режим STANDBY, вывод D13 используется для управления режимом STANDBY УМЗЧ. В регулятор громкости и тембра так же предусмотрены цифровые выходы режима работы селектора входов, к ним при необходимости можно подключить светодиоды диоды (через резистор 200 Ом) для индикации активности входа, использовать как управляющий сигнал для подачи питания на источник звукового сигнала.
#define ENC_DT 8 #define ENC_CLK 9 #define ENC_SW 10 #define IR 12 #define MENU 0x33B820DF // button encoder #define UP 0x33B810EF // >>> #define DW 0x33B8E01F // <<< #define INPUT_IR 0x33B88877 // IN #define POWER_IR 0x33B800FF // POWER #define MUTE_IR 0x33B811FF // MUTE #define IN 2 #define POWER 6 #define POWER_OUT_PIN 13 #define MUTE 3 #define IN1_OUT A0 #define IN2_OUT A1 #define IN3_OUT A2 #define IN4_OUT A3 #include <Wire.h> #include <U8glib.h> // https://github.com/olikraus/u8glib/ #include <MsTimer2.h> // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip #include <TDA7439.h> // http://rcl-radio.ru/wp-content/uploads/2019/01/TDA7439.zip #include <Encoder.h> // http://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip #include <EEPROM.h> #include <boarddefs.h> // входит в состав библиотеки IRremote #include <IRremote.h> // http://rcl-radio.ru/wp-content/uploads/2019/06/IRremote.zip TDA7439 tda; Encoder myEnc(ENC_DT, ENC_CLK); U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); IRrecv irrecv(IR); decode_results ir; long oldPosition = -999,newPosition, times; int vol_reg,balans,treb_reg,bass_reg,mid_reg,in_reg,gain0,gain1,gain2,gain3,gain4,menu,vol_old; bool gr1,gr2,w=1,w1,www,power,power_off=1,mute; void setup() { Wire.begin();Serial.begin(9600); irrecv.enableIRIn(); pinMode(ENC_SW,INPUT); pinMode(IN,INPUT_PULLUP); pinMode(MUTE,INPUT_PULLUP); pinMode(POWER,INPUT_PULLUP); pinMode(POWER_OUT_PIN,OUTPUT); pinMode(IN1_OUT,OUTPUT); pinMode(IN2_OUT,OUTPUT); pinMode(IN3_OUT,OUTPUT); pinMode(IN4_OUT,OUTPUT); if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении MsTimer2::set(1, to_Timer);MsTimer2::start(); vol_reg = EEPROM.read(0);treb_reg = EEPROM.read(1)-7;mid_reg = EEPROM.read(2)-7;bass_reg = EEPROM.read(3)-7; in_reg = EEPROM.read(4);gain1 = EEPROM.read(5);gain2 = EEPROM.read(6);gain3 = EEPROM.read(7);gain4 = EEPROM.read(8);balans = EEPROM.read(9)-8; switch(in_reg){ case 1: gain0=gain1;break; case 2: gain0=gain2;break; case 3: gain0=gain3;break; case 4: gain0=gain4;break; } audio(); } void loop() { if(power==0){ if(in_reg==1){digitalWrite(IN1_OUT,HIGH);}else{digitalWrite(IN1_OUT,LOW);} if(in_reg==2){digitalWrite(IN2_OUT,HIGH);}else{digitalWrite(IN2_OUT,LOW);} if(in_reg==3){digitalWrite(IN3_OUT,HIGH);}else{digitalWrite(IN3_OUT,LOW);} if(in_reg==4){digitalWrite(IN4_OUT,HIGH);}else{digitalWrite(IN4_OUT,LOW);} } else{digitalWrite(IN1_OUT,LOW);digitalWrite(IN2_OUT,LOW);digitalWrite(IN3_OUT,LOW);digitalWrite(IN4_OUT,LOW);} // IR //////////////////////////////////////// if ( irrecv.decode( &ir )) {Serial.print("0x");Serial.println( ir.value,HEX);irrecv.resume();}// IR приемник - чтение, в мониторе порта отображаются коды кнопок if(ir.value==0){gr1=0;gr2=0;}// запрет нажатий не активных кнопок пульта // BUTTON /////////////////////////////////////////////////// if((digitalRead(POWER)==LOW||ir.value==POWER_IR||power_off==1)&&power==0&&mute==0){power_off=0;power=1;menu=100;cl();vol_old=vol_reg;vol_reg=0;audio(); u8g.firstPage();do {u8g.setFont(u8g_font_profont12r);u8g.drawStr(40,30,"POWER OFF");} while( u8g.nextPage() ); delay(1500); u8g.firstPage();do {} while( u8g.nextPage() );} if((digitalRead(POWER)==LOW||ir.value==POWER_IR)&&power==1){power=0;menu=0;vol_reg=vol_old;times=millis();w=1;w1=1; u8g.firstPage();do {u8g.drawStr(42,30,"POWER ON");} while( u8g.nextPage() );delay(1500);audio();} if(power==0){digitalWrite(POWER_OUT_PIN,HIGH);}else{digitalWrite(POWER_OUT_PIN,LOW);} if(power==0){ if(digitalRead(ENC_SW)==LOW||ir.value==MENU){menu++;cl();if(menu>4){menu=0;}times=millis();w=1;w1=1;delay(200);} if(digitalRead(IN)==LOW||ir.value==INPUT_IR){menu=10;cl();in_reg++;times=millis();w=1;w1=1;www=1;if(in_reg>4){in_reg=1;};delay(200);} if((digitalRead(MUTE)==LOW||ir.value==MUTE_IR)&&mute==0){mute=1;menu=100;cl();vol_old=vol_reg;vol_reg=0;audio(); u8g.firstPage();do {u8g.setFont(u8g_font_profont12r);u8g.drawStr(53,30,"MUTE");} while( u8g.nextPage() );} if((digitalRead(MUTE)==LOW||ir.value==MUTE_IR)&&mute==1){mute=0;times=millis();w=1;w1=1;menu=0;cl();vol_reg=vol_old;audio();} } //////// VOLUME ////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(menu==0){ if(newPosition != oldPosition){oldPosition = newPosition;if(newPosition>1){newPosition=1;}if(newPosition<-1){newPosition=-1;} vol_reg=vol_reg+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;vol_func();audio();} if(ir.value==UP){vol_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;vol_func();audio();}// кнопка > if(ir.value==0xFFFFFFFF and gr1==1){vol_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;vol_func();audio();}// кнопка >>>>>> if(ir.value==DW){vol_reg--;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;vol_func();audio();}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){vol_reg--;gr1=0;cl();times=millis();w=1;w1=1;vol_func();audio();}// кнопка <<<<<< if(w==1){w=0; u8g.firstPage(); do { u8g.setFont(u8g_font_profont12r);u8g.drawStr(0,8,"VOLUME");u8g.drawStr(0,18,"IN"); u8g.setPrintPos(20, 18);u8g.print(in_reg);u8g.drawStr(0,28,"GAIN");u8g.setPrintPos(30, 28);u8g.print(gain0); u8g.drawLine(0, 32, 128, 32); u8g.drawStr(0,44,"TREBLE");u8g.setPrintPos(80, 44);u8g.print(treb_reg*2);u8g.drawStr(95,44,"dB"); u8g.drawStr(0,54,"MIDDLE");u8g.setPrintPos(80, 54);u8g.print(mid_reg*2);u8g.drawStr(95,54,"dB"); u8g.drawStr(0,64,"BASS");u8g.setPrintPos(80, 64);u8g.print(bass_reg*2);u8g.drawStr(95,64,"dB"); u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 22);u8g.print(vol_reg); } while( u8g.nextPage() ); }} ///////////////////////////////////////////////////////////////// //////// TRABLE ////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(menu==1){ if(newPosition != oldPosition){oldPosition = newPosition;if(newPosition>1){newPosition=1;}if(newPosition<-1){newPosition=-1;} treb_reg=treb_reg+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;treb_func();audio();} if(ir.value==UP){treb_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;treb_func();audio();}// кнопка > if(ir.value==0xFFFFFFFF and gr1==1){treb_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;treb_func();audio();}// кнопка >>>>>> if(ir.value==DW){treb_reg--;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;treb_func();audio();}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){treb_reg--;gr1=0;cl();times=millis();w=1;w1=1;treb_func();audio();}// кнопка <<<<<< if(w==1){w=0; u8g.firstPage(); do { u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 22);u8g.print(treb_reg*2); u8g.drawLine(0, 32, 128, 32); u8g.setFont(u8g_font_profont12r);u8g.drawStr(0,8,"TREBLE");u8g.drawStr(0,44,"MIDDLE");u8g.setPrintPos(80, 44);u8g.print(mid_reg*2);u8g.drawStr(95,44,"dB"); u8g.drawStr(0,54,"BASS");u8g.setPrintPos(80, 54);u8g.print(bass_reg*2);u8g.drawStr(95,54,"dB"); u8g.drawStr(0,64,"BALANCE");u8g.setPrintPos(80, 64);u8g.print(balans);u8g.drawStr(95,64,"dB"); } while( u8g.nextPage() ); }} ///////////////////////////////////////////////////////////////// //////// MIDDLE ////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(menu==2){ if(newPosition != oldPosition){oldPosition = newPosition;if(newPosition>1){newPosition=1;}if(newPosition<-1){newPosition=-1;} mid_reg=mid_reg+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;mid_func();audio();} if(ir.value==UP){mid_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;mid_func();audio();}// кнопка > if(ir.value==0xFFFFFFFF and gr1==1){mid_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;mid_func();audio();}// кнопка >>>>>> if(ir.value==DW){mid_reg--;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;mid_func();audio();}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){mid_reg--;gr1=0;cl();times=millis();w=1;w1=1;mid_func();audio();}// кнопка <<<<<< if(w==1){w=0; u8g.firstPage(); do { u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 22);u8g.print(mid_reg*2); u8g.drawLine(0, 32, 128, 32); u8g.setFont(u8g_font_profont12r);u8g.drawStr(0,8,"MIDDLE");u8g.drawStr(0,44,"BASS");u8g.setPrintPos(80, 44);u8g.print(bass_reg*2);u8g.drawStr(95,44,"dB"); u8g.drawStr(0,54,"BALANCE");u8g.setPrintPos(80, 54);u8g.print(balans);u8g.drawStr(95,54,"dB"); u8g.drawStr(0,64,"VOLUME");u8g.setPrintPos(80, 64);u8g.print(vol_reg);u8g.drawStr(95,64,"dB"); } while( u8g.nextPage() ); }} ///////////////////////////////////////////////////////////////// //////// BASS ////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(menu==3){ if(newPosition != oldPosition){oldPosition = newPosition;if(newPosition>1){newPosition=1;}if(newPosition<-1){newPosition=-1;} bass_reg=bass_reg+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;bass_func();audio();} if(ir.value==UP){bass_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;bass_func();audio();}// кнопка > if(ir.value==0xFFFFFFFF and gr1==1){bass_reg++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;bass_func();audio();}// кнопка >>>>>> if(ir.value==DW){bass_reg--;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;bass_func();audio();}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){bass_reg--;gr1=0;cl();times=millis();w=1;w1=1;bass_func();audio();}// кнопка <<<<<< if(w==1){w=0; u8g.firstPage(); do { u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 22);u8g.print(bass_reg*2); u8g.drawLine(0, 32, 128, 32); u8g.setFont(u8g_font_profont12r);u8g.drawStr(0,8,"BASS"); u8g.drawStr(0,44,"BALANCE");u8g.setPrintPos(80, 44);u8g.print(balans);u8g.drawStr(95,44,"dB"); u8g.drawStr(0,54,"VOLUME");u8g.setPrintPos(80, 54);u8g.print(vol_reg);u8g.drawStr(95,54,"dB"); u8g.drawStr(0,64,"TREBLE");u8g.setPrintPos(80, 64);u8g.print(treb_reg*2);u8g.drawStr(95,64,"dB"); } while( u8g.nextPage() ); }} ///////////////////////////////////////////////////////////////// //////// BALANCE ////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(menu==4){ if (newPosition != oldPosition){oldPosition = newPosition;balans=balans+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;ball_func();audio();} if(ir.value==UP){balans++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;ball_func();audio();}// кнопка > if(ir.value==0xFFFFFFFF and gr1==1){balans++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;ball_func();audio();}// кнопка >>>>>> if(ir.value==DW){balans--;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;ball_func();audio();}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){balans--;gr1=0;cl();times=millis();w=1;w1=1;ball_func();audio();}// кнопка <<<<<< if(w==1){w=0; u8g.firstPage(); do { u8g.setFont(u8g_font_profont12r);u8g.drawStr(0,8,"BALANCE");u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 22);u8g.print(abs(balans)); u8g.setFont(u8g_font_profont12r); if(balans<=0){u8g.drawStr(50,20,"LCH");} if(balans>=0){u8g.drawStr(105,20,"RCH");} u8g.drawLine(0, 32, 128, 32); u8g.drawStr(0,44,"VOLUME");u8g.setPrintPos(80, 44);u8g.print(vol_reg);u8g.drawStr(95,44,"dB"); u8g.drawStr(0,54,"TREBLE");u8g.setPrintPos(80, 54);u8g.print(mid_reg*2);u8g.drawStr(95,54,"dB"); u8g.drawStr(0,64,"MIDDLE");u8g.setPrintPos(80, 64);u8g.print(treb_reg*2);u8g.drawStr(95,64,"dB"); } while( u8g.nextPage() ); }} ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////// INPUT GAIN /////////////////////////////////////////////////////////////////// if(menu==10){ switch(in_reg){ case 1: gain0=gain1;break; case 2: gain0=gain2;break; case 3: gain0=gain3;break; case 4: gain0=gain4;break; } if (newPosition != oldPosition){oldPosition = newPosition;if(newPosition>1){newPosition=1;}if(newPosition<-1){newPosition=-1;} gain0=gain0+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;www=1;gain_func();} if(ir.value==UP){gain0++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;gain_func();www=1;}// кнопка > if(ir.value==0xFFFFFFFF and gr1==1){gain0++;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;gain_func();www=1;}// кнопка >>>>>> if(ir.value==DW){gain0--;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;gain_func();www=1;}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){gain0--;gr1=0;cl();times=millis();w=1;w1=1;gain_func();www=1;}// кнопка <<<<<< switch(in_reg){ case 1: gain1=gain0;break; case 2: gain2=gain0;break; case 3: gain3=gain0;break; case 4: gain4=gain0;break; } if(www==1){audio();www=0;} if(w==1){w=0; u8g.firstPage(); do { u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 22);u8g.print(in_reg); u8g.drawLine(0, 32, 128, 32); u8g.setFont(u8g_font_profont12r);u8g.drawStr(0,8,"INPUT");u8g.drawStr(0,44,"GAIN"); u8g.setFont(u8g_font_profont29r); u8g.setPrintPos(78, 60);u8g.print(gain0); } while( u8g.nextPage() ); }} if(millis()-times>5000 && w1==1 && power==0 && mute==0){ EEPROM.update(0,vol_reg);EEPROM.update(1,treb_reg+7);EEPROM.update(2,mid_reg+7);EEPROM.update(3,bass_reg+7); EEPROM.update(4,in_reg);EEPROM.update(5,gain1);EEPROM.update(6,gain2);EEPROM.update(7,gain3);EEPROM.update(8,gain4);EEPROM.update(9,balans+8); menu=0;w1=0;w=1;myEnc.write(0);} } void to_Timer(){newPosition = myEnc.read()/4;} void cl(){ir.value=0;delay(200);} void vol_func(){if(vol_reg<0){vol_reg=0;}if(vol_reg>48){vol_reg=48;}} void treb_func(){if(treb_reg<-7){treb_reg=-7;}if(treb_reg>7){treb_reg=7;}} void mid_func(){if(mid_reg<-7){mid_reg=-7;}if(mid_reg>7){mid_reg=7;}} void bass_func(){if(bass_reg<-7){bass_reg=-7;}if(bass_reg>7){bass_reg=7;}} void gain_func(){if(gain0>15){gain0=15;}if(gain0<0){gain0=0;}} void ball_func(){if(balans>8){balans=8;}if(balans<-8){balans=-8;}} void audio(){ tda.setInput(in_reg); // 1 to 4 // номер канала tda.inputGain(gain0); // 0 to 15 // усиление tda.setVolume(vol_reg); // 0 to 48 ( 0 is mute) // громкость tda.setSnd(bass_reg, 1); //-7 to +7 , 1 - Bass | 2 - Mids | 3 - Trebble tda.setSnd(mid_reg, 2); tda.setSnd(treb_reg, 3); tda.spkAtt(8 + balans ,8 - balans); // баланс R L от 0 to 79 (db) }
ИК пульт дублирует работу энкодера и кнопок. Для управления регулятором подойдет практически любой пульт ИК, для поддержки Вашего пульта необходимо прописать коды кнопок в скетч:
#define MENU 0x33B820DF // button encoder #define UP 0x33B810EF // >>> #define DW 0x33B8E01F // <<< #define INPUT_IR 0x33B88877 // IN #define POWER_IR 0x33B800FF // POWER #define MUTE_IR 0x33B811FF // MUTE
Для получения кодов кнопок Вашего пульта загрузите скетч и откройте монитор порта, при нажатии кнопки пульта его код будет отображен в мониторе порта.
Все очень здорово получилось слушаю и наслаждаюсь.
Автору большой «РЕСПЕКТ» и простое человеческое СПАСИБО.
Удачи.
P.S. Нa входах TDA7439 ставте пленку 0,47мкФ, электоролиты немного хуже, осциллограф показывает.
Здравствуйте, поставил ваш скетч, и экран начинает сам переключаться без энкодера.
Подскажите пожалуйста в чем проблема?
Нет энкодера
Он подключен.
Hw-040.
На плате энкодера должно быть 3 подтягивающих резистора к +5В по 10 кОм
Сзади энкодера распаяны только 2 резиста по 10ком , но в других проектах, он работал
У Вас скорее всего нет резистора на выходе SW, его надо установить или подключить внутренний программно.
pinMode(ENC_SW,INPUT_PULLUP);
Заработало, спасибо
Как по схеме вашей.
так резисторы на плате энкодера есть?
Здравствуйте,собрал все, но при подключении совместно с экраном, ничего не работает, пробовал 2 тдахи и сканером они тоже не определятся, на форуме в переделках написал подробнее (Arduino+tda+анализатор спектра)