1

Тема: TDA7468 - обновленная библиотека (полный функционал)

Данный контент доступен только зарегистрированным пользователям.


TDA7468.h

// rcl-radio.ru liman324@yandex.ru 
// Библиотека протестирована

#ifndef TDA7468_H
#define TDA7468_H

#define TDA7468_address 0x44

//Sub addresses
#define TDA7468_INPUT_SELECT   0b00000000
#define TDA7468_INPUT_GAIN     0b00000001
#define TDA7468_SURROUND       0b00000010
#define TDA7468_VOLUME_LEFT    0b00000011
#define TDA7468_VOLUME_RIGHT   0b00000100
#define TDA7468_TREBLE_BASS    0b00000101
#define TDA7468_OUTPUT         0b00000110
#define TDA7468_BASS_ALC       0b00000111

#include <Arduino.h>
class TDA7468
{
  public:
    TDA7468();
	void setInput(int input, int mute_mic, int mic);           // input 0...4 === IN1...IN4 
                                                                   // mute_mic 0...1 === OFF...ON
                                                                   // mic 0...3 === gain 14dB...0dB // mic 4 === OFF 

	void setGain(int gain);                                  // 0...7 0...14 dB // step 2dB
	void setSurround(int sur, int gain1, int mix, int buf);   // sur 1 on 0 off // gain 0...3 // mix 0...7 // buf 1 on 0 off
	void setVol_R(int vol_r);                                // 0...62 
	void setVol_L(int vol_l);                                // 0...62
	void setTreb_Bass(int treb, int bass);                   // -14...14 step 2 dB
        void setOutput(int output);                              // mute 0 on 1 off
        void setAlc(int mode, int detector, int circ, int attack, int tresh, int rez);
                 // mode 1 on 0 off 
                 // detector 1 on 0 off 
                 // circ 1 on 0 off 
                 // attack 12k5 25k 50k 100k 0...3
                 // tresh 700mVrms 485mVrms 320mVrms 170mVrms 0...3
                 // rez MODE 1: Fixed Resistor / MODE 2: Adaptive 0...1
  private:
	void writeWire(char a, char b);
};
	
#endif //TDA7468_H

TDA7468.cpp

#include <Arduino.h>
#include <Wire.h>
#include "TDA7468.h"

TDA7468::TDA7468(){
	Wire.begin();
}

void TDA7468::setInput(int input, int mute_mic, int mic){
  switch (input) {
        case 0: input = 0b00000000 + (mute_mic << 2) + (mic << 3);break;
	case 1: input = 0b00000001 + (mute_mic << 2) + (mic << 3);break;
	case 2: input = 0b00000010 + (mute_mic << 2) + (mic << 3);break;
	case 3: input = 0b00000011 + (mute_mic << 2) + (mic << 3);break;
  }
  writeWire(TDA7468_INPUT_SELECT,input);	
  } 

void TDA7468::setGain(int gain){
  switch (gain) {
        case 0: gain = 0b00000000;break;
	case 1: gain = 0b00000001;break;
	case 2: gain = 0b00000010;break;
	case 3: gain = 0b00000011;break;
        case 4: gain = 0b00000100;break;
	case 5: gain = 0b00000101;break;
	case 6: gain = 0b00000110;break;
	case 7: gain = 0b00000111;break;
  }
  writeWire(TDA7468_INPUT_GAIN,gain);	
  } 

void TDA7468::setSurround(int sur, int gain1, int mix, int buf){
  switch (sur) {
        case 0: sur = 0b00000001;break;
	case 1: sur = 0b00000000;break;
  }
  switch (gain1) {
        case 0: gain1 = 0b00000000;break;
	case 1: gain1 = 0b00000010;break;
        case 2: gain1 = 0b00000100;break;
	case 3: gain1 = 0b00000110;break;
  }
  switch (mix) {
        case 0: mix = 0b00000000;break;
	case 1: mix = 0b00001000;break;
        case 2: mix = 0b00010000;break;
	case 3: mix = 0b00011000;break;
	case 4: mix = 0b00100000;break;
	case 5: mix = 0b00101000;break;
	case 6: mix = 0b00110000;break;
	case 7: mix = 0b00111000;break;
  }
  switch (buf) {
        case 0: buf = 0b01000000;break;
	case 1: buf = 0b00000000;break;
  }
        int sum_sur = sur + gain1 + mix + buf;
  writeWire(TDA7468_SURROUND,sum_sur);	
  } 

void TDA7468::setVol_R(int vol_r){
    vol_r = 62-vol_r;
  writeWire(TDA7468_VOLUME_RIGHT,vol_r);	
  } 

void TDA7468::setVol_L(int vol_l){
    vol_l = 62-vol_l;
  writeWire(TDA7468_VOLUME_LEFT,vol_l);	
  } 

void TDA7468::setTreb_Bass(int treb, int bass){
  switch (treb) {
        case -7: treb = 0b00000000;break;
	case -6: treb = 0b00000001;break;
	case -5: treb = 0b00000010;break;
	case -4:  treb = 0b00000011;break;
        case -3:  treb = 0b00000100;break;
	case -2:  treb = 0b00000101;break;
	case -1:  treb = 0b00000110;break;
	case  0:  treb = 0b00000111;break;
        
        case 7: treb = 0b00001000;break;
	case 6: treb = 0b00001001;break;
	case 5: treb = 0b00001010;break;
	case 4:  treb = 0b00001011;break;
        case 3:  treb = 0b00001100;break;
	case 2:  treb = 0b00001101;break;
	case 1:  treb = 0b00001110;break;
  }
  switch (bass) {
        case -7: bass = 0b00000000;break;
	case -6: bass = 0b00010000;break;
	case -5: bass = 0b00100000;break;
	case -4:  bass = 0b00110000;break;
        case -3:  bass = 0b01000000;break;
	case -2:  bass = 0b01010000;break;
	case -1:  bass = 0b01100000;break;
	case  0:  bass = 0b01110000;break;
        
        case 7: bass = 0b10000000;break;
	case 6: bass = 0b10010000;break;
	case 5: bass = 0b10100000;break;
	case 4:  bass = 0b10110000;break;
        case 3:  bass = 0b11000000;break;
	case 2:  bass = 0b11010000;break;
	case 1:  bass = 0b11100000;break;
  }
        int sum_treb_bass = treb + bass;
  writeWire(TDA7468_TREBLE_BASS, sum_treb_bass);	
  } 

