TDA7449 + энкодер + ИК пульт + анализатор спектра

Ранее на странице http://rcl-radio.ru/?p=56015 рассматривался пример использования аудиопроцессора на платформе Arduino, в качестве органов управления были кнопки и энкодер. На этой странице будет показан пример использования аудиопроцессора который имеет управление одновременно от кнопок, энкодера и ИК пульта, так же в скетч добавлен анализатор спектра который срабатывает после 10 секундной не активности органов управления. Аудио сигнал (линейный) необходимо подать на вход А0 через разделительный конденсатор 0,1 мкФ.

Основные технические характеристики ИМС TDA7449:

  • Громкость 47 уровней от -47 до 0 дБ
  • Регулировка тембра НЧ, ВЧ  ±14 дБ (±7 уровней)
  • Коммутация входов — 2 стерео канала
  • Усиление от 0 до 30 дБ независимое для каждого канала
  • Регулировка баланса ± 8 дБ (ограниченно программно)
  • Отношение сигнал\шум 106 дБ
  • Разделение каналов 100 дБ
  • Режим MUTE
  • Частотный диапазон от 20 до 20000 Гц
  • Напряжение питания от 6 до 10,2 В (типовое значение 9 В)
  • КНИ на частоте 1 кГц не более 0,01%

Плата Arduino Nano аудиопроцессор TDA7449 обмениваются данными на шине I2C по линиям SDA (data — данные) и SCL (clock — синхронизация). В качестве индикатора используется LCD1602 на базе контроллера HD44780.

 

Библиотеки:

http://rcl-radio.ru/wp-content/uploads … Timer2.zip
http://rcl-radio.ru/wp-content/uploads … ncoder.zip
http://rcl-radio.ru/wp-content/uploads … DA7449.zip
http://rcl-radio.ru/wp-content/uploads … remote.zip

Получить коды кнопок своего ИК пульта можно в мониторе порта.

Скетч без анализатора спектра

#include <Wire.h>
#include <TDA7449.h>
#include <LiquidCrystal.h>
#include <Encoder.h>
#include <MsTimer2.h>
#include <boarddefs.h>
#include <IRremote.h>
#include <EEPROM.h>//#include <EEPROMex.h> для старых версий Arduino IDE
  TDA7449 tda;
  IRrecv irrecv(12); // указываем вывод модуля IR приемника
  Encoder myEnc(9, 8);//CLK, DT
  decode_results ir;
  LiquidCrystal lcd(7, 6, 2, 3, 4, 5);// RS,E,D4,D5,D6,D7
   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};
  int menu,vol,vol_d,bass,bass_d,mids,treb,treb_d,balans,in,gain,gain_d,gain0,gain1;
  int att=8; // аттенюатор - если звук очень громкий увеличьте значение (72 mute), меньше 8 не делать.
  byte w,w1,w2,in_d,z,z0,z1,www,mute,gr1,gr2,mute_w;
  unsigned long time,oldPosition  = -999,newPosition;
 
void setup(){ Serial.begin(9600);
  Wire.begin(); lcd.begin(16, 2);irrecv.enableIRIn(); // запускаем модуль IR
  MsTimer2::set(3, to_Timer);MsTimer2::start(); // АКТИВИРУЕМ ПРЕРЫВАНИЯ ДЛЯ ЭНКОДЕРА
  lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
  lcd.setCursor(0,0);lcd.print("    TDA7449    ");delay(1000);// ЗАСТАВКА
  pinMode(10,INPUT);// МЕНЮ КНОПКА SW энкодера
  pinMode(11,INPUT);// ВЫБОР ВХОДА КНОПКА IN
  pinMode(13,INPUT);// КНОПКА MUTE
  /// считываем все настройки с памяти при включении
  vol = EEPROM.read(0);// vol eeprom 
  bass = EEPROM.read(1)-7;// bass eeprom
  treb = EEPROM.read(3)-7;// treb eeprom
  balans = EEPROM.read(4)-4;// balans eeprom
  in = EEPROM.read(5);// in eeprom
  gain0 = EEPROM.read(6);// gain1 eeprom
  gain1 = EEPROM.read(7);// gain2 eeprom
  audio(); // заносим все параметры в tda7449
}
 
