M62446 6-и канальный регулятор громкости и тембра (Arduino)

Аудиопроцессор M62446 выпускается в двух вариантах M62446FP и M62446AFP, последний содержит более расширенный диапазон регулировки громкости и тембра. В ИМС M62446 нет коммутатора входов, микросхема имеет 8 входов (Cin SWin SLin SRin BYPASS1 BYPASS2 Lin Rin), два из которых (BYPASS1 BYPASS2) это входы для правого и левого канала (Lin Rin) но в обход регулятора громкости. Регулировка тембра осуществляется только по двум входам / выходам (Lin Rin / Lout Rout). Соответственно микросхема имеет 6 выходов (Cout SWout SLout SRout Lout Rout), регулировка громкости на каждом канале независимая.

Характеристики M62446:

  • Регулировка громкости для M62446AFP от 0 до –95 dB (1 dB/шаг) и от 0 до –79 dB (1 dB/шаг) для M62446FP
  • Регулировка тембра для M62446AFP от -14 до +14 dB (2 dB/шаг) и от -10 до +10 dB (1 dB/шаг) для M62446FP
  • 4-е цифровых выхода, для управления различными периферийными уст-вами в максимальным током нагрузки 0,2 мА
  • Напряжение питания +4,5 … 5,5 В (digital) и  ±4.5 … ±7.5 В (analog)
  • КНИ не более 0.002 %
  • Управление цифровое 3-wire

M62446 содержит всего 4-е 16-и битных регистра управления:

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

Схема

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

#define LATCH   2
#define DATA    3
#define CLOCK   4

void setup() {
  Serial.begin(9600);
  pinMode(LATCH, OUTPUT);digitalWrite(LATCH, LOW);
  pinMode(DATA, OUTPUT);digitalWrite(DATA, LOW);
  pinMode(CLOCK, OUTPUT);digitalWrite(CLOCK, LOW);
  delay(100);
}

void loop() {
  byte_1(0,0b0000,0,0);// treb -7...7, port 0b0000, bass -7...7, bypass = 0
  byte_2(0,0);// 0...95 = 0...-95 dB mute = 112
  byte_3(0,0);// 0...95 = 0...-95 dB mute = 112
  byte_4(0,0);// 0...95 = 0...-95 dB mute = 112
  delay(1000);

}

void byte_1(int treb, byte port, int bass, bool by_pass){
  // treb int -7...+7 === -14...+14 dB
  // bass int -7...+7 === -14...+14 dB
  // byte port 0b0000....0b1111
  // by_pass  === 0 TONE | 1 BYPASS 
  switch(treb){
    case -7: treb = 0b1111;break;
    case -6: treb = 0b1101;break;
    case -5: treb = 0b1110;break;
    case -4: treb = 0b1100;break;
    case -3: treb = 0b1011;break;
    case -2: treb = 0b1010;break;
    case -1: treb = 0b1001;break;
    case  0: treb = 0b0000;break;
    case  1: treb = 0b0001;break;
    case  2: treb = 0b0010;break;
    case  3: treb = 0b0011;break;
    case  4: treb = 0b0100;break;
    case  5: treb = 0b0110;break;
    case  6: treb = 0b0101;break;
    case  7: treb = 0b0111;break;
    }
  switch(bass){
    case -7: bass = 0b1111;break;
    case -6: bass = 0b1101;break;
    case -5: bass = 0b1110;break;
    case -4: bass = 0b1100;break;
    case -3: bass = 0b1011;break;
    case -2: bass = 0b1010;break;
    case -1: bass = 0b1001;break;
    case  0: bass = 0b0000;break;
    case  1: bass = 0b0001;break;
    case  2: bass = 0b0010;break;
    case  3: bass = 0b0011;break;
    case  4: bass = 0b0100;break;
    case  5: bass = 0b0110;break;
    case  6: bass = 0b0101;break;
    case  7: bass = 0b0111;break;
    }  
  unsigned int data_byte = (treb<<12)|(port<<8)|(bass<<4)|(by_pass<<2)|0b00;
  writeByte(data_byte);  
  }