void TDA7468::setOutput(int output){
  switch (output) {
        case 0: output = 0b00000000;break;
	case 1: output = 0b00000001;break;
  }
  writeWire(TDA7468_OUTPUT, output);	
  } 

void TDA7468::setAlc(int mode, int detector, int circ, int attack, int tresh, int rez){
  switch (mode) {
        case 0: mode = 0b00000001;break;
	case 1: mode = 0b00000000;break;
  }
  switch (detector) {
        case 0: detector = 0b00000010;break;
	case 1: detector = 0b00000000;break;
  }
  switch (circ) {
        case 0: circ = 0b00000100;break;
	case 1: circ = 0b00000000;break;
  }
  switch (attack) {
        case 0: attack = 0b00000000;break;
	case 1: attack = 0b00001000;break;
        case 2: attack = 0b00010000;break;
	case 3: attack = 0b00011000;break;
  }
  switch (tresh) {
        case 0: tresh = 0b00000000;break;
	case 1: tresh = 0b00100000;break;
        case 2: tresh = 0b01000000;break;
	case 3: tresh = 0b01100000;break;
  }
  switch (rez) {
        case 0: rez = 0b00000000;break;
	case 1: rez = 0b10000000;break;
  }
        int sum_alc = mode + detector + circ + attack + tresh + rez;
  writeWire(TDA7468_BASS_ALC ,sum_alc);	
  } 


void TDA7468::writeWire(char a, char b){
  Wire.beginTransmission(TDA7468_address);
  Wire.write (a);
  Wire.write (b);
  Wire.endTransmission();
}

test.ino

#include <Wire.h>
#include <TDA7468.h>
  TDA7468 tda;
  
void setup(){ 
  Serial.begin(9600);Wire.begin();
}

void loop(){
  audio();
  delay(1000);
}
// http://rcl-radio.ru/wp-content/uploads/2019/05/tda7468.pdf
void audio(){
  tda.setInput(0,0,0); 
   // setInput(input,mute_mic,mic)
       // input 0...4 === IN1...IN4 
       // mute_mic 0...1 === OFF...ON
       // mic 0...3 === gain 14dB...0dB // mic 4 === OFF 
///////////////////////////////////////////////////////////////       
  tda.setGain(0);
  //  setGain(gain);
       // gain 0...7 === 0...14 dB // step 2dB
//////////////////////////////////////////////////////////////       
  tda.setSurround(0,0,0,0);
  //  setSurround(sur,gain,mix,buf); 
       // sur 1 === on // 0 === off (SURROUND MODE)
       // gain 0...3 === 0...12 dB  (GAIN)
       // mix 0...7                 (MIXING)
       // buf 1 === on // 0 === off (BUFFER GAIN)    
  tda.setVol_R(62); // VOLUME R 0...62
  tda.setVol_L(62); // VOLUME L 0...62
  tda.setTreb_Bass(0,0); // -14...14 step 2 dB (TREBLE,BASS)
  tda.setOutput(1); // MUTE 0 === ON // 1 === OFF
  tda.setAlc(0,0,0,0,0,0);
  //  setAlc(mode,detector,circ,attack,tresh,rez);
       // mode 1 on 0 off 
       // detector 1 on 0 off 
       // circ 1 on 0 off 
       // attack 12k5 25k 50k 100k 0...3
       // tresh 700mVrms 485mVrms 320mVrms 170mVrms 0...3
       // rez MODE 1: Fixed Resistor / MODE 2: Adaptive 0...1
}

2 (2020-11-27 05:12:27 отредактировано dimb0t)

Re: TDA7468 - обновленная библиотека (полный функционал)

test.ino

#include <Wire.h>
#include <TDA7468.h>
  TDA7468 tda;
  
void setup(){ 
  Serial.begin(9600);Wire.begin();
}

void loop(){
  audio();
  delay(1000);
}
// http://rcl-radio.ru/wp-content/uploads/2019/05/tda7468.pdf
void audio(){
  tda.setInput(0,0,0); 
   // setInput(input,mute_mic,mic)
       // input 0...4 === IN1...IN4 //выбор входа
       // mute_mic 0...1 === OFF...ON //при включении входы переходят в режим MUTE, в звуковом тракте остаётся микрофон, если его вход активирован
       // mic 0...3 === gain 14dB...0dB // mic 4 === OFF //активация микрофонного входа и установка предусиления для него
///////////////////////////////////////////////////////////////       
  tda.setGain(0);
  //  setGain(gain);
       // gain 0...7 === 0...14 dB // step 2dB //установка предусиления
//////////////////////////////////////////////////////////////       
  tda.setSurround(0,0,0,0);
  //  setSurround(sur,gain,mix,buf); 
       // sur 1 === on // 0 === off (SURROUND MODE)
       // gain 0...3 === 0...12 dB  (GAIN)
       // mix 0...7                 (MIXING)
       // buf 1 === on // 0 === off (BUFFER GAIN)    
  tda.setVol_R(62); // VOLUME R 0...62 //регулирование громкости правого канала
  tda.setVol_L(62); // VOLUME L 0...62 //регулирование громкости левого канала
  tda.setTreb_Bass(0,0); // -14...14 step 2 dB (TREBLE,BASS)
  tda.setOutput(1); // MUTE 0 === ON // 1 === OFF //активация режима MUTE для выхода всего звукового тракта
  tda.setAlc(0,0,0,0,0,0);
  //  setAlc(mode,detector,circ,attack,tresh,rez);
       // mode 1 on 0 off 
       // detector 1 on 0 off 
       // circ 1 on 0 off 
       // attack 12k5 25k 50k 100k 0...3
       // tresh 700mVrms 485mVrms 320mVrms 170mVrms 0...3
       // rez MODE 1: Fixed Resistor / MODE 2: Adaptive 0...1
}

Протестировал разделы tda.setInput и tda.setGain, подписал.
Регулировка громкости и тембра работает (tda.setVol и setTreb_Bass).
Surround и ALC позже.