void loop() {
  if(digitalRead(10)==LOW&&mute==0){menu++;cl();w2=1;if(menu>4){menu=0;}}// меню
  if(digitalRead(11)==HIGH&&mute==0){in++;;cl();time=millis()-7000;w=1;w2=1;www=1;menu=4;if(in>1){in=0;};audio();}// КНОПКА ВЫБОРА ВХОДА IN
  if(digitalRead(13)==HIGH&&mute==0){mute=1;cl();att=70;audio();lcd.setCursor(0,0);lcd.print("      MUTE      ");menu=100;}
  if(digitalRead(13)==HIGH&&mute==1){mute=0;cl();att=8;menu=0;w2=1;audio();}
 
  ////////////////// ИК приемник - обработка нажатий ///////////////////////////////////////
  if ( irrecv.decode( &ir )) {Serial.print("0x");Serial.println( ir.value,HEX);time=millis();w=1;irrecv.resume();}// IR приемник - чтение
 
  if(ir.value==0x2FDD02F&&mute==0){menu++;gr1=0;gr2=0;cl();time=millis();w=1;w2=1;if(menu>4){menu=0;}}// меню кнопка вверх
  if(ir.value==0x2FD32CD&&mute==0){menu--;gr1=0;gr2=0;cl();time=millis();w=1;w2=1;if(menu<0){menu=4;}}// меню кнопка вниз
 
  if(ir.value==0x2FDEA15&&mute==0){mute=1;cl();att=70;audio();lcd.setCursor(0,0);lcd.print("      MUTE      ");menu=100;}
  if(ir.value==0x2FDEA15&&mute==1){mute=0;cl();att=8;menu=0;w2=1;audio();}
  if(mute==1){w=0;menu=100;gr1=0;}
 
  if(ir.value==0x2FD708F&&mute==0){in++;cl();time=millis()-7000;w=1;w2=1;www=1;menu=4;if(in>1){in=0;};gr1=0;gr2=0;audio();}// IN
 
  /////////////////////// VOLUME //////////////
   if(menu==0){
     if(ir.value==0x2FD906F){vol++;gr1=1;gr2=0;cl();w2=1;vol_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){vol++;gr2=0;cl();w2=1;vol_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){vol--;gr1=0;gr2=1;cl();w2=1;vol_func();audio();}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){vol--;gr1=0;cl();w2=1;vol_func();audio();}// кнопка <<<<<<
 
     if (newPosition != oldPosition){oldPosition = newPosition;
     vol=vol+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;vol_func();audio();} 
     lcd.setCursor(0,0);lcd.print("Volume  ");
     lcd.print(" ");lcd.print(-47+vol);lcd.print(" ");lcd.setCursor(13,0);lcd.print("dB");vol_d=vol;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=vol_d;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("   ");}}
   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  //////////////
   if(menu==1){
     if(ir.value==0x2FD906F){bass++;gr1=1;gr2=0;cl();w2=1;bass_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){bass++;gr2=0;cl();w2=1;bass_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){bass--;gr1=0;gr2=1;cl();w2=1;bass_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){bass--;gr1=0;cl();w2=1;bass_func();audio();}// кнопка <<<<<<  
 
     if (newPosition != oldPosition) {
    oldPosition = newPosition;
    bass=bass+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;bass_func();audio();} 
   lcd.setCursor(0,0);lcd.print("Bass    ");
   lcd.print(" ");lcd.print(bass*2);lcd.print(" ");lcd.setCursor(13,0);lcd.print("dB");bass_d=bass*2+15;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=bass_d;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("   ");}}
   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;}}
 
  ///////////////// TREBLE //////////////////
   if(menu==2){
     if(ir.value==0x2FD906F){treb++;gr1=1;gr2=0;cl();w2=1;treb_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){treb++;gr2=0;cl();w2=1;treb_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){treb--;gr1=0;gr2=1;cl();w2=1;treb_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){treb--;gr1=0;cl();w2=1;treb_func();audio();}// кнопка <<<<<<
 
     if (newPosition != oldPosition) {
    oldPosition = newPosition;
    treb=treb+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;treb_func();audio();} 
   lcd.setCursor(0,0);lcd.print("Treble  ");
   lcd.print(" ");lcd.print(treb*2);lcd.print(" ");lcd.setCursor(13,0);lcd.print("dB");treb_d=treb*2+15;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=treb_d;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("   ");}}
   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;}}
 ///////////////////////////////////////////////////////////
 
 //////////////// BALANSE  +\- 4 dB /////////////
   if(menu==3){
     if(ir.value==0x2FD906F){balans++;gr1=1;gr2=0;cl();balans_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){balans++;gr2=0;cl();balans_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){balans--;gr1=0;gr2=1;cl();balans_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){balans--;gr1=0;cl();balans_func();audio();}// кнопка <<<<<<
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    balans=balans+newPosition;myEnc.write(0);newPosition=0;lcd.clear();time=millis();w=1;balans_func();audio();}
  lcd.setCursor(0,0);
   if(balans>=0){lcd.print("-");}else{lcd.print("+");}
  lcd.print(abs(balans));lcd.print(" dB ");
  lcd.print(" <>  ");
   if(balans>=0){lcd.print("+");}else{lcd.print("-");}
  lcd.print(abs(balans));lcd.print(" dB ");
  lcd.setCursor(0,1);lcd.print("L");
  lcd.setCursor(15,1);lcd.print("R");
   if(balans<0){lcd.setCursor(balans+7,1);lcd.write((uint8_t)0);}
   if(balans>0){lcd.setCursor(balans+8,1);lcd.write((uint8_t)0);}
   if(balans==0){lcd.setCursor(7,1);lcd.write((uint8_t)0);lcd.setCursor(8,1);lcd.write((uint8_t)0);}
 }
 
 /////////// input + gain /////////////////////////////////////////
 if(menu==4){
        switch(in){
     case 0: gain = gain0;break;
     case 1: gain = gain1;break;
     }
 
     if(ir.value==0x2FD906F){gain++;gr1=1;gr2=0;cl();w2=1;gain_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){gain++;gr2=0;cl();w2=1;gain_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){gain--;gr1=0;gr2=1;cl();w2=1;gain_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){gain--;gr1=0;cl();w2=1;gain_func();audio();}// кнопка <<<<<<
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    gain=gain+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;gain_func();audio();} 
   switch(in){
     case 0: gain0 = gain;break;
     case 1: gain1 = gain;break;
     } 
     if(www==1){audio();www=0;}
   lcd.setCursor(0,0);lcd.print("Gain IN ");lcd.print(in);
      lcd.setCursor(10,0);lcd.print(" ");lcd.print(gain*2);lcd.print(" ");lcd.setCursor(14,0);lcd.print("dB");gain_d=gain*2;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=gain_d;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("   ");}}
   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;
  }
 /////////////////////////////////////////////////////////////
 
 // запись всех настроек в EEPROM при неактивности энкодера в течении 10 сек и выход в меню громкости
   if(millis()-time>10000 && w==1){
     EEPROM.update(0,vol);
     EEPROM.update(4,balans+4);
     EEPROM.update(1,bass+7);
     EEPROM.update(3,treb+7);
     EEPROM.update(5,in);
     EEPROM.update(6,gain0);EEPROM.update(7,gain1);
  menu=0;w=0;w2=1;cl();
 }
 }// loop
 
