Микроконтроллер Atmega88 может стать отличной заменой сильно подорожавших плат Arduino Nano. Большое кол-во проектов создаваемых на платах Arduino Nano часто используют небольшое объем памяти и применять Arduino Nano в данных проектах нецелесообразно. Atmega88 имеет 8 кБ программируемой Flash памяти, 1кБ SRAM памяти и 512 байта EEPROM.
Микроконтроллер Atmega88 поддерживается средой программирования Arduino IDE, так же большинство библиотек совместимы с этими контроллерами.
Ранее в http://rcl-radio.ru/?p=120507 рассматривался пример создания регулятора громкости и тембра на LC75342 с использованием платы Arduino Nano, на этой странице будет аналогичный проект, но с использованием микроконтроллера Atmega88.
ИМС LC75342 представляет собой аудиопроцессор специально разработанный для регулирования параметров аудиосигнала с минимальными искажениями. Аудиопроцессор включает в себя регулятор громкости, тембра, коммутатор входов и предусилители входов.
Более подробно об аудиопроцессоре можно узнать из статьи — LC75342 (Arduino)
Основные параметры LC75342
- Регулировка громкости от -79 до 0 дБ (шаг 1 дБ)
- Независимая регулировка громкости (баланс)
- Входной предварительный усилитель входа от 0 до +30 дБ (шаг 2 дБ)
- 4-х канальный коммутатор входов
- Регулировка тембра BASS от -20 до +20 дБ (шаг 2 дБ)
- Регулировка тембра TREBLE от -10 до +10 дБ (шаг 2 дБ)
- Напряжение питания от 5 до 10 В
- Управление цифровое 3-Wire (CL, DI, CE) (макс. тактовая частота до 500 кГц)
- Входное сопротивление 50 кОм
- Коэффициент нелинейных искажений 0,01% (макс.)
Регулятор громкости содержит два основных блока, первый блок микроконтроллерный (Arduino Nano) с органами управления и индикации, второй блок плата аудиопроцессора.
Регулировка громкости возможна в пределах от -79 до -4 дБ, недостающие 4 дБ отданы регулятору баланса.
Основное управление параметрами аудиопроцессора будет осуществляться при помощи энкодера (KY-040) и 2-х кнопок. Вся информация будет выводится на дисплей LCD1602 + I2C (I2C модуль на базе микросхем PCF8574 позволяют подключить символьный дисплей 1602 к плате Arduino всего по двум проводам SDA и SCL (А4 и А5), что дает возможность не использовать цифровые выходы Arduino при подключении дисплея.)
Регулятор тембра имеет одно меню, которое содержит регуляторы громкости, тембра (TRABLE, BASS) и баланса. Дополнительно при нажатии кнопки INPUT помимо переключения входа будет доступно меню предусилителя входа. (независимое для каждого входа).
Схема регулятора громкости и тембра
Как добавить микроконтроллер Atmega88 в среду программирования Arduino IDE и прошивать микроконтроллер можно узнать из статьи http://rcl-radio.ru/?p=113040.
Перед загрузкой в настройках платы укажите частоту кварцевого резонатора (12 МГц), выбрать программатор USBasp, в пункте Variant тип контроллера 88P/88PA, 88/88A (для Atmega88 20PU который я используя для этой статьи) или 88PB, в пункте Bootloader выберите No bootloader или Yes (UART0) если планируете загружать скетчи через UART ( USB — TTL ).
Во вкладке «Инструменты» нажмите «Записать загрузчик«.(делается только один раз)
Для запуска LCD1602 c I2C модулем на PCF8574, Вам понадобятся две библиотеки:
- Wire_low — библиотека для работы с шиной I2C (тестовая версия)
- Lcd1602_i2c_low — библиотека для работы с LCD1602 I2C на PCF8574
// ATMEGA88 12 MHz #define CE PD0 #define DI PD1 #define CL PD2 #define DT PD5 #define CLK PD6 #define SW PD7 #define IN PB1 #define MUTE PB2 #include <avr/io.h> #include <util/delay.h> #include <Wire_low.h> // http://forum.rcl-radio.ru/viewtopic.php?pid=5521#p5521 #include <Lcd1602_i2c_low.h> // http://rcl-radio.ru/wp-content/uploads/2022/03/Lcd1602_i2c_low.zip Lcd1602_i2c_low lcd(0x27);// адрес I2C volatile uint8_t _prevValueAB = 0; volatile uint8_t _currValueAB = 0; volatile int16_t newPosition = 0; int position = -999; int menu,vol_reg,mute_reg,in_reg,vol_old,treb_reg,treb_print,bass_reg,bass_print,ball,chl,chr,i; byte a[6],d1,d2,d3,d4,d5,d6,e1,e2,e3,w,w2,x,www; int gain0,gain1,gain2,gain3,gain4,gain5,gain0_print; unsigned long millis_times,times; int main(){ cli(); TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 46874; TCCR1B |= (1 << WGM12); TCCR1B |= (1 << CS12); TIMSK1 |= (1 << OCIE1A); sei(); wire_set(12000000,100000); // тактовая частота контроллера, частота шины I2C lcd.setInit(); lcd.Clear(); // очистка экрана lcd.led(1); // включение и отключение подсветки экрана lcd.Write(0, 0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111); lcd.Write(1, 0b00111,0b00111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000); lcd.Write(2, 0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111); lcd.Write(3, 0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111); lcd.Write(4, 0b11100,0b11100,0b00000,0b00000,0b00000,0b00000,0b11100,0b11100); lcd.Write(5, 0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100); lcd.Write(6, 0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00111,0b00111); lcd.Write(7, 0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000); DDRD |=(1<<CE)|(1<<DI)|(1<<CL); PORTD &=~(1<<CE)|(1<<DI)|(1<<CL); PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT21)|(1 << PCINT22); PORTB |=(1<<IN)|(1<<MUTE); if(EEPROM_read(100)!=0){for(int i=0;i<101;i++){EEPROM_write(i,0);}}// очистка памяти при первом включении vol_reg = EEPROM_read(0);treb_reg = EEPROM_read(1)-5;bass_reg = EEPROM_read(2)-10;gain1 = EEPROM_read(4); gain2 = EEPROM_read(5);gain3 = EEPROM_read(6);gain4 = EEPROM_read(7);gain5 = EEPROM_read(8); in_reg = EEPROM_read(9);ball = EEPROM_read(10)-4; switch(in_reg){ case 0: gain0 = gain1;break; case 1: gain0 = gain2;break; case 2: gain0 = gain3;break; case 3: gain0 = gain4;break; } audio_L(); audio_R(); while(1){ /// BUTTON /////////////////////////////////// if(mute_reg==0){ if(((PIND >> SW) & 1)==0){menu++;cl();w2=1;w=1;times=millis_times;if(menu>3){menu=0;}} if(((PINB >> IN) & 1)==0){in_reg++;menu=4;cl();w=1;times=millis_times;if(in_reg>3){in_reg=0;}} } if((((PINB >> MUTE) & 1)==0)&&mute_reg==0){mute_reg=1;menu=100;cl();w=1;times=millis_times;vol_old=vol_reg;vol_reg=79;audio_R();audio_L();lcd.Curs(0,6);lcd.PrintString("MUTE");} if((((PINB >> MUTE) & 1)==0)&&mute_reg==1){mute_reg=0;menu=0;cl();w=1;times=millis_times;vol_reg=vol_old;audio_R();audio_L();} ////////////// VOLUME /////////////////////////////////////////////////////////////////// if(menu==0){ if(newPosition != position){position = newPosition;vol_reg = vol_reg+newPosition;newPosition=0;w=1;times=millis_times;vol_func();audio_R();audio_L();} a[0]= (79-vol_reg)/10;a[1]=(79-vol_reg)%10; for(x=0;x<2;x++){switch(x){case 0: e1=10,e2=11,e3=12;break;case 1: e1=13,e2=14,e3=15;break;}digit();} if(mute_reg==0){lcd.Curs(0,0);lcd.PrintString("VOLUME");}else{lcd.Curs(0,0);lcd.PrintString("MUTE");} lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1); } ////////////// TREBLE /////////////////////////////////////////////////////////////////// if(menu==1){ if(newPosition != position){position = newPosition;treb_reg = treb_reg-newPosition;newPosition=0;w=1;times=millis_times;treb_func();audio_R();audio_L();} if(treb_reg<0){treb_print = (-treb_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{treb_print = treb_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");} a[0]= treb_print/10;a[1]=treb_print%10; for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();} lcd.Curs(0,0);lcd.PrintString("TREBLE");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB"); } ////////////// BASS /////////////////////////////////////////////////////////////////// if(menu==2){ if(newPosition != position){position = newPosition;bass_reg = bass_reg-newPosition;newPosition=0;w=1;times=millis_times;bass_func();audio_R();audio_L();} if(bass_reg<0){bass_print = (-bass_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{bass_print = bass_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");} a[0]= bass_print/10;a[1]=bass_print%10; for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();} lcd.Curs(0,0);lcd.PrintString("BASS");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB"); } //////// BALANCE /////////////////////////////////////////////////////////////// if(menu==3){ if(newPosition != position){position = newPosition;ball = ball-newPosition;newPosition=0;w=1;w2=1;times=millis_times;ball_fun();audio_R();audio_L();} lcd.Curs(0,4);lcd.PrintString(" <> ");lcd.Curs(1,4);lcd.PrintString("CHL CHR"); chl=(4+ball)-4;chr=(4-ball)-4; if(chl<0){lcd.Curs(0,12);chl=(-chl);lcd.PrintChar(2);}else{lcd.Curs(0,12);lcd.PrintString(" ");} if(chr<0){lcd.Curs(0,0);chr=(-chr);lcd.PrintChar(2);}else{lcd.Curs(0,0);lcd.PrintString(" ");} if(w2==1){w2=0;a[0]=chl;a[1]=chr; for(i=0;i<2;i++){ switch(i){ case 0: e1=1,e2=2,e3=3;break; case 1: e1=13,e2=14,e3=15;break; } switch(a[i]){ case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break; case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break; case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break; case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break; case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break; } char_lcd(); }}} ////////////// INPUT GAIN /////////////////////////////////////////////////////////////////// if(menu==4){ switch(in_reg){ case 0: gain0 = gain1;break; case 1: gain0 = gain2;break; case 2: gain0 = gain3;break; case 3: gain0 = gain4;break;} if(newPosition != position){position = newPosition;gain0 = gain0-newPosition;newPosition=0;w=1;times=millis_times;www=1;gain_func();} switch(in_reg){ case 0: gain1 = gain0;break; case 1: gain2 = gain0;break; case 2: gain3 = gain0;break; case 3: gain4 = gain0;break;} gain0_print = gain0*2; a[0]= gain0_print/10;a[1]=gain0_print%10; for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();} if(www==1){audio_R();audio_L();www=0;} lcd.Curs(0,0);lcd.PrintString("IN GAIN");lcd.Curs(0,14);lcd.PrintString("dB"); lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1);} ////////////////// EEPROM ////////////////////////////////////////////////////////////// if(millis_times-times>10 && w==1 && mute_reg==0){ EEPROM_write(0,vol_reg);EEPROM_write(1,treb_reg+5);EEPROM_write(2,bass_reg+10);EEPROM_write(4,gain1); EEPROM_write(5,gain2);EEPROM_write(6,gain3);EEPROM_write(7,gain4);EEPROM_write(8,gain5); EEPROM_write(9,in_reg);EEPROM_write(10,ball+4); if(menu!=0){lcd.Clear();menu=0;}w=0;} }}// end while ISR(TIMER1_COMPA_vect){millis_times++;} void digit(){switch(a[x]){ case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break; case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break; case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break; case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break; case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break;} char_lcd();} void char_lcd(){ lcd.Curs(0,e1);lcd.PrintChar(d1);lcd.Curs(0,e2);lcd.PrintChar(d2);lcd.Curs(0,e3);lcd.PrintChar(d3); lcd.Curs(1,e1); lcd.PrintChar(d4);lcd.Curs(1,e2);lcd.PrintChar(d5);lcd.Curs(1,e3);lcd.PrintChar(d6); } void vol_func(){if(vol_reg<4){vol_reg=4;}if(vol_reg>79){vol_reg=79;}} void gain_func(){{if(gain0<0){gain0=0;}if(gain0>15){gain0=15;}}} void ball_fun(){if(ball>4){ball=4;}if(ball<-4){ball=-4;}} void bass_func(){if(bass_reg<-10){bass_reg=-10;}if(bass_reg>10){bass_reg=10;}} void treb_func(){if(treb_reg<-5){treb_reg=-5;}if(treb_reg>5){treb_reg=5;}} void cl(){_delay_ms(300);lcd.Clear();} ISR(PCINT2_vect){ bool pinA = ((PIND >> DT) & 1); bool pinB = ((PIND >> CLK) & 1); _currValueAB = (pinA << 1) | pinB; switch(_prevValueAB | _currValueAB){ case 0b0001: newPosition++;break; case 0b0100: newPosition--;break; } _prevValueAB = _currValueAB << 2; } void addr(){ PORTD &=~(1<<CL)|(1<<CE); byte addr = 0b01000001; for(int i = 7; i >= 0; i--){ PORTD &=~(1<<CL); if(((addr>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } PORTD |=(1<<CE); } void set_input(byte in){ for(int i = 0; i <= 3; i++){ PORTD &=~(1<<CL); switch(i){ case 0: if(((in & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 1: if(((in & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 2: if(((in & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 3: if(((in & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; } PORTD |=(1<<CL); } } void set_gain(byte gain){ for(int i = 0; i <= 3; i++){ PORTD &=~(1<<CL); switch(i){ case 0: if(((gain & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 1: if(((gain & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 2: if(((gain & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 3: if(((gain & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; } PORTD |=(1<<CL); } } void set_volume(byte vol){ for(int i = 0; i <= 7; i++){ PORTD &=~(1<<CL); switch(i){ case 0: if(((vol & 0b00000001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 1: if(((vol & 0b00000010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 2: if(((vol & 0b00000100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 3: if(((vol & 0b00001000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 4: if(((vol & 0b00010000)>>4)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 5: if(((vol & 0b00100000)>>5)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 6: if(((vol & 0b01000000)>>6)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 7: if(((vol & 0b10000000)>>7)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; } PORTD |=(1<<CL); } } void set_treble(int treb){ switch(treb){ case 5: treb = 0b1010;break;//10dB case 4: treb = 0b0010;break;//8dB case 3: treb = 0b1100;break;//6dB case 2: treb = 0b0100;break;//4dB case 1: treb = 0b1000;break;//2dB case 0: treb = 0b0000;break;//0dB case -1: treb = 0b1001;break;//-2dB case -2: treb = 0b0101;break;//-4dB case -3: treb = 0b1101;break;//-6dB case -4: treb = 0b0011;break;//-8dB case -5: treb = 0b1011;break;//10dB } for(int i = 3; i >= 0; i--){ PORTD &=~(1<<CL); if(((treb>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } } void set_bass(int bass){ switch(bass){ case 10: bass = 0b010100;break;//20dB case 9 : bass = 0b100100;break;//18dB case 8 : bass = 0b000100;break;//16dB case 7 : bass = 0b111000;break;//14dB case 6 : bass = 0b011000;break;//12dB case 5 : bass = 0b101000;break;//10dB case 4 : bass = 0b001000;break;//8dB case 3 : bass = 0b110000;break;//6dB case 2 : bass = 0b010000;break;//4dB case 1 : bass = 0b101000;break;//2dB case 0 : bass = 0b000000;break;//0dB case -1: bass = 0b100010;break;//-2dB case -2: bass = 0b010010;break;//-4dB case -3: bass = 0b110010;break;//-6dB case -4: bass = 0b001010;break;//-8dB case -5: bass = 0b101010;break;//-10dB case -6: bass = 0b011010;break;//-12dB case -7: bass = 0b111010;break;//-14dB case -8: bass = 0b000110;break;//-16dB case -9: bass = 0b100110;break;//-18dB case -10: bass = 0b010110;break;//-20dB } for(int i = 5; i >= 0; i--){ PORTD &=~(1<<CL); if(((bass>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } } void set_ch(byte ch){ switch(ch){ case 1: ch = 0b01;break; case 2: ch = 0b10;break; case 3: ch = 0b11;break; } for(int i = 1; i >= 0; i--){ PORTD &=~(1<<CL); if(((ch>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } } void test(){ byte test = 0; for(int i = 3; i >= 0; i--){ PORTD &=~(1<<CL); if(((test>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } PORTD &=~(1<<CL); PORTD &=~(1<<CE); } void audio_L(){ addr(); set_input(0); // input 1...4 = byte 0...3 (byte 4...7 = All switches off) set_gain(gain0); // gain 0...30 dB step 2 dB = byte 0...15 set_volume(vol_reg-ball); // volume 0...-79 dB = byte 0...79 set_treble(treb_reg); // treble 10...-10 dB step 2 dB = int 5...-5 set_bass(bass_reg); // bass 20...-20 dB step 2 dB = int 10...-10 set_ch(1); // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 test(); } void audio_R(){ addr(); set_input(0); // input 1...4 = byte 0...3 (byte 4...7 = All switches off) set_gain(gain0); // gain 0...30 dB step 2 dB = byte 0...15 set_volume(vol_reg+ball); // volume 0...-79 dB = byte 0...79 set_treble(treb_reg); // treble 10...-10 dB step 2 dB = int 5...-5 set_bass(bass_reg); // bass 20...-20 dB step 2 dB = int 10...-10 set_ch(2); // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 test(); } unsigned char EEPROM_read(unsigned int uiAddress){ while(EECR & (1<<EEPE)); // проверка готовности EEPROM EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H EEARL = uiAddress & 0x0F; // регистр адреса L EECR |= (1<<EERE);// чтение EEPROM return EEDR; // вывод значения } void EEPROM_write(unsigned int uiAddress, unsigned char ucData){ while(EECR & (1<<EEPE)); // проверка готовности EEPROM EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H EEARL = uiAddress & 0x0F; // регистр адреса L EEDR = ucData; // регистр данных EECR |= (1<<EEMPE);// Разрешение записи в EEPROM EECR |= (1<<EEPE); // Запись в EEPROM }
Скетч использует 5738 байт (70%) памяти устройства. Всего доступно 8192 байт.
Глобальные переменные используют 141 байт (13%) динамической памяти, оставляя 883 байт для локальных переменных. Максимум: 1024 байт.
Доработка
В проект регулятора громкости и тембра на LC75342 добавлен ИК пульт.
ИК пульт дублирует работу энкодера и кнопок. Для управления регулятором подойдет практически любой пульт ИК, для поддержки Вашего пульта необходимо прописать коды кнопок в скетч:
#define IR2 0x33B820DF // button encoder #define IR3 0x33B8946B // mute #define IR4 0x33B810EF // >>> #define IR5 0x33B8E01F // <<< #define IR6 0x33B844BB // INPUT
Так как проект не использует интерфейс UART, то получение кода кнопок через монитор порта не возможно, поэтому ниже показан скетч который позволяет получить коды кнопок выводя их на LCD1602_I2C. ИК датчик подключается к пину 26 (PC3) микроконтроллера Atmega88.
#define IR_IN PC3 #include <avr/io.h> #include <util/delay.h> #include <Wire_low.h> // http://forum.rcl-radio.ru/viewtopic.php?pid=5521#p5521 #include <Lcd1602_i2c_low.h> // http://rcl-radio.ru/wp-content/uploads/2022/03/Lcd1602_i2c_low.zip Lcd1602_i2c_low lcd(0x27);// адрес I2C bool data[96],st,st1,raz; uint32_t cod; byte i1,i2,s; unsigned long data_ir; int main(){ wire_set(12000000,100000); // тактовая частота контроллера, частота шины I2C lcd.setInit(); lcd.Clear(); // очистка экрана lcd.led(1); // включение и отключение подсветки экрана ////////// TIMER_1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; // (12000000/((6749+1)x1)) = 562.5 mks OCR1A = 6749; TCCR1B |= (1 << WGM12); // Prescaler 1 TCCR1B |= (1 << CS10); TIMSK1 |= (1 << OCIE1A); sei(); while(1){ lcd.Curs(0,0); lcd.PrintString("IR_CODE"); if(raz==1){ lcd.Clear(); data_ir = IR(); String stringVar = String(data_ir, HEX); char charVar[10]; stringVar.toCharArray(charVar, 10); lcd.Curs(1,0); lcd.PrintString(charVar); _delay_ms(200); } }} ISR(TIMER1_COMPA_vect){ if(((PINC >> IR_IN) & 1)==0&&st==0&&raz==0){st=1;OCR1A = 6749;} if(st==1){s++;} if(s>20&&((PINC >> IR_IN) & 1)==0){st1=1;} if(st1==1){data[i1]=((PINC >> IR_IN) & 1);i1++;} if(i1>96){i1=0;s=0;st=0;raz=1;st1=0;TCCR1B &= ~(1 << CS10); } } uint32_t IR(){ _delay_ms(100); cod=0;i2=0; for(int ai=0;ai<96;ai++){ if(data[ai] + data[ai+2] == 2){cod += ((uint32_t)0 << 31-i2);i2++;ai=ai+1;} if(data[ai] + data[ai+2] == 1){cod += ((uint32_t)1 << 31-i2);i2++;ai=ai+3;}} raz=0; TCCR1B |= (1 << CS10);OCR1A = 239;//50000 kHz if(cod==1||cod>0x7fffffff){cod=0xFFFFFFFF;} return cod;}
После получения кодов кнопок пульта, необходимо их вписать в основной скетч и загрузить его в микроконтроллер.
// ATMEGA88 12 MHz #define IR2 0x33B820DF // button encoder #define IR3 0x33B8946B // mute #define IR4 0x33B810EF // >>> #define IR5 0x33B8E01F // <<< #define IR6 0x33B844BB // INPUT #define CE PD0 #define DI PD1 #define CL PD2 #define DT PD5 #define CLK PD6 #define SW PD7 #define IN PB1 #define MUTE PB2 #define IR_IN PC3 #include <avr/io.h> #include <util/delay.h> #include <Wire_low.h> // http://forum.rcl-radio.ru/viewtopic.php?pid=5521#p5521 #include <Lcd1602_i2c_low.h> // http://rcl-radio.ru/wp-content/uploads/2022/03/Lcd1602_i2c_low.zip Lcd1602_i2c_low lcd(0x27);// адрес I2C volatile uint8_t _prevValueAB = 0; volatile uint8_t _currValueAB = 0; volatile int16_t newPosition = 0; int position = -999; int menu,vol_reg,mute_reg,in_reg,vol_old,treb_reg,treb_print,bass_reg,bass_print,ball,chl,chr,i; byte a[6],d1,d2,d3,d4,d5,d6,e1,e2,e3,w,w2,x,www,gr1,gr2; int gain0,gain1,gain2,gain3,gain4,gain5,gain0_print; unsigned long millis_times,times,data_ir,d_ir; bool data[96],st,st1,raz; uint32_t cod; byte i1,i2,s; int main(){ cli(); ////////// TIMER_2 TCCR2A = 0; TCCR2B = 0; TCNT2 = 0; // (12000000/((186+1)x64))=1002.6737967914 Hz OCR2A = 186; TCCR2A |= (1 << WGM21); // Prescaler 64 TCCR2B |= (1 << CS22); TIMSK2 |= (1 << OCIE2A); ////////// TIMER_1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; // (12000000/((6749+1)x1)) = 562.5 mks OCR1A = 6749; TCCR1B |= (1 << WGM12); // Prescaler 1 TCCR1B |= (1 << CS10); TIMSK1 |= (1 << OCIE1A); sei(); wire_set(12000000,100000); // тактовая частота контроллера, частота шины I2C lcd.setInit(); lcd.Clear(); // очистка экрана lcd.led(1); // включение и отключение подсветки экрана lcd.Write(0, 0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111); lcd.Write(1, 0b00111,0b00111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000); lcd.Write(2, 0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111); lcd.Write(3, 0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111); lcd.Write(4, 0b11100,0b11100,0b00000,0b00000,0b00000,0b00000,0b11100,0b11100); lcd.Write(5, 0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100); lcd.Write(6, 0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00111,0b00111); lcd.Write(7, 0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000); DDRD |=(1<<CE)|(1<<DI)|(1<<CL); PORTD &=~(1<<CE)|(1<<DI)|(1<<CL); PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT21)|(1 << PCINT22); PORTB |=(1<<IN)|(1<<MUTE); if(EEPROM_read(100)!=0){for(int i=0;i<101;i++){EEPROM_write(i,0);}}// очистка памяти при первом включении vol_reg = EEPROM_read(0);treb_reg = EEPROM_read(1)-5;bass_reg = EEPROM_read(2)-10;gain1 = EEPROM_read(4); gain2 = EEPROM_read(5);gain3 = EEPROM_read(6);gain4 = EEPROM_read(7);gain5 = EEPROM_read(8); in_reg = EEPROM_read(9);ball = EEPROM_read(10)-4; switch(in_reg){ case 0: gain0 = gain1;break; case 1: gain0 = gain2;break; case 2: gain0 = gain3;break; case 3: gain0 = gain4;break; } audio_L(); audio_R(); while(1){ /// IR READ if(raz==1){d_ir=IR();} /// BUTTON /////////////////////////////////// if(mute_reg==0){ if(((PIND >> SW) & 1)==0||d_ir==IR2){menu++;d_ir=0;cl();w2=1;w=1;times=millis_times;if(menu>3){menu=0;}} if(((PINB >> IN) & 1)==0||d_ir==IR6){in_reg++;d_ir=0;menu=4;cl();w=1;times=millis_times;if(in_reg>3){in_reg=0;}} } if((((PINB >> MUTE) & 1)==0||d_ir==IR3)&&mute_reg==0){mute_reg=1;d_ir=0;menu=100;cl();w=1;times=millis_times;vol_old=vol_reg;vol_reg=79;audio_R();audio_L();lcd.Curs(0,6);lcd.PrintString("MUTE");} if((((PINB >> MUTE) & 1)==0||d_ir==IR3)&&mute_reg==1){mute_reg=0;d_ir=0;menu=0;cl();w=1;times=millis_times;vol_reg=vol_old;audio_R();audio_L();} ////////////// VOLUME /////////////////////////////////////////////////////////////////// if(menu==0){ if(d_ir==IR5){vol_reg++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка > if(d_ir==0xFFFFFFFF and gr1==1){vol_reg++;gr2=0;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка >>>>>> if(d_ir==IR4){vol_reg--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка < if(d_ir==0xFFFFFFFF and gr2==1){vol_reg--;gr1=0;d_ir=0;w=1;times=millis_times;vol_func();audio_R();audio_L();}// кнопка <<<<<< if(newPosition != position){position = newPosition;vol_reg = vol_reg+newPosition;newPosition=0;w=1;times=millis_times;vol_func();audio_R();audio_L();} a[0]= (79-vol_reg)/10;a[1]=(79-vol_reg)%10; for(x=0;x<2;x++){switch(x){case 0: e1=10,e2=11,e3=12;break;case 1: e1=13,e2=14,e3=15;break;}digit();} if(mute_reg==0){lcd.Curs(0,0);lcd.PrintString("VOLUME");}else{lcd.Curs(0,0);lcd.PrintString("MUTE");} lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1); } ////////////// TREBLE /////////////////////////////////////////////////////////////////// if(menu==1){ if(d_ir==IR4){treb_reg++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;treb_func();audio_R();audio_L();}// кнопка > if(d_ir==IR5){treb_reg--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;treb_func();audio_R();audio_L();}// кнопка < if(newPosition != position){position = newPosition;treb_reg = treb_reg-newPosition;newPosition=0;w=1;times=millis_times;treb_func();audio_R();audio_L();} if(treb_reg<0){treb_print = (-treb_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{treb_print = treb_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");} a[0]= treb_print/10;a[1]=treb_print%10; for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();} lcd.Curs(0,0);lcd.PrintString("TREBLE");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB"); } ////////////// BASS /////////////////////////////////////////////////////////////////// if(menu==2){ if(d_ir==IR4){bass_reg++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;bass_func();audio_R();audio_L();}// кнопка > if(d_ir==IR5){bass_reg--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;bass_func();audio_R();audio_L();}// кнопка < if(newPosition != position){position = newPosition;bass_reg = bass_reg-newPosition;newPosition=0;w=1;times=millis_times;bass_func();audio_R();audio_L();} if(bass_reg<0){bass_print = (-bass_reg)*2;lcd.Curs(0,7);lcd.PrintChar(2);}else{bass_print = bass_reg*2;lcd.Curs(0,7);lcd.PrintString(" ");} a[0]= bass_print/10;a[1]=bass_print%10; for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();} lcd.Curs(0,0);lcd.PrintString("BASS");lcd.Curs(1,0);lcd.PrintString("CONTROL");lcd.Curs(0,14);lcd.PrintString("dB"); } //////// BALANCE /////////////////////////////////////////////////////////////// if(menu==3){ if(d_ir==IR4){ball++;gr1=1;gr2=0;d_ir=0;w2=1;w=1;times=millis_times;ball_fun();audio_R();audio_L();}// кнопка > if(d_ir==IR5){ball--;gr1=0;gr2=1;d_ir=0;w2=1;w=1;times=millis_times;ball_fun();audio_R();audio_L();}// кнопка < if(newPosition != position){position = newPosition;ball = ball-newPosition;newPosition=0;w=1;w2=1;times=millis_times;ball_fun();audio_R();audio_L();} lcd.Curs(0,4);lcd.PrintString(" <> ");lcd.Curs(1,4);lcd.PrintString("CHL CHR"); chl=(4+ball)-4;chr=(4-ball)-4; if(chl<0){lcd.Curs(0,12);chl=(-chl);lcd.PrintChar(2);}else{lcd.Curs(0,12);lcd.PrintString(" ");} if(chr<0){lcd.Curs(0,0);chr=(-chr);lcd.PrintChar(2);}else{lcd.Curs(0,0);lcd.PrintString(" ");} if(w2==1){w2=0;a[0]=chl;a[1]=chr; for(i=0;i<2;i++){ switch(i){ case 0: e1=1,e2=2,e3=3;break; case 1: e1=13,e2=14,e3=15;break; } switch(a[i]){ case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break; case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break; case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break; case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break; case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break; } char_lcd(); }}} ////////////// INPUT GAIN /////////////////////////////////////////////////////////////////// if(menu==4){ switch(in_reg){ case 0: gain0 = gain1;break; case 1: gain0 = gain2;break; case 2: gain0 = gain3;break; case 3: gain0 = gain4;break;} if(d_ir==IR4){gain0++;gr1=1;gr2=0;d_ir=0;w=1;times=millis_times;gain_func();audio_R();audio_L();}// кнопка > if(d_ir==IR5){gain0--;gr1=0;gr2=1;d_ir=0;w=1;times=millis_times;gain_func();audio_R();audio_L();}// кнопка < if(newPosition != position){position = newPosition;gain0 = gain0-newPosition;newPosition=0;w=1;times=millis_times;www=1;gain_func();} switch(in_reg){ case 0: gain1 = gain0;break; case 1: gain2 = gain0;break; case 2: gain3 = gain0;break; case 3: gain4 = gain0;break;} gain0_print = gain0*2; a[0]= gain0_print/10;a[1]=gain0_print%10; for(x=0;x<2;x++){switch(x){case 0: e1=8,e2=9,e3=10;break;case 1: e1=11,e2=12,e3=13;break;}digit();} if(www==1){audio_R();audio_L();www=0;} lcd.Curs(0,0);lcd.PrintString("IN GAIN");lcd.Curs(0,14);lcd.PrintString("dB"); lcd.Curs(1,0);lcd.PrintString("INPUT ");lcd.PrintInt(in_reg+1);} ////////////////// EEPROM ////////////////////////////////////////////////////////////// if(millis_times-times>10000 && w==1 && mute_reg==0){ EEPROM_write(0,vol_reg);EEPROM_write(1,treb_reg+5);EEPROM_write(2,bass_reg+10);EEPROM_write(4,gain1); EEPROM_write(5,gain2);EEPROM_write(6,gain3);EEPROM_write(7,gain4);EEPROM_write(8,gain5); EEPROM_write(9,in_reg);EEPROM_write(10,ball+4); if(menu!=0){lcd.Clear();menu=0;}w=0;} }}// end while ISR(TIMER1_COMPA_vect){ if(((PINC >> IR_IN) & 1)==0&&st==0&&raz==0){st=1;OCR1A = 6749;} if(st==1){s++;} if(s>20&&((PINC >> IR_IN) & 1)==0){st1=1;} if(st1==1){data[i1]=((PINC >> IR_IN) & 1);i1++;} if(i1>96){i1=0;s=0;st=0;raz=1;st1=0;TCCR1B &= ~(1 << CS10); } } ISR(TIMER2_COMPA_vect){millis_times++;} uint32_t IR(){ _delay_ms(100); cod=0;i2=0; for(int ai=0;ai<96;ai++){ if(data[ai] + data[ai+2] == 2){cod += ((uint32_t)0 << 31-i2);i2++;ai=ai+1;} if(data[ai] + data[ai+2] == 1){cod += ((uint32_t)1 << 31-i2);i2++;ai=ai+3;}} raz=0; TCCR1B |= (1 << CS10);OCR1A = 239;//50000 kHz if(cod==1||cod>0x7fffffff){cod=0xFFFFFFFF;} return cod;} void digit(){switch(a[x]){ case 0: d1=0,d2=7,d3=5,d4=0,d5=2,d6=5;break;case 1: d1=32,d2=1,d3=5,d4=32,d5=32,d6=5;break; case 2: d1=1,d2=7,d3=5,d4=0,d5=3,d6=4;break;case 3: d1=1,d2=3,d3=5,d4=6,d5=2,d6=5;break; case 4: d1=0,d2=2,d3=5,d4=32,d5=32,d6=5;break;case 5: d1=0,d2=3,d3=4,d4=6,d5=2,d6=5;break; case 6: d1=0,d2=3,d3=4,d4=0,d5=2,d6=5;break;case 7: d1=0,d2=7,d3=5,d4=32,d5=32,d6=5;break; case 8: d1=0,d2=3,d3=5,d4=0,d5=2,d6=5;break;case 9: d1=0,d2=3,d3=5,d4=6,d5=2,d6=5;break;} char_lcd();} void char_lcd(){ lcd.Curs(0,e1);lcd.PrintChar(d1);lcd.Curs(0,e2);lcd.PrintChar(d2);lcd.Curs(0,e3);lcd.PrintChar(d3); lcd.Curs(1,e1); lcd.PrintChar(d4);lcd.Curs(1,e2);lcd.PrintChar(d5);lcd.Curs(1,e3);lcd.PrintChar(d6); } void vol_func(){if(vol_reg<4){vol_reg=4;}if(vol_reg>79){vol_reg=79;}} void gain_func(){{if(gain0<0){gain0=0;}if(gain0>15){gain0=15;}}} void ball_fun(){if(ball>4){ball=4;}if(ball<-4){ball=-4;}} void bass_func(){if(bass_reg<-10){bass_reg=-10;}if(bass_reg>10){bass_reg=10;}} void treb_func(){if(treb_reg<-5){treb_reg=-5;}if(treb_reg>5){treb_reg=5;}} void cl(){_delay_ms(200);lcd.Clear();} ISR(PCINT2_vect){ bool pinA = ((PIND >> DT) & 1); bool pinB = ((PIND >> CLK) & 1); _currValueAB = (pinA << 1) | pinB; switch(_prevValueAB | _currValueAB){ case 0b0001: newPosition++;break; case 0b0100: newPosition--;break; } _prevValueAB = _currValueAB << 2; } void addr(){ PORTD &=~(1<<CL)|(1<<CE); byte addr = 0b01000001; for(int i = 7; i >= 0; i--){ PORTD &=~(1<<CL); if(((addr>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } PORTD |=(1<<CE); } void set_input(byte in){ for(int i = 0; i <= 3; i++){ PORTD &=~(1<<CL); switch(i){ case 0: if(((in & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 1: if(((in & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 2: if(((in & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 3: if(((in & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; } PORTD |=(1<<CL); } } void set_gain(byte gain){ for(int i = 0; i <= 3; i++){ PORTD &=~(1<<CL); switch(i){ case 0: if(((gain & 0b0001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 1: if(((gain & 0b0010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 2: if(((gain & 0b0100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 3: if(((gain & 0b1000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; } PORTD |=(1<<CL); } } void set_volume(byte vol){ for(int i = 0; i <= 7; i++){ PORTD &=~(1<<CL); switch(i){ case 0: if(((vol & 0b00000001)>>0)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 1: if(((vol & 0b00000010)>>1)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 2: if(((vol & 0b00000100)>>2)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 3: if(((vol & 0b00001000)>>3)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 4: if(((vol & 0b00010000)>>4)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 5: if(((vol & 0b00100000)>>5)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 6: if(((vol & 0b01000000)>>6)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; case 7: if(((vol & 0b10000000)>>7)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);};break; } PORTD |=(1<<CL); } } void set_treble(int treb){ switch(treb){ case 5: treb = 0b1010;break;//10dB case 4: treb = 0b0010;break;//8dB case 3: treb = 0b1100;break;//6dB case 2: treb = 0b0100;break;//4dB case 1: treb = 0b1000;break;//2dB case 0: treb = 0b0000;break;//0dB case -1: treb = 0b1001;break;//-2dB case -2: treb = 0b0101;break;//-4dB case -3: treb = 0b1101;break;//-6dB case -4: treb = 0b0011;break;//-8dB case -5: treb = 0b1011;break;//10dB } for(int i = 3; i >= 0; i--){ PORTD &=~(1<<CL); if(((treb>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } } void set_bass(int bass){ switch(bass){ case 10: bass = 0b010100;break;//20dB case 9 : bass = 0b100100;break;//18dB case 8 : bass = 0b000100;break;//16dB case 7 : bass = 0b111000;break;//14dB case 6 : bass = 0b011000;break;//12dB case 5 : bass = 0b101000;break;//10dB case 4 : bass = 0b001000;break;//8dB case 3 : bass = 0b110000;break;//6dB case 2 : bass = 0b010000;break;//4dB case 1 : bass = 0b101000;break;//2dB case 0 : bass = 0b000000;break;//0dB case -1: bass = 0b100010;break;//-2dB case -2: bass = 0b010010;break;//-4dB case -3: bass = 0b110010;break;//-6dB case -4: bass = 0b001010;break;//-8dB case -5: bass = 0b101010;break;//-10dB case -6: bass = 0b011010;break;//-12dB case -7: bass = 0b111010;break;//-14dB case -8: bass = 0b000110;break;//-16dB case -9: bass = 0b100110;break;//-18dB case -10: bass = 0b010110;break;//-20dB } for(int i = 5; i >= 0; i--){ PORTD &=~(1<<CL); if(((bass>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } } void set_ch(byte ch){ switch(ch){ case 1: ch = 0b01;break; case 2: ch = 0b10;break; case 3: ch = 0b11;break; } for(int i = 1; i >= 0; i--){ PORTD &=~(1<<CL); if(((ch>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } } void test(){ byte test = 0; for(int i = 3; i >= 0; i--){ PORTD &=~(1<<CL); if(((test>>i)&0x01)==1){PORTD |=(1<<DI);}else{PORTD &=~(1<<DI);} PORTD |=(1<<CL); } PORTD &=~(1<<CL); PORTD &=~(1<<CE); } void audio_L(){ addr(); set_input(0); // input 1...4 = byte 0...3 (byte 4...7 = All switches off) set_gain(gain0); // gain 0...30 dB step 2 dB = byte 0...15 set_volume(vol_reg-ball); // volume 0...-79 dB = byte 0...79 set_treble(treb_reg); // treble 10...-10 dB step 2 dB = int 5...-5 set_bass(bass_reg); // bass 20...-20 dB step 2 dB = int 10...-10 set_ch(1); // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 test(); } void audio_R(){ addr(); set_input(0); // input 1...4 = byte 0...3 (byte 4...7 = All switches off) set_gain(gain0); // gain 0...30 dB step 2 dB = byte 0...15 set_volume(vol_reg+ball); // volume 0...-79 dB = byte 0...79 set_treble(treb_reg); // treble 10...-10 dB step 2 dB = int 5...-5 set_bass(bass_reg); // bass 20...-20 dB step 2 dB = int 10...-10 set_ch(2); // Channel Selection RCH = byte 2, LCH = byte 1, Left and right together = byte 3 test(); } unsigned char EEPROM_read(unsigned int uiAddress){ while(EECR & (1<<EEPE)); // проверка готовности EEPROM EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H EEARL = uiAddress & 0x0F; // регистр адреса L EECR |= (1<<EERE);// чтение EEPROM return EEDR; // вывод значения } void EEPROM_write(unsigned int uiAddress, unsigned char ucData){ while(EECR & (1<<EEPE)); // проверка готовности EEPROM EEARH = ((uiAddress & 0xF0) << 2); // регистр адреса H EEARL = uiAddress & 0x0F; // регистр адреса L EEDR = ucData; // регистр данных EECR |= (1<<EEMPE);// Разрешение записи в EEPROM EECR |= (1<<EEPE); // Запись в EEPROM }
Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=5542#p5542