А ещё сомнения в необходимости наличия функции спектроанализатора. Информативности никакой, украшательство, не более. Тем более скетч и так большой, после компиляции Arduino IDE сообщает, что памяти мало. АЦП опять же настраивать. Запускать его геморрой - две кнопки жми и не абы как, а в определённой последовательности...

И вот ещё что. Зачем кнопка "IN" нужна? Может использовать вариант короткое/длительное нажатие на кнопку энкодера? На моём устройстве эта дополнительная кнопка как бельмо в глазу. Нет, правда!

3

Re: TDA7468 - обновленная библиотека (полный функционал)

Что касается BASS ALC. Найти вразумительное описание работы этой системы мне не удалось, но.

В даташите имеется таблица 15 "Bass Automatic Level Control (ALC)", график 9 "Threshold curve" (пороговые напряжения) и график 10 "THD" (показатель искажений при разных величинах коррекции). Они иллюстрируют работу системы ALC.

Судя по блок-схеме, с выходов микросхемы через сумматор сигнал поступает на детектор (Half Wave Rectifier). Продетектированный сигнал выделяется на резистивном делителе, состоящем из внутреннего программно изменяемого резистора (Attack Time Resistor) и внешнего, подключенного к выводу 16 резистора номиналом 1МОм. Внутренний резистор может изменять сопротивление от 12,5 до 100 кОм и имеет два режима (Attack Mode). MODE 1: Fixed Resistor с дискретными значениями сопротивления 12,5 ,25, 50 и 100 кОм; MODE 2: Adaptive с подстраивающимся (адаптивным) сопротивлением, очевидно зависящим от уровня НЧ в выходном сигнале. Со средней точки резистивного делителя система автоматического регулирования воздействует непосредственно на частотозадающие цепи НЧ корректора, в результате изменяя как уровень НЧ сигнала на выходе, так и подъём АЧХ на НЧ.

Таким образом, система автоматически корректирует (регулирует, изменяет) максимальную выходную синусоидальную мощность НЧ сигнала (RMS) звукового тракта, приводя его к неким стандартам. В таблице перечислены верхние пороговые (Threshold) значения выходного напряжения: 700, 485, 320 и 170 mVrms.

Итак, по таблице 15 и терминам имеем:
- BASS ALC (Bass Automatic Level Control) - автоматическое регулирование уровня низкочастотного сигнала.
- ALC Mode (on/off) - включение/выключение режима автоматического регулирования.
- Detector (on/off) - включение/выключение детектора НЧ составляющей на выходе.
- Release Current Circuit (on/off) - включение/выключение источника тока. Согласно распиновке на рисунке 17 даташита, источник тока устанавливает режим работы дифференциального каскада системы регулирования.
- Attack Time Resistor (12,5 ,25, 50 и 100 кОм) - программно устанавливаемый резистор делителя, формирующего сигнал управления системой регулирования.
- Threshold (700, 485, 320 и 170 mVrms) - пороговые уровни ограничения НЧ сигнала на выходе процессора, также устанавливаемые программно.
- Attack Mode (выбор режима работы резистора делителя Attack Time Resistor), MODE 1: Fixed Resistor с фиксированным и установленным ранее значением сопротивления и MODE 2: Adaptive с изменяющимся сопротивлением плеча делителя в зависимости от уровня НЧ составляющей в выходном сигнале.

Это всё, что мне удалось выжать из даташита. Но осталось ещё несколько вопросов относительно логики взаимодействия узлов системы. Например, что будет, если ALC включить, но выключить Detector или выключить Release Current Circuit? Что тогда станет делать система регулирования? И зачем предусмотрена возможность выключать детектор и источник тока, если система активирована? Ведь это ключевые блоки автоматики...

Буду благодарен за конструктивные поправки и дополнения.

О тестировании блока tda.setAlc в тестовом скетче сообщу чуть позже.

С реализацией в TDA7468 режима Surround в двухканальном варианте (идиотизм, конечно же), как там миксуются инвертированные и неинвертированные сигналы, - также постараюсь разобраться чуть позже.

4

Re: TDA7468 - обновленная библиотека (полный функционал)

И вот ещё что. Зачем кнопка "IN" нужна? Может использовать вариант короткое/длительное нажатие на кнопку энкодера? На моём устройстве эта дополнительная кнопка как бельмо в глазу. Нет, правда!

Это можно сделать, будет только один энкодер

Буду благодарен за конструктивные поправки и дополнения.

Когда Вы все протестируете, то часть настроек сделаете по умолчанию, а часть настраиваемых через меню. Необходимые Вам пункты меню я добавлю в скетч (скорее всего напишу полностью новый).

5

Re: TDA7468 - обновленная библиотека (полный функционал)

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

Поэтому снова опираясь на даташит позволю себе предположить следующее. Согласно блок-схеме полезный сигнал после селектора и предусилителя поступает на линейный выход (выводы  7 и 22) и на внутренний смеситель. Сейчас я говорю об одном канале. Во втором всё происходит также и там свой селектор, предусилитель и смеситель. В простейшем случае линейный выход (выводы 7, 22) нагружен на резистор и с него через переходной конденсатор сигнал вновь возвращается в микросхему через входы 8 и 21. Это входы фазоинверторов, соответственно левого и правого каналов. А дальше инвертированный сигнал левого канала идёт на смеситель правого и инвертированный сигнал правого канала - на смеситель левого. Далее через аттенюаторы, тон-корректоры и буферные каскады - к выходу. Именно такой коктейль, по мнению разработчиков, создаёт эффект Surround и слушатель воспринимает это как расширение стереобазы и увеличение объёма звука.

Что мы имеем в сухом остатке? По таблице 9 "SURROUND":
- SURROUND MODE (on/off) - включение/выключение режима Surround.
- GAIN (0, 6, 9, 12dB) - предусиление фазоинверторов перед подмешиванием сигнала в соседний канал.
- MIXING - фазоинвертор с программно устанавливаемыми режимами (inverting 100%, 50%, 25%, 0%, non inverting 100%, 75%, 50%, mute). Mute - по всей видимости отключает фазоинвертор.
- BUFFER GAIN (0 dB, 6 dB) - предусиление буфера. Буфер на блок-схеме не показан, однако нужен для согласования между каскадами и/или для осуществления небольшой задержки сигнала перед смесителем.