void byte_2(int vol_l, int vol_r){
  // int vol 0...95 === 0...-95 dB mute=112
  if(vol_l>79){vol_l=vol_l+16;}
  if(vol_r>79){vol_r=vol_r+16;}
  unsigned int data_byte = (vol_l<<9)|(vol_r<<2)|0b01;
  writeByte(data_byte); 
  }  
void byte_3(int vol_c, int vol_sw){
  // int vol 0...95 === 0...-95 dB mute=112
  if(vol_c>79){vol_c=vol_c+16;}
  if(vol_sw>79){vol_sw=vol_sw+16;}
  unsigned int data_byte = (vol_c<<9)|(vol_sw<<2)|0b10;
  writeByte(data_byte); 
  }  
void byte_4(int vol_sl, int vol_sr){
  // int vol 0...95 === 0...-95 dB mute=112
  if(vol_sl>79){vol_sl=vol_sl+16;}
  if(vol_sr>79){vol_sr=vol_sr+16;}
  unsigned int data_byte = (vol_sl<<9)|(vol_sr<<2)|0b11;
  writeByte(data_byte); 
  }    

void writeByte(uint16_t data){
    digitalWrite(LATCH, HIGH); delayMicroseconds(1);
    digitalWrite(LATCH, LOW); delayMicroseconds(3);
    for (int i = 15; i >= 0; i--) {
        digitalWrite(DATA, (data >> i) & 1); delayMicroseconds(3);
        digitalWrite(CLOCK, HIGH); delayMicroseconds(3);
        digitalWrite(CLOCK, LOW); delayMicroseconds(3);
    }
    digitalWrite(LATCH, HIGH); delayMicroseconds(1);
    digitalWrite(LATCH, LOW); delayMicroseconds(3);
}

Как видно скетч содержит 4-е функции управления (одна на каждый регистр), первая функция управляет тембром, а остальные громкостью всех каналов (по 2 канала на функцию):

  byte_1(5,0b0000,5,0);// treb -7...7, port 0b0000, bass -7...7, bypass = 0
  byte_2(0,0);// 0...95 = 0...-95 dB mute = 112
  byte_3(0,0);// 0...95 = 0...-95 dB mute = 112
  byte_4(0,0);// 0...95 = 0...-95 dB mute = 112

Для M62446FP которая имеет более узкий диапазон регулировки громкости и тембра необходимо использовать следующий пример:

  byte_1(5,0b0000,5,0);// treb -5...5, port 0b0000, bass -5...5, bypass = 0
  byte_2(0,0);// 0...79 = 0...-79 dB mute = 80
  byte_3(0,0);// 0...79 = 0...-79 dB mute = 80
  byte_4(0,0);// 0...79 = 0...-79 dB mute = 80

Далее рассмотрим пример создания регулятора громкости и тембра на базе ИМС M62446.

Регулировка всех параметров регулятора громкости и тембра будет осуществляться при помощи энкодера (модуль KY-040) и трех кнопок, дополнительно управление параметрам будет продублировано ИК пультом (ИК-датчик VS1838B). Вся информация будет выводится на LCD2004_I2C.

Дополнительно регулятор громкости и тембра имеет функцию STANDBY и MUTE. Так же в примере используются часы реального времени DS3231 (модуль).

В режиме STANDBY (POWER_OFF) на дисплей будет выводится текущее время, подсветка дисплея будет работать с пониженной яркостью.

В проекте используется два меню, в первом меню выводятся основные параметры аудиопроцессора — громкость, тембр НЧ и ВЧ и часы. Во втором меню осуществляется регулировка аттенюаторов выходов.

Для перехода из одного меню в другое используйте кнопку SET. Регулировка параметров осуществляется путем поворота ручки энкодера, переход от одного параметра к другому осуществляется при помощи кнопки энкодера.