void gain_func(){if(gain<0){gain=0;}if(gain>15){gain=15;}}
void balans_func(){;if(balans>4){balans=4;}if(balans<-4){balans=-4;}}
void treb_func(){if(treb>7){treb=7;}if(treb<-7){treb=-7;}}
void bass_func(){if(bass>7){bass=7;}if(bass<-7){bass=-7;}} 
void vol_func(){if(vol<0){vol=0;}if(vol>47){vol=47;}}
void cl(){ir.value=0;delay(200);lcd.clear();}
 
void audio(){
  tda.setInput(in); //         int in 1...2 //// номер входа
  tda.inputGain(gain); //      int gain 0...15 (шаг 2дБ)    0...30 дБ  //// усиление
  tda.setVolume(vol); //       int vol 0...47 (шаг 1 дБ)  -47...0 дБ  //// громкость
  tda.setBass(bass); //        int bass -7...+7 (шаг 2 дБ) -14...14 дБ //// тембр НЧ
  tda.setTreble(treb); //      int treb -7...+7 (шаг 2 дБ) -14...14 дБ //// тембр ВЧ
  tda.setAttL(att-balans); //  int att 0...79 (шаг 1дБ)    
  tda.setAttR(att+balans); //  int att 0...79 (шаг 1дБ)    
}
 
void to_Timer(){newPosition = myEnc.read()/4;}

Скетч с анализатором спектра

Дополнительная библиотека — http://rcl-radio.ru/wp-content/uploads/2018/11/FHT.zip

#define AUTO_GAIN 1       // автонастройка по громкости
#define VOL_THR 35        // порог тишины (ниже него отображения на матрице не будет)
#define LOW_PASS 30       // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
#define DEF_GAIN 80       // максимальный порог по умолчанию 
#define FHT_N 256         // ширина спектра х2
#define LOG_OUT 1
#include <FHT.h> 
#include <Wire.h>
#include <TDA7449.h>
#include <LiquidCrystal.h>
#include <Encoder.h>
#include <MsTimer2.h>
#include <boarddefs.h>
#include <IRremote.h>
#include <EEPROM.h>
  TDA7449 tda;
  IRrecv irrecv(12); // указываем вывод модуля IR приемника
  Encoder myEnc(9, 8);//CLK, DT
  decode_results ir;
  LiquidCrystal lcd(7, 6, 2, 3, 4, 5);// RS,E,D4,D5,D6,D7
  byte posOffset[16] = {2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}; // вч выше
  int menu,vol,vol_d,bass,bass_d,mids,treb,treb_d,balans,in,gain,gain_d,gain0,gain1;
  int att=8; // аттенюатор - если звук очень громкий увеличьте значение (72 mute), меньше 8 не делать.
  byte w,w1,w2,in_d,z,z0,z1,www,mute,gr1,gr2,mute_w;
  unsigned long time,oldPosition  = -999,newPosition;
  unsigned long gainTimer;
  byte maxValue, maxValue_f,spek;
  float k = 0.1;
  byte gain_sp = DEF_GAIN;  
  int i1,yyy;
 