Снова надеюсь на поправки и дополнения по существу изложенного выше! Мог где-то ошибиться или допустить неточность в изложении.

6

Re: TDA7468 - обновленная библиотека (полный функционал)

Данный контент доступен только зарегистрированным пользователям.

#include <Wire.h>
#include <TDA7468.h>
  TDA7468 tda;
  
void setup(){ 
  Serial.begin(9600);Wire.begin();
}

void loop(){
  audio();
  delay(1000);
}
// http://rcl-radio.ru/wp-content/uploads/2019/05/tda7468.pdf
void audio(){
  tda.setInput(1,0,0); // INPUT SELECT & MIC - установки входных цепей и микрофонного входа;
                       // INPUT SELECT 0...4 === IN1...IN4 - выбор входа;
                       // MUTE (IN5) 0 off 1 on (IN5) - при включении входы IN1...IN4 переходят в режим MUTE, в звуковом тракте остаётся микрофон (вход IN5), если он активирован;
                       // MIC 0...3 === gain 14dB...0dB // mic 4 === OFF - активация микрофонного входа (IN5) и установка предусиления для него;
///////////////////////////////////////////////////////////////       
  tda.setGain(2); // INPUT GAIN - установка предварительного усиления;
                  // gain 0...7 === 0...14 dB  step 2dB;
//////////////////////////////////////////////////////////////       
  tda.setSurround(0,2,0,0); // SURROUND - установки режима объёмного звука; 
                            // SURROUND MODE 1 on 0 off - активация режима объёмного звука;
                            // GAIN 0...3 === 0...12 dB - предусиление фазоинверторов перед подмешиванием сигнала в соседний канал;
                            // MIXING 0...7 === inverting 100%, 50%, 25%, 0%, non inverting 100%, 75%, 50%, mute - установка режима фазоинверторов;
                            // BUFFER GAIN 1...0 === 0dB...6dB - установка режима буферного каскада;    
  tda.setVol_R(35); // VOLUME R 0...62 - регулирование уровня правого канала;
  tda.setVol_L(35); // VOLUME L 0...62 - регулирование уровня левого канала;
  tda.setTreb_Bass(3,7); // TREBLE & BASS SELECTION -14...14 step 2 dB - коррекция тона ВЧ-НЧ. Когда бас установлен в диапазоне-14dB...0dB, ALC автоматически переключается в положение "OFF";
  tda.setOutput(1); // OUTPUT - установка выхода;
                    // MUTE 0...1 === ON...OFF - активация режима MUTE для выхода всего звукового тракта;
  tda.setAlc(0,0,0,0,0,0); // BASS ALC - установки автоматической регулировки уровня низких частот;
                           // ALC Mode 1 on 0 off - включение/выключение режима автоматического регулирования;
                           // Detector 1 on 0 off - включение/выключение детектора НЧ составляющей на выходе;
                           // Release Current Circuit 1 on 0 off - включение/выключение источника тока;
                           // Attack Time Resistor 0...3 === 12k5, 25k, 50k, 100k - резистор делителя, формирующего сигнал управления системой ALC;
                           // Threshold 0...3 === 700mVrms, 485mVrms, 320mVrms, 170mVrms, - пороговые уровни ограничения НЧ сигнала на выходе;
                           // Attack Mode - режим резистора делителя Attack Time Resistor - 0...1 === MODE 1: Fixed Resistor ... MODE 2: Adaptive - фиксированное значение/адаптивное значение;
 }

Протестировал. Два момента. На слух не могу понять включается ли и работает ли Bass ALC. Но видимо мой слух пороги ограничения не улавливает. И второе. Какой-то косяк с блоком Surround. Если эту систему не активировать, то всё равно работают настройки предусиления, фазоинвертора и буфера. А вот если включаю режим Mute в настройках фазоинвертора (последний пункт в таблице), то звук вообще пропадает. Хотя по логике если есть режим Mute на входах, есть на выходах отдельно, то режим Mute в настройках фазоинвертора по идее должен просто отключить сам фазоинвертор, но звук должен оставаться.

Остальное вроде адекватно реагирует на настройку.

7

Re: TDA7468 - обновленная библиотека (полный функционал)

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

8

Re: TDA7468 - обновленная библиотека (полный функционал)

А что с косяком в блоке Surround?

9

Re: TDA7468 - обновленная библиотека (полный функционал)

А что с косяком в блоке Surround?

- пока не знаю, надо подумать.

Я сделал промежуточный скетч, в нем меню громкости, тембра, выбора входа и регулировка предусиления каждого входа.
Для активации меню входа нажмите кнопку энкодера и удерживайте ее 2 сек, появится меню входа, кнопка энкодера меняет вход, поворот ручки энкодера меняет предусиление. Все параметры заносятся в память.

Экран под i2c, если это Вам не подходит, поправлю под параллельное подключение.

Протестируйте, а далее укажите какие меню в какой последовательности сделать. Один параметр на одно меню. Я так понимаю кнопок у Вас не будет, только энкодер? Я обычно под редко меняемые параметры делаю отдельное меню которое активируется кнопкой. Так же под функцию mute и power (standby) тоже отвожу отдельные кнопки.

#include <Wire.h>
#include <TDA7468.h>
#include <EEPROM.h>
#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 <MsTimer2.h> // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip
#include <LiquidCrystal_I2C.h> //Библиотека -  http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
 LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей 
 Encoder myEnc(8, 9);//CLK, DT
  TDA7468 tda;
  IRrecv irrecv(12);  //  D12 = IR
  decode_results ir;

  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 power,menu,menu_in,in,xd,x,gain0,gain1,gain2,gain3,gain4,w,w2,www,vol,vol_d,z,z0,z1;
  int bas,treb;
  unsigned long oldPosition  = -999,newPosition,times,times1;
  