Подсветка — убрать перемычку с модуля I2C PCF8574 и подключить вывод модуля к цифровому выходу Arduino D6. Перед подключением замерить ток подсветки который не должен превышать 20 мА (у моего модуля ток не более 15 мА, замер производить между контактами перемычки).

 

Максимальный выходной ток одного выхода Arduino Nano не должен превышать 40 мА.

Установить текущее время можно двумя способами:

  • Установки времени через скетч:

Раскомментируйте строку:

clock.setDateTime(__DATE__, __TIME__); // Устанавливаем время на часах, основываясь на времени компиляции скетча

загрузите скетч, далее закомментируйте строку:

// clock.setDateTime(__DATE__, __TIME__); // Устанавливаем время на часах, основываясь на времени компиляции скетча

повторно загрузите скетч.

  • Установка времени кнопками:
  • Перейдите в режим STANDBY, нажать и удерживать кнопку энкодера, нажимать кнопки:
    • SET — коррекция часов
    • MUTE — коррекция минут

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

// IR
#define IR_OK    0x33B8A05F // Кнопка OK
#define IR_UP    0x33B810EF // Кнопка >
#define IR_DW    0x33B8E01F // Кнопка <
#define IR_SET   0x33B844BB // Кнопка SET
#define IR_MUTE  0x33B8946B // Кнопка MUTE
#define IR_POWER 0x33B800FF // Кнопка STANDBY (POWER)

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

Схема блока контроллера

Скетч:

// M62446
#define LATCH   2
#define DATA    3
#define CLOCK   4
// ENCODER
#define ENC_SW  10
#define ENC_DT  9
#define ENC_CLK 8
// ВЫХОД УПРАВЛЕНИЯ ПОДСВЕТКОЙ D6
#define BRIG_H  200      // Яркость 0...255 POWER ON
#define BRIG_L  50       // Яркость 0...255 POWER OFF
// BUTTON
#define SET     A0
#define MUTE    A1
#define STANDBY A2
#define ST_OUT  13
// IR
#define IR_OK    0x33B8A05F // Кнопка OK
#define IR_UP    0x33B810EF // Кнопка >
#define IR_DW    0x33B8E01F // Кнопка <
#define IR_SET   0x33B844BB // Кнопка SET
#define IR_MUTE  0x33B8946B // Кнопка MUTE
#define IR_POWER 0x33B800FF // Кнопка STANDBY (POWER)

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>  // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
#include <Encoder.h>            // http://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip    
#include <EEPROM.h>
#include <MsTimer2.h>           // http://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip       
#include <boarddefs.h>          // входит в состав библиотеки IRremote
#include <IRremote.h>           // http://rcl-radio.ru/wp-content/uploads/2019/06/IRremote.zip
#include <DS3231.h>             // http://rcl-radio.ru/wp-content/uploads/2022/10/DS3231.zip

 DS3231 clock;RTCDateTime DateTime;
 LiquidCrystal_I2C lcd(0x27,20,4);  // Устанавливаем дисплей
 IRrecv irrecv(12); // указываем вывод модуля IR приемника
 Encoder myEnc(ENC_DT, ENC_CLK);
 decode_results ir; 

 unsigned long time0,oldPosition  = -999,newPosition;
 int menu0,menu,menu1,temp0,z1,z0,z,vol,treb,bass,par,treb_d,bass_d,vol_d,z_old;
 byte gr1,gr2,www,power,w2[4],q;
 int hour,minut,secon;
 int att_l,att_r,att_c,att_sw,att_sl,att_sr;
 bool w,mute;
 byte mesto2[8]={0,10,0,10,0,10};
 byte mesto3[8]={0,0,1,1,2,2};
 bool off=1;