void setup(){ Serial.begin(9600);
  Wire.begin(); lcd.begin(16, 2);irrecv.enableIRIn(); // запускаем модуль IR
  lcd.setCursor(0,0);lcd.print("    TDA7449    ");delay(1000);// ЗАСТАВКА
  pinMode(10,INPUT);// МЕНЮ КНОПКА SW энкодера
  pinMode(11,INPUT);// ВЫБОР ВХОДА КНОПКА IN
  pinMode(13,INPUT);// КНОПКА MUTE
  ADMUX  = 0b01100000; ADCSRA = 0b11010100; // http://rcl-radio.ru/?p=57478
  MsTimer2::set(3, to_Timer);MsTimer2::start(); // АКТИВИРУЕМ ПРЕРЫВАНИЯ ДЛЯ ЭНКОДЕРА
  /// считываем все настройки с памяти при включении
  vol = EEPROM.read(0);// vol eeprom 
  bass = EEPROM.read(1)-7;// bass eeprom
  treb = EEPROM.read(3)-7;// treb eeprom
  balans = EEPROM.read(4)-8;// balans eeprom
  in = EEPROM.read(5);// in eeprom
  gain0 = EEPROM.read(6);// gain1 eeprom
  gain1 = EEPROM.read(7);// gain2 eeprom
  audio(); // заносим все параметры в tda7449
}
 