void setup(){ 
   Wire.begin();
   Serial.begin(9600);
   MsTimer2::set(1, to_Timer);MsTimer2::start();
   lcd.init();lcd.backlight();irrecv.enableIRIn();
   pinMode(10,INPUT);   // SW кнопка энкодера
   lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
   if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}} 
   in=EEPROM.read(0);vol=EEPROM.read(1);gain1=EEPROM.read(2);gain2=EEPROM.read(3);gain3=EEPROM.read(4);
   gain4=EEPROM.read(5);bas=EEPROM.read(6);treb=EEPROM.read(7);
   audio();
}

void loop(){
 //////////////// INPUT MENU //////////////////////////////////////////////////////////
  Serial.println(in);
  if(power==0){
  if(digitalRead(10)==LOW && menu_in==0){x++;xd=1;delay(200);}
  if(digitalRead(10)==HIGH && menu_in==0 && x>0){xd=1;x=0;times1=millis();}
  if(x > 10){menu_in=1;lcd.clear();lcd.setCursor(0,0);lcd.print(F("   INPUT MENU    "));delay(2000);lcd.clear(); times1 = millis();}
  if(menu_in==1){menu=0;x=0;if(digitalRead(10)==LOW){times1 = millis();in++;if(in>3){in = 0;}
  audio();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;}
     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;} 
    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;}}  
  if(digitalRead(10)==HIGH && millis()-times1>5000 && menu_in==1){x=0;menu=-1;menu_in=0;times1=millis();lcd.clear();w2=1;}
  if(digitalRead(10)==HIGH && xd == 1 && menu_in==0){menu++;times=millis();w=1;w2=1;xd=0;lcd.clear();if(menu>7){menu=0;}}
  }
  ///////////////// END INPUT MENU /////////////////////////////////////////////////////// 

  /////////////////////////////// VOLUME 0...62 ////////////////////////////////////////////////
 if(menu==0 && menu_in==0 && power==0){
  
   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(vol);
     vol_d=map(vol, 0,62, 0, 48);
     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;} 

   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(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;}}
  ////////////////////// VOLUME END ////////////////////////////////////////////

  ///////////////////////// BASS +/-14 dB /////////////////////////////////////////////////////////
   if(menu==1){
     
   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*2-14>=0){lcd.print(F("+"));}lcd.print(bas*2-14);lcd.print(" ");lcd.setCursor(13,0);lcd.print(F("dB"));
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=(bas+1)*2;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 (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*2-14>=0){lcd.print(F("+"));}lcd.print(treb*2-14);lcd.print(" ");lcd.setCursor(13,0);lcd.print(F("dB"));
   if(w2==1){
   for(z=0,z0=0,z1=0;z<=(treb+1)*2;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 //////////////////////////////////
  
 ////////////// EEPROM ///////////////////////////////////////////////////
 if(millis()-times>10000 && w==1 && power==0){
     EEPROM.update(0,in);EEPROM.update(1,vol);
     EEPROM.update(2,gain1);EEPROM.update(3,gain2);EEPROM.update(4,gain3);EEPROM.update(5,gain4);
     EEPROM.update(6,bas);EEPROM.update(7,treb);
     menu=0;w=0;w2=1;cl();}
 
} 
  void cl(){ir.value=0;delay(300);lcd.clear();}
  void vol_func(){if(vol>62){vol=62;}if(vol<0){vol=0;}}
  void gain_func(){if(gain0>7){gain0=7;}if(gain0<0){gain0=0;}}
  void treb_func(){if(treb>14){treb=14;}if(treb<0){treb=0;}}
  void bass_func(){if(bas>14){bas=14;}if(bas<0){bas=0;}}
  void audio(){
  tda.setInput(in,0,0); // INPUT SELECT & MIC - установки входных цепей и микрофонного входа;
                       // INPUT SELECT 0...4 === IN1...IN4 - выбор входа;
                       // MUTE (IN5) 0 off 1 on (IN5) - при включении входы IN1...IN4 переходят в режим MUTE, в звуковом тракте остаётся микрофон (вход IN5), если он активирован;
                       // MIC 0...3 === gain 14dB...0dB // mic 4 === OFF - активация микрофонного входа (IN5) и установка предусиления для него;
///////////////////////////////////////////////////////////////       
  tda.setGain(gain0); // INPUT GAIN - установка предварительного усиления;
                      // gain 0...7 === 0...14 dB  step 2dB;
//////////////////////////////////////////////////////////////       
  tda.setSurround(0,2,0,0); // SURROUND - установки режима объёмного звука; 
                            // SURROUND MODE 1 on 0 off - активация режима объёмного звука;
                            // GAIN 0...3 === 0...12 dB - предусиление фазоинверторов перед подмешиванием сигнала в соседний канал;
                            // MIXING 0...7 === inverting 100%, 50%, 25%, 0%, non inverting 100%, 75%, 50%, mute - установка режима фазоинверторов;
                            // BUFFER GAIN 1...0 === 0dB...6dB - установка режима буферного каскада;    
  tda.setVol_R(vol); // VOLUME R 0...62 - регулирование уровня правого канала;
  tda.setVol_L(vol); // VOLUME L 0...62 - регулирование уровня левого канала;
  tda.setTreb_Bass(treb,bas); // TREBLE & BASS SELECTION -14...14 step 2 dB - коррекция тона ВЧ-НЧ. Когда бас установлен в диапазоне-14dB...0dB, ALC автоматически переключается в положение "OFF";
  tda.setOutput(1); // OUTPUT - установка выхода;
                    // MUTE 0...1 === ON...OFF - активация режима MUTE для выхода всего звукового тракта;
  tda.setAlc(0,0,0,0,0,0); // BASS ALC - установки автоматической регулировки уровня низких частот;
                           // ALC Mode 1 on 0 off - включение/выключение режима автоматического регулирования;
                           // Detector 1 on 0 off - включение/выключение детектора НЧ составляющей на выходе;
                           // Release Current Circuit 1 on 0 off - включение/выключение источника тока;
                           // Attack Time Resistor 0...3 === 12k5, 25k, 50k, 100k - резистор делителя, формирующего сигнал управления системой ALC;
                           // Threshold 0...3 === 700mVrms, 485mVrms, 320mVrms, 170mVrms, - пороговые уровни ограничения НЧ сигнала на выходе;
                           // Attack Mode - режим резистора делителя Attack Time Resistor - 0...1 === MODE 1: Fixed Resistor ... MODE 2: Adaptive - фиксированное значение/адаптивное значение;
}

void to_Timer(){newPosition = myEnc.read()/4;}

10 (2020-11-28 03:04:29 отредактировано dimb0t)

Re: TDA7468 - обновленная библиотека (полный функционал)

После закрузки скетча экран индицирует "VOLUME 0 AUX1". Через несколько секунд подсветка экрана гаснет. На энкодер никакой реакции. Подключил согласно указаний в скетче.

Подсветка экрана как-то бессистемно помигивает иногда.

Сигналы от пульта ИК в монитор порта не шлются (молчит монитор).

11

Re: TDA7468 - обновленная библиотека (полный функционал)

У меня все работает, регулируется, сохраняется в память, только без TDA. У Вас клинит шину i2c.

12

Re: TDA7468 - обновленная библиотека (полный функционал)

Без TDA у меня тоже заработало. Короткими кликами перебираются громкость, тембр, потом несколько пустых окон. Длинный клик - выхожу в меню выбора входа. Я правильно понимаю, что дисплей и TDA висят на одной шине  i2c? По отдельности нормально. Вместе не хотят работать. У меня подозрение на модуль расширения i2c. Беру паузу. Модуль у меня один, я с ним когда-то экспериментировал, может он приболел от этого. Новый купить смогу через пару дней.

13

Re: TDA7468 - обновленная библиотека (полный функционал)

Подтягивающие резисторы на шине i2c стоят?

14

Re: TDA7468 - обновленная библиотека (полный функционал)

Ёптыть, нет. А нужны?

15

Re: TDA7468 - обновленная библиотека (полный функционал)

Шина бывает что не тянет 2 уст-ва, ее клинит. На выводы SDA SCL tda7468 надо подать 5В (от ардуино) через 4,7 К

16

Re: TDA7468 - обновленная библиотека (полный функционал)

Сканер i2c должен показать два адреса http://forum.rcl-radio.ru/viewtopic.php?id=64
В крайнем случае можно перейти на паралельное подключение.
Бывает что провода i2c длинные, тоже плохо, чем короче тем лучше.

17 (2020-11-28 17:56:09 отредактировано dimb0t)

Re: TDA7468 - обновленная библиотека (полный функционал)

Да, я совсем выпустил из головы этот момент. Но всё равно продолжить смогу через пару дней. Мне пришлось по делам выехать из города. Я чуть позже напомню о себе. Спасибо за умное замечание :-)