void setup() {
  irrecv.enableIRIn();lcd.init();lcd.backlight();clock.begin();Serial.begin(9600);
  pinMode(ENC_SW,INPUT); 
  pinMode(LATCH, OUTPUT);digitalWrite(LATCH, LOW);
  pinMode(DATA, OUTPUT);digitalWrite(DATA, LOW);
  pinMode(CLOCK, OUTPUT);digitalWrite(CLOCK, LOW);
  pinMode(SET,INPUT_PULLUP);   // КНОПКА SET
  pinMode(MUTE,INPUT_PULLUP);   // КНОПКА MUTE
  pinMode(STANDBY,INPUT_PULLUP);   // КНОПКА STANDBY
  pinMode(ST_OUT,OUTPUT); 
  //  clock.setDateTime(__DATE__, __TIME__); // Устанавливаем время на часах, основываясь на времени компиляции скетча
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении  
  pinMode(6,OUTPUT);  // ВЫХОД УПРАВЛЕНИЯ ПОДСВЕТКОЙ
  analogWrite(6, BRIG_H);// больше 200 не делать
  lcd.setCursor(3,1);lcd.print("Sound Processor");lcd.setCursor(7,2);lcd.print("M62446"); delay(2000);lcd.clear();
  MsTimer2::set(3, to_Timer);MsTimer2::start();
  w2[0]=1;w2[1]=1;w2[2]=1;w2[3]=1;
  vol = EEPROM.read(0);bass = EEPROM.read(1)-7;treb = EEPROM.read(2)-7;
  att_l = EEPROM.read(3);att_r = EEPROM.read(4);att_c = EEPROM.read(5);att_sw = EEPROM.read(6);att_sl = EEPROM.read(7);att_sr = EEPROM.read(8);
  audio();
}

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