void loop() {
  if (newPosition != oldPosition) {if(spek==1){cl();menu=0;}}
  if(spek==0){
      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};
      lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
    }else{
      byte v1[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01110};
      byte v2[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01110, 0b01110};
      byte v3[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01110, 0b01110, 0b01110};
      byte v4[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b01110, 0b01110, 0b01110, 0b01110};
      byte v5[8] = {0b00000, 0b00000, 0b00000, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110};
      byte v6[8] = {0b00000, 0b00000, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110};
      byte v7[8] = {0b00000, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110};
      byte v8[8] = {0b01110, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110, 0b01110};
      lcd.createChar(0, v1);lcd.createChar(1, v2);lcd.createChar(2, v3);lcd.createChar(3, v4);lcd.createChar(4, v5);lcd.createChar(5, v6);lcd.createChar(6, v7);lcd.createChar(7, v8);
      }
 
  if(digitalRead(10)==LOW&&mute==0){menu++;cl();w2=1;if(menu>4){menu=0;}}// меню
  if(digitalRead(11)==HIGH&&mute==0){in++;;cl();time=millis()-7000;w=1;w2=1;www=1;menu=4;if(in>1){in=0;};audio();}// КНОПКА ВЫБОРА ВХОДА IN
  if(digitalRead(13)==HIGH&&mute==0){mute=1;cl();att=70;audio();lcd.setCursor(0,0);lcd.print("      MUTE      ");menu=100;}
  if(digitalRead(13)==HIGH&&mute==1){mute=0;cl();att=8;menu=0;w2=1;audio();}
 
  ////////////////// ИК приемник - обработка кодов кнопок ///////////////////////////////////////
  if ( irrecv.decode( &ir )) {Serial.print("0x");Serial.println( ir.value,HEX);irrecv.resume();time=millis();w=1;if(spek==1){menu=0;cl();}}// IR приемник - чтение, в мониторе порта отображаются коды кнопок
 
  if(ir.value==0x2FDD02F&&mute==0){menu++;gr1=0;gr2=0;cl();time=millis();w=1;w2=1;if(menu>4){menu=0;}}// меню кнопка вверх
  if(ir.value==0x2FD32CD&&mute==0){menu--;gr1=0;gr2=0;cl();time=millis();w=1;w2=1;if(menu<0){menu=4;}}// меню кнопка вниз
 
  if(ir.value==0x2FDEA15&&mute==0){mute=1;cl();att=70;audio();lcd.setCursor(0,0);lcd.print("      MUTE      ");menu=100;}
  if(ir.value==0x2FDEA15&&mute==1){mute=0;cl();att=8;menu=0;w2=1;audio();}
  if(mute==1){spek=0;w=0;menu=100;gr1=0;}
 
  if(ir.value==0x2FD708F&&mute==0){in++;cl();time=millis()-7000;w=1;w2=1;www=1;menu=4;if(in>1){in=0;};gr1=0;gr2=0;audio();}// IN
 
  /////////////////////// VOLUME //////////////
   if(menu==0){
     if(ir.value==0x2FD906F){vol++;gr1=1;gr2=0;cl();w2=1;vol_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){vol++;gr2=0;cl();w2=1;vol_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){vol--;gr1=0;gr2=1;cl();w2=1;vol_func();audio();}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){vol--;gr1=0;cl();w2=1;vol_func();audio();}// кнопка <<<<<<
 
     if (newPosition != oldPosition){oldPosition = newPosition;
     vol=vol+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;vol_func();audio();} 
     lcd.setCursor(0,0);lcd.print("Volume  ");
     lcd.print(" ");lcd.print(-47+vol);lcd.print(" ");lcd.setCursor(13,0);lcd.print("dB");vol_d=vol;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=vol_d;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("   ");}}
   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  //////////////
   if(menu==1){
     if(ir.value==0x2FD906F){bass++;gr1=1;gr2=0;cl();w2=1;bass_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){bass++;gr2=0;cl();w2=1;bass_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){bass--;gr1=0;gr2=1;cl();w2=1;bass_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){bass--;gr1=0;cl();w2=1;bass_func();audio();}// кнопка <<<<<<  
 
     if (newPosition != oldPosition) {
    oldPosition = newPosition;
    bass=bass+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;bass_func();audio();} 
   lcd.setCursor(0,0);lcd.print("Bass    ");
   lcd.print(" ");lcd.print(bass*2);lcd.print(" ");lcd.setCursor(13,0);lcd.print("dB");bass_d=bass*2+15;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=bass_d;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("   ");}}
   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;}}
 
  ///////////////// TREBLE //////////////////
   if(menu==2){
     if(ir.value==0x2FD906F){treb++;gr1=1;gr2=0;cl();w2=1;treb_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){treb++;gr2=0;cl();w2=1;treb_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){treb--;gr1=0;gr2=1;cl();w2=1;treb_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){treb--;gr1=0;cl();w2=1;treb_func();audio();}// кнопка <<<<<<
 
     if (newPosition != oldPosition) {
    oldPosition = newPosition;
    treb=treb+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;treb_func();audio();} 
   lcd.setCursor(0,0);lcd.print("Treble  ");
   lcd.print(" ");lcd.print(treb*2);lcd.print(" ");lcd.setCursor(13,0);lcd.print("dB");treb_d=treb*2+15;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=treb_d;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("   ");}}
   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;}}
 ///////////////////////////////////////////////////////////
 
 //////////////// BALANSE  +\- 8 dB /////////////
   if(menu==3){
     if(ir.value==0x2FD906F){balans++;gr1=1;gr2=0;cl();balans_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){balans++;gr2=0;cl();balans_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){balans--;gr1=0;gr2=1;cl();balans_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){balans--;gr1=0;cl();balans_func();audio();}// кнопка <<<<<<
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    balans=balans+newPosition;myEnc.write(0);newPosition=0;lcd.clear();time=millis();w=1;balans_func();audio();}
  lcd.setCursor(0,0);
   if(balans>=0){lcd.print("-");}else{lcd.print("+");}
  lcd.print(abs(balans));lcd.print(" dB ");
  if(balans==0){lcd.print(" <>  ");}
  if(balans<0){lcd.print(" <   ");}
  if(balans>0){lcd.print("  >  ");}
   if(balans>=0){lcd.print("+");}else{lcd.print("-");}
  lcd.print(abs(balans));lcd.print(" dB ");
  lcd.setCursor(0,1);lcd.print("L");
  lcd.setCursor(15,1);lcd.print("R");
   if(balans<0){lcd.setCursor(balans/2+7,1);lcd.write((uint8_t)0);}
   if(balans>0){lcd.setCursor(balans/2+8,1);lcd.write((uint8_t)0);}
   if(balans==0){lcd.setCursor(7,1);lcd.write((uint8_t)0);lcd.setCursor(8,1);lcd.write((uint8_t)0);}}
 
 /////////// input + gain /////////////////////////////////////////
 if(menu==4){
        switch(in){
     case 0: gain = gain0;break;
     case 1: gain = gain1;break;
     }
 
     if(ir.value==0x2FD906F){gain++;gr1=1;gr2=0;cl();w2=1;gain_func();audio();}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){gain++;gr2=0;cl();w2=1;gain_func();audio();}// кнопка >>>>>>
     if(ir.value==0x2FDF20D){gain--;gr1=0;gr2=1;cl();w2=1;gain_func();audio();}// кнопка < 
     if(ir.value==0xFFFFFFFF and gr2==1){gain--;gr1=0;cl();w2=1;gain_func();audio();}// кнопка <<<<<<
 
    if (newPosition != oldPosition) {
    oldPosition = newPosition;
    gain=gain+newPosition;myEnc.write(0);newPosition=0;time=millis();w=1;w2=1;gain_func();audio();} 
   switch(in){
     case 0: gain0 = gain;break;
     case 1: gain1 = gain;break;
     } 
     if(www==1){audio();www=0;}
   lcd.setCursor(0,0);lcd.print("Gain IN ");lcd.print(in);
      lcd.setCursor(10,0);lcd.print(" ");lcd.print(gain*2);lcd.print(" ");lcd.setCursor(14,0);lcd.print("dB");gain_d=gain*2;
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=gain_d;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("   ");}}
   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;
  }
 /////////////////////////////////////////////////////////////
 
 // запись всех настроек в EEPROM при неактивности энкодера в течении 10 сек и выход в меню громкости
   if(millis()-time>10000 && w==1){
     EEPROM.update(0,vol);
     EEPROM.update(4,balans+8);
     EEPROM.update(1,bass+7);
     EEPROM.update(3,treb+7);
     EEPROM.update(5,in);
     EEPROM.update(6,gain0);EEPROM.update(7,gain1);
  menu=100;lcd.clear();w=0;w2=1;cl();spek=1;
 }
 
 if(spek==1){
  analyzeAudio();   // функция FHT, забивает массив fht_log_out[] величинами по спектру
 
  for (int pos = 0; pos < 16; pos++) {   // для окошек дисплея с 0 по 15
    // найти максимум из пачки тонов
    if (fht_log_out[posOffset[pos]] > maxValue) maxValue = fht_log_out[posOffset[pos]];
 
    lcd.setCursor(pos, 0);
 
    // преобразовать значение величины спектра в диапазон 0..15 с учётом настроек
    int posLevel = map(fht_log_out[posOffset[pos]], LOW_PASS, gain_sp, 0, 15);
    posLevel = constrain(posLevel, 0, 15);
  while(yyy<2){yyy++;
    if (posLevel > 7) {               // если значение больше 7 (значит нижний квадратик будет полный)
      lcd.write((uint8_t)posLevel - 8);    // верхний квадратик залить тем что осталось
      lcd.setCursor(pos, 1);          // перейти на нижний квадратик
      lcd.write((uint8_t)7);        // залить его полностью
  } 
    else {                          // если значение меньше 8
      lcd.print(" ");                 // верхний квадратик пустой
      lcd.setCursor(pos, 1);          // нижний квадратик
      lcd.write((uint8_t)posLevel);        // залить полосками
    }} yyy=0;
  }  
 
  if (AUTO_GAIN) {
    maxValue_f = maxValue * k + maxValue_f * (1 - k);
    if (millis() - gainTimer > 1500) {      // каждые 1500 мс
      // если максимальное значение больше порога, взять его как максимум для отображения
      if (maxValue_f > VOL_THR) gain_sp = maxValue_f;
 
      // если нет, то взять порог побольше, чтобы шумы вообще не проходили
      else gain_sp = 100;
      gainTimer = millis();
    }
  }else{gain_sp = DEF_GAIN;}
  }
  //////////////////////////////////
 }// loop
 