И да. Параллельное подключение оставим на крайний случай. I2C рациональнее и удобнее.

18

Re: TDA7468 - обновленная библиотека (полный функционал)

И снова здрасссте!

Железные проблемы решены. Всё светится и регулируется. Высокие и низкие регулируются неадекватно. Там что-то напутано.

19

Re: TDA7468 - обновленная библиотека (полный функционал)

Тембр я поправил, проверьте

#include <Wire.h>
#include <TDA7468.h>
#include <EEPROM.h>
#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 <MsTimer2.h> // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip
#include <LiquidCrystal_I2C.h> //Библиотека -  http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
 LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей 
 Encoder myEnc(8, 9);//CLK, DT
  TDA7468 tda;
  IRrecv irrecv(12);  //  D12 = IR
  decode_results ir;

  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 power,menu,menu_in,in,xd,x,gain0,gain1,gain2,gain3,gain4,w,w2,www,vol,vol_d,z,z0,z1;
  int bas,treb;
  unsigned long oldPosition  = -999,newPosition,times,times1;
  
void setup(){ 
   Wire.begin();
   Serial.begin(9600);
   MsTimer2::set(1, to_Timer);MsTimer2::start();
   lcd.init();lcd.backlight();irrecv.enableIRIn();
   pinMode(10,INPUT);   // SW кнопка энкодера
   lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
   if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}} 
   in=EEPROM.read(0);vol=EEPROM.read(1);gain1=EEPROM.read(2);gain2=EEPROM.read(3);gain3=EEPROM.read(4);
   gain4=EEPROM.read(5);bas=EEPROM.read(6)-7;treb=EEPROM.read(7)-7;
   audio();
}