void loop() {
  DateTime = clock.getDateTime();hour = DateTime.hour;minut = DateTime.minute;secon = DateTime.second;

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

  if(power==0){
  if((ir.value==IR_OK||digitalRead(ENC_SW)==LOW)&&menu0==0){menu++;delay(200);time0=millis();w=1;w2[0]=1;w2[1]=1;w2[2]=1;if(menu>2){menu=0;}}// меню 0
  
  if((ir.value==IR_OK||digitalRead(ENC_SW)==LOW)&&menu0==1){menu1++;gr1=0;gr2=0;cl1();time0=millis();w=1;w2[0]=1;w2[1]=1;w2[2]=1;if(menu1>5){menu1=0;}}//меню 1

  if(ir.value==IR_SET||digitalRead(SET)==LOW){menu0++;if(menu0>1){menu0=0;}cl();w2[0]=1;w2[1]=1;w2[2]=1;time0=millis();w=1;lcd.setCursor(5,1);
     lcd.print("SETTING_");lcd.print(menu0);delay(500);lcd.clear();} 

  if((ir.value==IR_MUTE||digitalRead(MUTE)==LOW)&&mute==0){mute=1;menu0=100;cl();w=1;w2[0]=1;w2[1]=1;w2[2]=1;lcd.setCursor(8,1);lcd.print("MUTE");audio_mute();delay(300);}// mute on
  if((ir.value==IR_MUTE||digitalRead(MUTE)==LOW)&&mute==1){mute=0;cl();time0=millis();w=1;w2[0]=1;w2[1]=1;w2[2]=1;menu0=0;menu=0;myEnc.write(0);audio();}// mute off   
  } // power == 0 

 // power 
  if((ir.value==IR_POWER||digitalRead(STANDBY)==LOW||off==1)&&power==0){power=1;off=0;cl();audio_mute();lcd.setCursor(5,1);lcd.print("POWER  OFF");menu0=100;delay(3000);analogWrite(6,BRIG_L);}// power off
  if((ir.value==IR_POWER||digitalRead(STANDBY)==LOW)&&power==1){power=0;analogWrite(6, BRIG_H);cl();lcd.setCursor(5,1);lcd.print("POWER   ON ");w=1;
  w=1;w2[0]=1;w2[1]=1;w2[2]=1;menu0=0;myEnc.write(0);audio();delay(3000);cl();}// power on   

  
  if(power==0){digitalWrite(ST_OUT,HIGH);
   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}; 
   byte a4[8] = {0b10000,0b11000,0b11100,0b11110,0b11100,0b11000,0b10000,0b00000}; //>
   byte a5[8] = {0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000};
   lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);lcd.createChar(3,a4);lcd.createChar(4,a5);
  }
  if(power==1){digitalWrite(ST_OUT,LOW);
      byte v1[8] = {7,7,7,7,7,7,7,7};
      byte v2[8] = {7,7,0, 0, 0, 0, 0, 0};      
      byte v3[8] = { 0, 0, 0, 0, 0,0,31,31};
      byte v4[8] = {31,31, 0, 0, 0, 0,31,31};
      byte v5[8] = { 28, 28, 0, 0, 0, 0, 28, 28};
      byte v6[8] = {28,28,28,28,28,28,28,28};
      byte v7[8] = { 0, 0, 0, 0, 0, 0,7,7};
      byte v8[8] = { 31, 31,0,0,0,0,0, 0};
   byte a[6];
   byte i0,d1,d2,d3,d4,d5,d6,e1,e2,e3;
  lcd.createChar(1, v1);lcd.createChar(2, v2);lcd.createChar(3, v3);lcd.createChar(4, v4);lcd.createChar(5, v5);lcd.createChar(6, v6);lcd.createChar(7, v7);lcd.createChar(8, v8);
 
     a[0]=DateTime.hour/10;
     a[1]=DateTime.hour%10;
     a[2]=DateTime.minute/10;
     a[3]=DateTime.minute%10;
     a[4]=DateTime.second/10;
     a[5]=DateTime.second%10;
 
 for(int i=0;i<6;i++){
      switch(i){
        case 0: e1=0,e2=1,e3=2;break;
        case 1: e1=3,e2=4,e3=5;break;
        case 2: e1=7,e2=8,e3=9;break;
        case 3: e1=10,e2=11,e3=12;break;
        case 4: e1=14,e2=15,e3=16;break;
        case 5: e1=17,e2=18,e3=19;break;
        }
      switch(a[i]){
        case 0: d1=1,d2=8,d3=6,d4=1,d5=3,d6=6;break;
        case 1: d1=32,d2=2,d3=6,d4=32,d5=32,d6=6;break;
        case 2: d1=2,d2=8,d3=6,d4=1,d5=4,d6=5;break;
        case 3: d1=2,d2=4,d3=6,d4=7,d5=3,d6=6;break;
        case 4: d1=1,d2=3,d3=6,d4=32,d5=32,d6=6;break;
        case 5: d1=1,d2=4,d3=5,d4=7,d5=3,d6=6;break;
        case 6: d1=1,d2=4,d3=5,d4=1,d5=3,d6=6;break;
        case 7: d1=1,d2=8,d3=6,d4=32,d5=32,d6=6;break;
        case 8: d1=1,d2=4,d3=6,d4=1,d5=3,d6=6;break;
        case 9: d1=1,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    }
 
      lcd.setCursor(e1,0);lcd.write((uint8_t)d1);lcd.setCursor(e2,0);lcd.write((uint8_t)d2);lcd.setCursor(e3,0);lcd.write((uint8_t)d3);
      lcd.setCursor(e1,1);lcd.write((uint8_t)d4);lcd.setCursor(e2,1);lcd.write((uint8_t)d5);lcd.setCursor(e3,1);lcd.write((uint8_t)d6);
  }
  lcd.setCursor(6,0);lcd.print(".");lcd.setCursor(13,0);lcd.print(".");lcd.setCursor(6,1);lcd.print(".");lcd.setCursor(13,1);lcd.print(".");
  lcd.setCursor(5,3);lcd.print("POWER  OFF");
  if(digitalRead(ENC_SW)==LOW&&digitalRead(SET)==LOW){hour++;if(hour>23){hour=0;} clock.setDateTime(2024, 9, 15, hour, minut, 0);delay(100);}    // SET
  if(digitalRead(ENC_SW)==LOW&&digitalRead(MUTE)==LOW){minut++;if(minut>59){minut=0;} clock.setDateTime(2024, 9, 15, hour, minut, 0);delay(100); }// MUTE
  } 
  
  /////////////////////////////// MENU0 = VOLUME TERBLE BASS MIDDLE ///////////////////////////////////////////////////////////////////////
  if(menu0==0){ 
    switch(menu){
      case 0: temp0 = vol;q=0;break;
      case 1: temp0 = bass;q=1;break;
      case 2: temp0 = treb;q=2;break;
      }
 
     if(ir.value==IR_UP){temp0++;gr1=1;gr2=0;cl1();time0=millis();w=1;w2[q]=1;www=1;}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){temp0++;gr2=0;cl1();time0=millis();w=1;w2[q]=1;www=1;}// кнопка >>>>>>
     if(ir.value==IR_DW){temp0--;gr1=0;gr2=1;cl1();time0=millis();w=1;w2[q]=1;www=1;}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){temp0--;gr1=0;cl1();time0=millis();w=1;w2[q]=1;www=1;}// кнопка <<<<<<   
 
   if (newPosition != oldPosition){oldPosition = newPosition;
     if(menu==0){temp0=temp0-newPosition;}else{temp0=temp0+newPosition;}myEnc.write(0);newPosition=0;time0=millis();w=1;w2[q]=1;www=1;} 
 
     switch(menu){
      case 0: vol = temp0;vol_func();break;
      case 1: bass = temp0;bass_func();break;
      case 2: treb = temp0;treb_func();break;
      }
 
   au();
   for(int i=0;i<3;i++){if(menu==i){lcd.setCursor(0,i);lcd.write((uint8_t)3);}else{lcd.setCursor(0,i);lcd.print(" ");}}
   lcd.setCursor(1,0);lcd.print("VOLUME ");if(vol>=0){lcd.print(" ");}lcd.print(50-vol);lcd.print(" ");vol_d=map(vol,50,0,1,24);
   lcd.setCursor(1,1);lcd.print("BASS   ");if(bass>=0){lcd.print(" ");}lcd.print(bass);lcd.print(" ");bass_d=map(bass,-7,7,1,24);
   lcd.setCursor(1,2);lcd.print("TREBLE ");if(treb>=0){lcd.print(" ");}lcd.print(treb);lcd.print(" ");treb_d=map(treb,-7,7,1,24);
   
   lcd.setCursor(0,3);lcd.print("------");lcd.print(DateTime.hour/10);lcd.print(DateTime.hour%10);lcd.print(":");lcd.print(DateTime.minute/10);
   lcd.print(DateTime.minute%10);lcd.print(":");lcd.print(DateTime.second/10);lcd.print(DateTime.second%10);lcd.print("------");
 
 
   for(int n=0;n<3;n++){if(w2[n]==1){
   switch(n){
    case 0: par = vol_d;break;
    case 1: par = bass_d;break;
    case 2: par = treb_d;break; 
    } 
 
   for(z=0,z0=0,z1=0;z<=par;z++,z1++){if(z1>2){z1=0;z0++;}
   if(z1==1){lcd.setCursor(z0+12,n);lcd.write((uint8_t)0);lcd.setCursor(z0+1+12,n);Serial.println(z0);z_old=7-par/3;while(z_old>0){z_old=z_old-1;lcd.write((uint8_t)4);}}}
   if(z1==3){lcd.setCursor(z0+12,n);lcd.write((uint8_t)1);}
   if(z1==2){lcd.setCursor(z0+12,n);lcd.write((uint8_t)2);}w2[n]=0;}
   }}// menu0 = 0