void gain_func(){if(gain<0){gain=0;}if(gain>15){gain=15;}}
void balans_func(){if(balans>8){balans=8;}if(balans<-8){balans=-8;}}
void treb_func(){if(treb>7){treb=7;}if(treb<-7){treb=-7;}}
void bass_func(){if(bass>7){bass=7;}if(bass<-7){bass=-7;}} 
void vol_func(){if(vol<0){vol=0;}if(vol>47){vol=47;}}
void cl(){ir.value=0;delay(300);spek=0;lcd.clear();}
 
void audio(){
  tda.setInput(in+1); //         int in 1...2 //// номер входа
  tda.inputGain(gain); //      int gain 0...15 (шаг 2дБ)    0...30 дБ  //// усиление
  tda.setVolume(vol); //       int vol 0...47 (шаг 1 дБ)  -47...0 дБ  //// громкость
  tda.setBass(bass); //        int bass -7...+7 (шаг 2 дБ) -14...14 дБ //// тембр НЧ
  tda.setTreble(treb); //      int treb -7...+7 (шаг 2 дБ) -14...14 дБ //// тембр ВЧ
  tda.setAttL(att-balans); //  int att 0...79 (шаг 1дБ)    
  tda.setAttR(att+balans); //  int att 0...79 (шаг 1дБ)    
}
 
void to_Timer(){newPosition = myEnc.read()/4;}
 
void analyzeAudio() {  
  cli(); 
 while( i1 < FHT_N ) {  i1++; 
    do{ADCSRA |= (1 << ADSC);} 
    while((ADCSRA & (1 << ADIF)) == 0);
    fht_input[i1] = (ADCL|ADCH << 8); 
    //fht_input[i1] = ADCH; 
    }i1=0;
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
  sei();
}

Форум:

