Аудиопроцессор 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