///////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////
 
 if(menu0==1){
     switch(menu1){
      case 0: temp0 = att_l;break;
      case 1: temp0 = att_r;break;
      case 2: temp0 = att_c;break;
      case 3: temp0 = att_sw;break;
      case 4: temp0 = att_sl;break;
      case 5: temp0 = att_sr;break;
      }
 
     if(ir.value==IR_UP){temp0++;gr1=1;gr2=0;cl1();time0=millis();w=1;www=1;}// кнопка > 
     if(ir.value==0xFFFFFFFF and gr1==1){temp0++;gr2=0;cl1();time0=millis();w=1;www=1;}// кнопка >>>>>>
     if(ir.value==IR_DW){temp0--;gr1=0;gr2=1;cl1();time0=millis();;w=1;www=1;}// кнопка <
     if(ir.value==0xFFFFFFFF and gr2==1){temp0--;gr1=0;cl1();time0=millis();w=1;www=1;}// кнопка <<<<<<     
 
   if (newPosition != oldPosition){oldPosition = newPosition;
     temp0=temp0+newPosition;myEnc.write(0);newPosition=0;time0=millis();w=1;www=1;} 
 
     switch(menu1){
      case 0: att_l = temp0;att_l_func();break;
      case 1: att_r = temp0;att_r_func();break;
      case 2: att_c = temp0;att_c_func();break;
      case 3: att_sw = temp0;att_sw_func();break;      
      case 4: att_sl  = temp0;att_sl_func();break;
      case 5: att_sr  = temp0;att_sr_func();break;
      }
 
  au();
  for(int i=0;i<6;i++){if(menu1==i){lcd.setCursor(mesto2[i],mesto3[i]);lcd.write((uint8_t)3);}else{lcd.setCursor(mesto2[i],mesto3[i]);lcd.print(" ");}}
 
  lcd.setCursor(1,0);lcd.print("AT_L  ");lcd.print(att_l);lcd.print(" ");lcd.setCursor(11,0);lcd.print("AT_R  ");lcd.print(att_r);lcd.print(" ");
  lcd.setCursor(1,1);lcd.print("AT_C  ");lcd.print(att_c);lcd.print(" ");lcd.setCursor(11,1);lcd.print("AT_SW ");lcd.print(att_sw);lcd.print(" ");
  lcd.setCursor(1,2);lcd.print("AT_SL ");lcd.print(att_sl);lcd.print(" ");lcd.setCursor(11,2);lcd.print("AT_SR ");lcd.print(att_sr);lcd.print(" ");
 
 } // menu0 = 1

 if(millis()-time0>10000&&w==1&&mute==0&&power==0){
  if(menu0==1){cl();}w=0;if(menu0!=0){cl();}menu0=0;menu=0;w2[0]=1;w2[1]=1;w2[2]=1;
   EEPROM.update(0,vol);EEPROM.update(1,bass+7);EEPROM.update(2,treb+7);
   EEPROM.update(3,att_l);EEPROM.update(4,att_r);EEPROM.update(5,att_c);
   EEPROM.update(6,att_sw);EEPROM.update(7,att_sl);EEPROM.update(8,att_sr);
   }

}