void loop(){
 //////////////// INPUT MENU //////////////////////////////////////////////////////////
  Serial.println(in);
  if(power==0){
  if(digitalRead(10)==LOW && menu_in==0){x++;xd=1;delay(200);}
  if(digitalRead(10)==HIGH && menu_in==0 && x>0){xd=1;x=0;times1=millis();}
  if(x > 10){menu_in=1;lcd.clear();lcd.setCursor(0,0);lcd.print(F("   INPUT MENU    "));delay(2000);lcd.clear(); times1 = millis();}
  if(menu_in==1){menu=0;x=0;if(digitalRead(10)==LOW){times1 = millis();in++;if(in>3){in = 0;}
  audio();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;}
     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;} 
    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;}}  
  if(digitalRead(10)==HIGH && millis()-times1>5000 && menu_in==1){x=0;menu=-1;menu_in=0;times1=millis();lcd.clear();w2=1;}
  if(digitalRead(10)==HIGH && xd == 1 && menu_in==0){menu++;times=millis();w=1;w2=1;xd=0;lcd.clear();if(menu>7){menu=0;}}
  }
  ///////////////// END INPUT MENU /////////////////////////////////////////////////////// 

  /////////////////////////////// VOLUME 0...62 ////////////////////////////////////////////////
 if(menu==0 && menu_in==0 && power==0){
  
   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(vol);
     vol_d=map(vol, 0,62, 0, 48);
     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;} 

   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(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;}}
  ////////////////////// VOLUME END ////////////////////////////////////////////

  ///////////////////////// BASS +/-14 dB /////////////////////////////////////////////////////////
   if(menu==1){
     
   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*2>=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+1)*2+14;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 (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*2>=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+1)*2+14;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 //////////////////////////////////
  
 ////////////// EEPROM ///////////////////////////////////////////////////
 if(millis()-times>10000 && w==1 && power==0){
     EEPROM.update(0,in);EEPROM.update(1,vol);
     EEPROM.update(2,gain1);EEPROM.update(3,gain2);EEPROM.update(4,gain3);EEPROM.update(5,gain4);
     EEPROM.update(6,bas+7);EEPROM.update(7,treb+7);
     menu=0;w=0;w2=1;cl();}
 
} 
  void cl(){ir.value=0;delay(300);lcd.clear();}
  void vol_func(){if(vol>62){vol=62;}if(vol<0){vol=0;}}
  void gain_func(){if(gain0>7){gain0=7;}if(gain0<0){gain0=0;}}
  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 audio(){
  tda.setInput(in,0,0); // INPUT SELECT & MIC - установки входных цепей и микрофонного входа;
                       // INPUT SELECT 0...4 === IN1...IN4 - выбор входа;
                       // MUTE (IN5) 0 off 1 on (IN5) - при включении входы IN1...IN4 переходят в режим MUTE, в звуковом тракте остаётся микрофон (вход IN5), если он активирован;
                       // MIC 0...3 === gain 14dB...0dB // mic 4 === OFF - активация микрофонного входа (IN5) и установка предусиления для него;
///////////////////////////////////////////////////////////////       
  tda.setGain(gain0); // INPUT GAIN - установка предварительного усиления;
                      // gain 0...7 === 0...14 dB  step 2dB;
//////////////////////////////////////////////////////////////       
  tda.setSurround(0,2,0,0); // SURROUND - установки режима объёмного звука; 
                            // SURROUND MODE 1 on 0 off - активация режима объёмного звука;
                            // GAIN 0...3 === 0...12 dB - предусиление фазоинверторов перед подмешиванием сигнала в соседний канал;
                            // MIXING 0...7 === inverting 100%, 50%, 25%, 0%, non inverting 100%, 75%, 50%, mute - установка режима фазоинверторов;
                            // BUFFER GAIN 1...0 === 0dB...6dB - установка режима буферного каскада;    
  tda.setVol_R(vol); // VOLUME R 0...62 - регулирование уровня правого канала;
  tda.setVol_L(vol); // VOLUME L 0...62 - регулирование уровня левого канала;
  tda.setTreb_Bass(treb,bas); // TREBLE & BASS SELECTION -14...14 step 2 dB - коррекция тона ВЧ-НЧ. Когда бас установлен в диапазоне-14dB...0dB, ALC автоматически переключается в положение "OFF";
  tda.setOutput(1); // OUTPUT - установка выхода;
                    // MUTE 0...1 === ON...OFF - активация режима MUTE для выхода всего звукового тракта;
  tda.setAlc(0,0,0,0,0,0); // BASS ALC - установки автоматической регулировки уровня низких частот;
                           // ALC Mode 1 on 0 off - включение/выключение режима автоматического регулирования;
                           // Detector 1 on 0 off - включение/выключение детектора НЧ составляющей на выходе;
                           // Release Current Circuit 1 on 0 off - включение/выключение источника тока;
                           // Attack Time Resistor 0...3 === 12k5, 25k, 50k, 100k - резистор делителя, формирующего сигнал управления системой ALC;
                           // Threshold 0...3 === 700mVrms, 485mVrms, 320mVrms, 170mVrms, - пороговые уровни ограничения НЧ сигнала на выходе;
                           // Attack Mode - режим резистора делителя Attack Time Resistor - 0...1 === MODE 1: Fixed Resistor ... MODE 2: Adaptive - фиксированное значение/адаптивное значение;
}

void to_Timer(){newPosition = myEnc.read()/4;}

20

Re: TDA7468 - обновленная библиотека (полный функционал)

Теперь норм. Крайнее левое положение (минимум) громкости показывает 10. И звук ещё есть. Ноль должен быть?

21

Re: TDA7468 - обновленная библиотека (полный функционал)

Я поправил.

#include <Wire.h>
#include <TDA7468.h>
#include <EEPROM.h>
#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 <MsTimer2.h> // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip
#include <LiquidCrystal_I2C.h> //Библиотека -  http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
 LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей 
 Encoder myEnc(8, 9);//CLK, DT
  TDA7468 tda;
  IRrecv irrecv(12);  //  D12 = IR
  decode_results ir;

  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 power,menu,menu_in,in,xd,x,gain0,gain1,gain2,gain3,gain4,w,w2,www,vol,vol_d,z,z0,z1;
  int bas,treb;
  unsigned long oldPosition  = -999,newPosition,times,times1;
  
void setup(){ 
   Wire.begin();
   Serial.begin(9600);
   MsTimer2::set(1, to_Timer);MsTimer2::start();
   lcd.init();lcd.backlight();irrecv.enableIRIn();
   pinMode(10,INPUT);   // SW кнопка энкодера
   lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
   if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}} 
   in=EEPROM.read(0);vol=EEPROM.read(1);gain1=EEPROM.read(2);gain2=EEPROM.read(3);gain3=EEPROM.read(4);
   gain4=EEPROM.read(5);bas=EEPROM.read(6)-7;treb=EEPROM.read(7)-7;
   audio();
}