Comments

  1. Погонял немного эту схему.
    Реагирует на 0xFFFFFFFF чужих пультов.
    Чтобы избавиться от этого в теме TDA 7313 вы добавляли в код строку
    if(ir.value==0){gr1=0;gr2=0;}
    Я попробовал так:

    /////////////////////// VOLUME //////////////
    if(menu==0){
    if(ir.value==0x828D7){vol++;gr1=1;gr2=0;cl();w2=1;vol_func();audio();}// кнопка >
    if(ir.value==0xFFFFFFFF and gr1==1){vol++;gr2=0;cl();w2=1;vol_func();audio();}// кнопка >>>>>>
    if(ir.value==0x848B7){vol—;gr1=0;gr2=1;cl();w2=1;vol_func();audio();}// кнопка <
    if(ir.value==0xFFFFFFFF and gr2==1){vol—;gr1=0;cl();w2=1;vol_func();audio();}// кнопка <<<<<<
    if(ir.value==0){gr1=0;gr2=0;}

    Работает ,на чужие пульты не реагирует, но регулировка громкости стала пошаговой —
    нужно много раз нажимать .
    Наверное куда-то не туда вставил код.
    В тембрах сделал то-же самое.Там пошаговая регулировка даже лучше —
    ступеней мало и регулировать стало удобнее.
    А вот для громкости это не подходит.

    1. Я вставлял этот код сразу после строки опроса ИК пульта
      if ( irrecv.decode( &ir )) {Serial.print("0x");Serial.println( ir.value,HEX);irrecv.resume();time=millis();w=1;}// IR приемник - чтение, в мониторе порта отображаются коды кнопок
      if(ir.value==0){gr1=0;gr2=0;}// запрет нажатий не активных кнопок пульта

  2. Спасибо,попробую.
    Хотелось бы ещё вход с пульта сделать (сейчас только с кнопки).
    Ну и кнопку сеть добавить (и с пульта тоже).
    Да,ещё,громкость желательно отдельными кнопками с пульта управлять,а не стрелками —
    как во всех промышленных устройствах.
    Сайт у вас хороший,много интересного.

    1. Попробуйте вставить этот код перед /////////////////////// VOLUME ////////////// для отдельной регулировки громкости

      if(ir.value==Код_кнопки+ && menu!=0){menu=0;}
      if(ir.value==Код_кнопки- && menu!=0){menu=0;}

      и поправьте код громкости

      if(menu==0){
      if(ir.value==0x2FD906F || ir.value==Код_кнопки+){vol++;gr1=1;gr2=0;cl();w2=1;vol_func();audio();}// кнопка >
      if(ir.value==0xFFFFFFFF and gr1==1){vol++;gr2=0;cl();w2=1;vol_func();audio();}// кнопка >>>>>>
      if(ir.value==0x2FDF20D || ir.value==Код_кнопки-){vol--;gr1=0;gr2=1;cl();w2=1;vol_func();audio();}// кнопка < if(ir.value==0xFFFFFFFF and gr2==1){vol--;gr1=0;cl();w2=1;vol_func();audio();}// кнопка <<<<<<

      Для кнопки IN

      Берем за основу код кнопки

      if(digitalRead(11)==HIGH&&mute==0){in++;cl();time=millis()-7000;w=1;w2=1;www=1;menu=4;if(in>1){in=0;};audio();}// КНОПКА ВЫБОРА ВХОДА IN

      и делаем кнопку IN с пульта

      if(ir.value==код_кнопка_IN){in++;cl();time=millis()-7000;w=1;w2=1;www=1;menu=4;if(in>1){in=0;};audio();}// IN

  3. Хорошо,буду пробовать.
    Осталось только только сеть сделать (в выключенном состоянии гаснет подсветка дисплея плюс транзисторный ключ и реле «сеть».
    Сейчас от питания 9в. TDAшка вместе с ардуинкой (через КРЕНку) потребляет 51 ма.
    Без подсветки будет ещё меньше.
    Это где-то пол ватта потребления в дежурном режиме.

  4. У меня I2C модуля нет.
    Здесь тоже должно хватить входов.
    Кнопка IN переключить с D11 на A2.
    Кнопка СЕТЬ подключить на A1.
    Выход реле СЕТЬ подключить на D11.
    Ещё даже штуки три входа свободных остаются (аналоговых).

    1. Вот реализация функции STANDBY — http://forum.rcl-radio.ru/viewtopic.php?id=49

      В Вашем случае должно быть примерно так:

      if(standby==1){menu=100;lcd.setCursor(0,0);lcd.print(" POWER OFF ");}
      if(analogRead(A1)>900&&standby==1){standby=0;lcd.clear();lcd.setCursor(0,0);lcd.print(" POWER ON ");digitalWrite(11,HIGH);delay(1000);menu=0;w2=1;}
      if(analogRead(A1)>900&&standby==0){standby=1;lcd.clear();digitalWrite(11,LOW);delay(500);menu=100;}

  5. Продолжаю экспериментировать со схемой , появились некоторые результаты.
    Изменил функциональность пульта:

    1.Добавил функцию -20dB.
    2.Задействовал кнопку МЕНЮ (аналог стрелка вверх).
    3.Согласно Вашим подсказкам добавил кнопки Сеть и громкость.
    4.Дополнительно добавил на пульте две кнопки для пошаговой
    регулировки громкости (по 1dB) — удобно , когда надо чуть-чуть
    прибавить или убавить.
    5.Регулировки тембра и баланса тоже перевёл на пошаговый режим —
    мне так удобнее.

    Также подстроил чувствительность под имеющийся усилитель
    мощности (QUAD 405 из китайского набора).
    Для этого GAIN входов установил 0dB,а выходной аттенюатор на 14 (int att=14).

    Появились предложения по дальнейшей модернизации устройства:

    1.Сделать несколько ячеек памяти для текущих значений регулировок.
    Например слушаю я музыку на каких-то комфортных мне значениях тембров и
    громкости , нажимаю на пульте кнопку программирования а затем цифру 1-
    и текущие значения пишутся в ячейку 1.
    В следующий раз , чтобы вернуться к этим значениям, мне достаточно нажать
    цифру 1.
    Ячейки три было-бы достаточно.

    2.Сделать регулировку яркости подсветки (D11 поддерживает ШИМ ,можно также
    использовать A2 или A3 — с выхода через резистор на базу транзистора , коллектор
    транзистора — на светодиод подсветки дисплея).
    Регулировать с пульта (две кнопки) или энкодером.

    1. Запись и чтение параметров:

      int save,brig;

      if(ir.value==кнопка_запись){save=1;gr1=0;gr2=0;cl();}// активация записи

      if(ir.value==кнопка_1&&save==1){ // запись параметров на кнопку 1 если перед этим нажата кнопка save
      EEPROM.update(100,vol);
      EEPROM.update(101,balans+4);
      EEPROM.update(102,bass+7);
      EEPROM.update(103,treb+7);
      cl();
      lcd.clear();lcd.setCursor(0,0);lcd.print(" SAVE ");
      delay(1000);save=0;
      }

      if(ir.value==кнопка_1&&save==0){ // чтение параметров кнопки 1
      vol = EEPROM.read(100);// vol eeprom
      balans = EEPROM.read(101)-4;// balans eeprom
      bass = EEPROM.read(102)-7;// bass eeprom
      treb = EEPROM.read(103)-7;// treb eeprom
      cl();
      audio();
      }

      С шим регулированием яркости все просто, надо задействовать две кнопки пульта:

      if(ir.value==кнопка_яркость+){brig++;cl();
      analogWrite (11, brig);
      if(brig>255){brig=255;}
      }

      if(ir.value==кнопка_яркость-){brig--;cl();
      analogWrite (11, brig);
      if(brig<0){brig=0;}
      }

  6. Ради интереса заполнил все 9 цифр пульта фиксированными настройками.
    Думал , памяти не хватит , оказалось — всё нормально работает.
    При отключении питания всё сохраняется.
    Подсветку дисплея пока сделал просто отключаемой с пульта.
    Шим на D11 у меня что-то не заработал.
    Записываешь на выход 255 — подсветка загорается.
    Записываешь 254 и ниже — подсветка гаснет.

  7. Это писал — не помогает. Я же посылаю туда 255 — и выход включается.

    Ещё немного о фиксированных настройках.

    Надо в режиме чтения выводить на дисплей надпись (MODE 1,например) при нажатии цифры 1.
    А то сейчас при переключении фиксированных настроек у меня просто на несколько секунд
    исчезает шкала громкости ,а потом появляется опять.

    И ещё из опыта эксплуатации.
    После загрузки скетча с фиксированными настройками следует записать во все ячейки
    какие-то средние значения.Иначе вы рискуете при случайном нажатии на какую-нибудь цифру,
    в которую ничего не записали получить акустический удар по ушам (я чуть не оглох).
    Потому-что в ячейках по умолчанию записаны максимальные значения.

    1. С ШИМ надо разбираться, возможно не получится, библиотека таймера или ИК пульт используют одинаковый таймер с ШИМ.

      if(EEPROM.read(999)!=0){for(int i=0;i<999;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении

      установить все ячейки в 0, этот код работает только один раз, но его можно не удалять

      В код выбора кнопки добавить перед audio()

      lcd.setCursor(0,0);lcd.print(» MODE_1 «);delay(2000);

  8. Я и без шима обойдусь.Можно получить два значения яркости с помощью двух выходов.
    Один выход подключает подсветку напрямую, другой — через резистор 470 ом (этот вариант
    я сегодня уже опробовал).

    А lcd.clear() не надо , как в случае с » SAVE » ?

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

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