void au(){if(www==1){audio();www=0;}}
void vol_func(){if(vol>50){vol=50;}if(vol<0){vol=0;}}
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 cl(){ir.value=0;delay(300);lcd.clear();}
void cl1(){ir.value=0;delay(200);}  

void att_l_func(){if(att_l>19){att_l=19;}if(att_l<0){att_l=0;}}
void att_r_func(){if(att_r>19){att_r=19;}if(att_r<0){att_r=0;}}
void att_c_func(){if(att_c>19){att_c=19;}if(att_c<0){att_c=0;}}
void att_sw_func(){if(att_sw>19){att_sw=19;}if(att_sw<0){att_sw=0;}}
void att_sr_func(){if(att_sr>19){att_sr=19;}if(att_sr<0){att_sr=0;}}
void att_sl_func(){if(att_sl>19){att_sl=19;}if(att_sl<0){att_sl=0;}}

void audio(){
  byte_1(treb,0b0000,bass,0);// treb -7...7, port 0b0000, bass -7...7, bypass = 0
  byte_2(vol+att_l,vol+att_r);// 0...95 = 0...-95 dB mute = 111
  byte_3(vol+att_c,vol+att_sw);// 0...95 = 0...-95 dB mute = 111
  byte_4(vol+att_sl,vol+att_sr);// 0...95 = 0...-95 dB mute = 111
  }