void loop(){
 //////////////// INPUT MENU //////////////////////////////////////////////////////////
  Serial.println(in);
  if(power==0){
  if(digitalRead(10)==LOW && menu_in==0){x++;xd=1;delay(200);}
  if(digitalRead(10)==HIGH && menu_in==0 && x>0){xd=1;x=0;times1=millis();}
  if(x > 10){menu_in=1;lcd.clear();lcd.setCursor(0,0);lcd.print(F("   INPUT MENU    "));delay(2000);lcd.clear(); times1 = millis();}
  if(menu_in==1){menu=0;x=0;if(digitalRead(10)==LOW){times1 = millis();in++;if(in>3){in = 0;}
  audio();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;}
     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;} 
    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;}}  
  if(digitalRead(10)==HIGH && millis()-times1>5000 && menu_in==1){x=0;menu=-1;menu_in=0;times1=millis();lcd.clear();w2=1;}
  if(digitalRead(10)==HIGH && xd == 1 && menu_in==0){menu++;times=millis();w=1;w2=1;xd=0;lcd.clear();if(menu>7){menu=0;}}
  }
  ///////////////// END INPUT MENU /////////////////////////////////////////////////////// 

  /////////////////////////////// VOLUME 0...62 ////////////////////////////////////////////////
 if(menu==0 && menu_in==0 && power==0){
  
   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(7,0);lcd.print(" ");}else{lcd.setCursor(7,0);}lcd.print(vol);
     vol_d=map(vol, 0,62, 0, 48);
     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;} 

   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(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;}}
  ////////////////////// VOLUME END ////////////////////////////////////////////

  ///////////////////////// BASS +/-14 dB /////////////////////////////////////////////////////////
   if(menu==1){
     
   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*2>=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+1)*2+14;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 (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*2>=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+1)*2+14;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 //////////////////////////////////
  
 ////////////// EEPROM ///////////////////////////////////////////////////
 if(millis()-times>10000 && w==1 && power==0){
     EEPROM.update(0,in);EEPROM.update(1,vol);
     EEPROM.update(2,gain1);EEPROM.update(3,gain2);EEPROM.update(4,gain3);EEPROM.update(5,gain4);
     EEPROM.update(6,bas+7);EEPROM.update(7,treb+7);
     menu=0;w=0;w2=1;cl();}
 
} 
  void cl(){ir.value=0;delay(300);lcd.clear();}
  void vol_func(){if(vol>62){vol=62;}if(vol<0){vol=0;}}
  void gain_func(){if(gain0>7){gain0=7;}if(gain0<0){gain0=0;}}
  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 audio(){
  tda.setInput(in,0,0); // INPUT SELECT & MIC - установки входных цепей и микрофонного входа;
                       // INPUT SELECT 0...4 === IN1...IN4 - выбор входа;
                       // MUTE (IN5) 0 off 1 on (IN5) - при включении входы IN1...IN4 переходят в режим MUTE, в звуковом тракте остаётся микрофон (вход IN5), если он активирован;
                       // MIC 0...3 === gain 14dB...0dB // mic 4 === OFF - активация микрофонного входа (IN5) и установка предусиления для него;
///////////////////////////////////////////////////////////////       
  tda.setGain(gain0); // INPUT GAIN - установка предварительного усиления;
                      // gain 0...7 === 0...14 dB  step 2dB;
//////////////////////////////////////////////////////////////       
  tda.setSurround(0,2,0,0); // SURROUND - установки режима объёмного звука; 
                            // SURROUND MODE 1 on 0 off - активация режима объёмного звука;
                            // GAIN 0...3 === 0...12 dB - предусиление фазоинверторов перед подмешиванием сигнала в соседний канал;
                            // MIXING 0...7 === inverting 100%, 50%, 25%, 0%, non inverting 100%, 75%, 50%, mute - установка режима фазоинверторов;
                            // BUFFER GAIN 1...0 === 0dB...6dB - установка режима буферного каскада;    
  tda.setVol_R(vol); // VOLUME R 0...62 - регулирование уровня правого канала;
  tda.setVol_L(vol); // VOLUME L 0...62 - регулирование уровня левого канала;
  tda.setTreb_Bass(treb,bas); // TREBLE & BASS SELECTION -14...14 step 2 dB - коррекция тона ВЧ-НЧ. Когда бас установлен в диапазоне-14dB...0dB, ALC автоматически переключается в положение "OFF";
  tda.setOutput(1); // OUTPUT - установка выхода;
                    // MUTE 0...1 === ON...OFF - активация режима MUTE для выхода всего звукового тракта;
  tda.setAlc(0,0,0,0,0,0); // BASS ALC - установки автоматической регулировки уровня низких частот;
                           // ALC Mode 1 on 0 off - включение/выключение режима автоматического регулирования;
                           // Detector 1 on 0 off - включение/выключение детектора НЧ составляющей на выходе;
                           // Release Current Circuit 1 on 0 off - включение/выключение источника тока;
                           // Attack Time Resistor 0...3 === 12k5, 25k, 50k, 100k - резистор делителя, формирующего сигнал управления системой ALC;
                           // Threshold 0...3 === 700mVrms, 485mVrms, 320mVrms, 170mVrms, - пороговые уровни ограничения НЧ сигнала на выходе;
                           // Attack Mode - режим резистора делителя Attack Time Resistor - 0...1 === MODE 1: Fixed Resistor ... MODE 2: Adaptive - фиксированное значение/адаптивное значение;
}

void to_Timer(){newPosition = myEnc.read()/4;}

22 (2020-11-30 20:34:27 отредактировано dimb0t)

Re: TDA7468 - обновленная библиотека (полный функционал)

Есть.

Что Вы имели в виду:

liman324 пишет:

а далее укажите какие меню в какой последовательности сделать. Один параметр на одно меню

Вот, например, Table 7. INPUT SELECTION & MIC в даташите: сейчас реализован только параметр INPUT SELECT. А остальные (MUTE (IN5) и MIC) не будут использованы? Например, в меню SURROUND четыре подменю и как раз их вариации настраивают эффекты на выходе. Если сделать просто включить SURROUND, а остальные параметры этого меню установить по умолчанию, то смысл подстройки под конкретную акустику - теряется.

Я уже согласен на дополнительные кнопки.

23

Re: TDA7468 - обновленная библиотека (полный функционал)

Надо просто решить какие параметры нужны в меню, а какие сделать по умолчанию.

Например меню входа, помимо in1...in4 можно добавить in5 c параметрами on/off, если on то появится еще одно подменю входа - усиление, если еще раз нажать на кнопку энкодера, то снова будет in1.

Или сделать отдельное меню для In5 в основном меню.

Или оставить этот параметр на потом, делать другие.

Параметров много, каждое нажатие кнопки энкодера позволит менять только один параметр.

Например меню SURROUND

Экран

SURROUND MODE
ON

SURROUND GAIN
1 dB

SURROUND MIXING
inverting : 100%

SURROUND BUFFER
GAIN 6 dB

http://forum.rcl-radio.ru/uploads/images/2020/11/8534770a279aaef33b362deee51f98f4.png

24

Re: TDA7468 - обновленная библиотека (полный функционал)

Можно перейти на lcd2004 - немного сложнее, но будет все информативно

Вот пример - http://rcl-radio.ru/?p=80718

25

Re: TDA7468 - обновленная библиотека (полный функционал)

С дополнительными кнопками будет проще?