void audio_mute(){
  byte_2(111,111);
  byte_3(111,111);
  byte_4(111,111);
  }  

void byte_1(int treb, byte port, int bass, bool by_pass){
  // treb int -7...+7 === -14...+14 dB
  // bass int -7...+7 === -14...+14 dB
  // byte port 0b0000....0b1111
  // by_pass  === 0 TONE | 1 BYPASS 
  switch(treb){
    case -7: treb = 0b1111;break;
    case -6: treb = 0b1101;break;
    case -5: treb = 0b1110;break;
    case -4: treb = 0b1100;break;
    case -3: treb = 0b1011;break;
    case -2: treb = 0b1010;break;
    case -1: treb = 0b1001;break;
    case  0: treb = 0b0000;break;
    case  1: treb = 0b0001;break;
    case  2: treb = 0b0010;break;
    case  3: treb = 0b0011;break;
    case  4: treb = 0b0100;break;
    case  5: treb = 0b0110;break;
    case  6: treb = 0b0101;break;
    case  7: treb = 0b0111;break;
    }
  switch(bass){
    case -7: bass = 0b1111;break;
    case -6: bass = 0b1101;break;
    case -5: bass = 0b1110;break;
    case -4: bass = 0b1100;break;
    case -3: bass = 0b1011;break;
    case -2: bass = 0b1010;break;
    case -1: bass = 0b1001;break;
    case  0: bass = 0b0000;break;
    case  1: bass = 0b0001;break;
    case  2: bass = 0b0010;break;
    case  3: bass = 0b0011;break;
    case  4: bass = 0b0100;break;
    case  5: bass = 0b0110;break;
    case  6: bass = 0b0101;break;
    case  7: bass = 0b0111;break;
    }  
  unsigned int data_byte = (treb<<12)|(port<<8)|(bass<<4)|(by_pass<<2)|0b00;
  writeByte(data_byte);  
  }

void byte_2(int vol_l, int vol_r){
  // int vol 0...95 === 0...-95 dB mute=111
  if(vol_l>79){vol_l=vol_l+16;}
  if(vol_r>79){vol_r=vol_r+16;}
  unsigned int data_byte = (vol_l<<9)|(vol_r<<2)|0b01;
  writeByte(data_byte); 
  }  
void byte_3(int vol_c, int vol_sw){
  // int vol 0...95 === 0...-95 dB mute=112
  if(vol_c>79){vol_c=vol_c+16;}
  if(vol_sw>79){vol_sw=vol_sw+16;}
  unsigned int data_byte = (vol_c<<9)|(vol_sw<<2)|0b10;
  writeByte(data_byte); 
  }  
void byte_4(int vol_sl, int vol_sr){
  // int vol 0...95 === 0...-95 dB mute=112
  if(vol_sl>79){vol_sl=vol_sl+16;}
  if(vol_sr>79){vol_sr=vol_sr+16;}
  unsigned int data_byte = (vol_sl<<9)|(vol_sr<<2)|0b11;
  writeByte(data_byte); 
  }    

void writeByte(uint16_t data){
    digitalWrite(LATCH, HIGH); delayMicroseconds(1);
    digitalWrite(LATCH, LOW); delayMicroseconds(3);
    for (int i = 15; i >= 0; i--) {
        digitalWrite(DATA, (data >> i) & 1); delayMicroseconds(3);
        digitalWrite(CLOCK, HIGH); delayMicroseconds(3);
        digitalWrite(CLOCK, LOW); delayMicroseconds(3);
    }
    digitalWrite(LATCH, HIGH); delayMicroseconds(1);
    digitalWrite(LATCH, LOW); delayMicroseconds(3);
}

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

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

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