// LGT8F328 | ATtmega328
#define SW 10
#define MUTE 7
#define POWER 11
#define POWER_OUT 5
#define LCD_LED_OUT 6
#define IR 12
#define MUTE_PIN 13
#define BRIG_H 200 // Яркость 0…255 POWER ON
#define BRIG_L 50 // Яркость 0…255 POWER OFF
#define IR1 0x807F48B7 // VOL+
#define IR2 0x807FC837 // VOL-
#define IR3 0x807FD02F // BAL+
#define IR4 0x807F50AF // BAL-
#define IR5 0x807FF807 // MUTE
#define IR6 0x807F807F // POWER
#include <Wire.h>
#include <EEPROM.h>
#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 <CS3310.h> // http://rcl-radio.ru/wp-content/uploads/2020/11/CS3310.zip
#include <LiquidCrystal_I2C.h> // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
#include <DS3231.h> // http://rcl-radio.ru/wp-content/uploads/2022/07/DS3231.zip
#include <boarddefs.h> // входит в состав библиотеки IRremote
#include <IRremote.h> // http://rcl-radio.ru/wp-content/uploads/2019/06/IRremote.zip
LiquidCrystal_I2C lcd(0x27,16,2); // Устанавливаем дисплей
Encoder myEnc(9, 8);//CLK, DT
CS3310 pga(2,3,4);//CS,SCLK,SDATAI
DS3231 clock;RTCDateTime DateTime;
IRrecv irrecv(IR); // указываем вывод модуля IR приемника
decode_results ir;
int a[4],vol,vol_d,z,z0,z1,vol_old,balanc,x;
byte w,w1,mute,menu;
unsigned long times,oldPosition = -999,newPosition,times_3231;
byte power, d1,d2,d3,d4,d5,d6,e1,e2,e3;
int hour,minut,secon,old_sec;
bool gr1,gr2;
void setup(){
delay(100);
Wire.begin();Serial.begin(9600);
lcd.init();lcd.backlight();clock.begin();
irrecv.enableIRIn();
MsTimer2::set(1, to_Timer);MsTimer2::start();
pinMode(LCD_LED_OUT,OUTPUT); // ВЫХОД УПРАВЛЕНИЯ ПОДСВЕТКОЙ
analogWrite(LCD_LED_OUT, BRIG_H);
lcd.setCursor(0,0);lcd.print(" PGA2311 ");
lcd.setCursor(0,1);lcd.print(" Volume Control ");delay(1000);lcd.clear();
if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении
vol = EEPROM.read(0);
balanc = EEPROM.read(1)-20;
// clock.setDateTime(__DATE__, __TIME__);
pinMode(SW,INPUT); // кнопка энкодера MENU
pinMode(MUTE,INPUT_PULLUP); // кнопка MUTE
pinMode(POWER,INPUT_PULLUP); // кнопка POWER
pinMode(POWER_OUT,OUTPUT); // выход управления POWER
pinMode(MUTE_PIN,OUTPUT); // выход управления MUTE
digitalWrite(MUTE_PIN,HIGH);
audio();
}
void loop(){
if ( irrecv.decode( &ir )) {Serial.print("0x");Serial.println( ir.value,HEX);irrecv.resume();times=millis();w=1;w1=1;}// IR приемник - чтение, в мониторе порта отображаются коды кнопок
if(ir.value==0){gr1=0;gr2=0;}// запрет нажатий не активных кнопок пульта
if(ir.value==IR1 && menu!=0&&mute==0&&power==0){vol++;menu=0;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;vol_func();audio();}
if(ir.value==IR2 && menu!=0&&mute==0&&power==0){vol--;menu=0;gr1=0;gr2=1;cl();times=millis();w=1;w1=1;vol_func();audio();}
if(ir.value==IR3 && menu!=1&&mute==0&&power==0){balanc++;menu=1;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;balanc_func();audio();}
if(ir.value==IR4 && menu!=1&&mute==0&&power==0){balanc--;menu=1;gr1=1;gr2=0;cl();times=millis();w=1;w1=1;balanc_func();audio();}
if(power==0){
byte a1[8] = {0b00000,0b10101,0b10101,0b10101,0b10101,0b10101,0b10101,0b00000};
byte a2[8] = {0b00000,0b10100,0b10100,0b10100,0b10100,0b10100,0b10100,0b00000};
byte a3[8] = {0b00000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b00000};
lcd.createChar(0,a1);lcd.createChar(1,a2);lcd.createChar(2,a3);
}
else{
byte v1[8] = {0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111,0b00111};
byte v2[8] = {0b00111,0b00111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000};
byte v3[8] = {0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111};
byte v4[8] = {0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b11111,0b11111};
byte v5[8] = {0b11100,0b11100,0b00000,0b00000,0b00000,0b00000,0b11100,0b11100};
byte v6[8] = {0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100};
byte v7[8] = {0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00111,0b00111};
byte v8[8] = {0b11111,0b11111,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000};
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);
}
if(power==0){
digitalWrite(POWER_OUT,HIGH); //STBY
analogWrite(LCD_LED_OUT, BRIG_H);
/// MENU ///////////////////////////////////////
if(digitalRead(SW)==LOW){menu++;if(menu>1){menu=0;}lcd.clear();times=millis();w=1;w1=1;delay(200);}
/// MUTE ///////////////////////////////////////
if((digitalRead(MUTE)==LOW||ir.value==IR5)&&mute==0){mute=1;digitalWrite(MUTE_PIN,LOW);audio();cl();lcd.setCursor(0,0);lcd.print(" MUTE ");delay(300);}
if((digitalRead(MUTE)==LOW||ir.value==IR5)&&mute==1){mute=0;digitalWrite(MUTE_PIN,HIGH);audio();cl();w1=1;delay(300);}
}
else{analogWrite(LCD_LED_OUT, BRIG_L);digitalWrite(POWER_OUT,LOW);}//STBY
if((digitalRead(POWER)==LOW||ir.value==IR6)&&digitalRead(SW)==HIGH&&power==0&&mute==0){power=1;digitalWrite(MUTE_PIN,LOW);audio();cl();
lcd.setCursor(0,0);lcd.print(" POWER OFF ");delay(500);}
if((digitalRead(POWER)==LOW||ir.value==IR6)&&digitalRead(SW)==HIGH&&power==1){power=0;digitalWrite(MUTE_PIN,HIGH);audio();cl();
lcd.setCursor(0,0);lcd.print(" POWER ON ");w1=1;delay(500);}
/////////////// VOLUME /////////////////////////////////////////////////////////
if(menu==0&&mute==0&&power==0){
if(ir.value==IR1){vol++;gr1=1;gr2=0;cl1();times=millis();w=1;w1=1;vol_func();audio();}
if(ir.value==0xFFFFFFFF and gr1==1){vol++;gr2=0;cl1();times=millis();w=1;w1=1;vol_func();audio();}
if(ir.value==IR2){vol--;gr1=0;gr2=1;cl1();times=millis();w=1;w1=1;vol_func();audio();}
if(ir.value==0xFFFFFFFF and gr2==1){vol--;gr1=0;cl1();times=millis();w=1;w1=1;vol_func();audio();}
if (newPosition != oldPosition&&mute==0){oldPosition = newPosition;
vol=vol+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;vol_func();audio();}
vol_d=map(vol,0,235,0,45);
if(w1==1){
for(z=0,z0=0,z1=0;z<=vol_d;z++,z1++){if(z1>2){z1=0;z0++;}
if(z1==1){lcd.setCursor(z0,1);lcd.write((uint8_t)0);lcd.setCursor(z0+1,1);lcd.print(" ");}}
if(z1==3){lcd.setCursor(z0,1);lcd.write((uint8_t)1);}
if(z1==2){lcd.setCursor(z0,1);lcd.write((uint8_t)2);}w1=0;}
lcd.setCursor(0,0);lcd.print("VOLUME ");
if(vol*0.5-96>=0){lcd.print("+");}
lcd.print(vol*0.5-96,1);lcd.print(" ");
lcd.setCursor(14,0);lcd.print("dB");
} // menu == 0
/////////////// BALANCE +/- 10 dB /////////////////////////////////////////////////////////
if(menu==1&&mute==0&&power==0){
if(ir.value==IR3){balanc++;gr1=1;gr2=0;cl1();times=millis();w=1;w1=1;balanc_func();audio();}
if(ir.value==0xFFFFFFFF and gr1==1){balanc++;gr2=0;cl1();times=millis();w=1;w1=1;balanc_func();audio();}
if(ir.value==IR4){balanc--;gr1=0;gr2=1;cl1();times=millis();w=1;w1=1;balanc_func();audio();}
if(ir.value==0xFFFFFFFF and gr2==1){balanc--;gr1=0;cl1();times=millis();w=1;w1=1;balanc_func();audio();}
if (newPosition != oldPosition&&mute==0){oldPosition = newPosition;
balanc=balanc+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;balanc_func();audio();}
lcd.setCursor(0,0);lcd.print("BALANCE ");if(balanc>=0){lcd.print("+");}lcd.print(balanc*0.5,1);lcd.print(" ");lcd.setCursor(14,0);lcd.print("dB");
if(w1==1){
if(balanc<0){lcd.setCursor(balanc/4-2+7,1);lcd.print(" ");lcd.write((uint8_t)0);lcd.print(" ");}
if(balanc==0){lcd.setCursor(balanc/4-2+7,1);lcd.print(" ");lcd.write((uint8_t)0);lcd.write((uint8_t)0);lcd.print(" ");}
if(balanc>0){lcd.setCursor(balanc/4-2+8,1);lcd.print(" ");lcd.write((uint8_t)0);lcd.print(" ");}
w1=0;}
}// menu == 1
if(power==1){
DateTime = clock.getDateTime();hour = DateTime.hour;minut = DateTime.minute;secon = DateTime.second;
int tim=1254;
a[0]=hour/10%10;
a[1]=hour%10;
a[2]=minut/10%10;
a[3]=minut%10;
for(x=0;x<4;x++){
switch(x){
case 0: e1=1,e2=2,e3=3;break;
case 1: e1=4,e2=5,e3=6;break;
case 2: e1=8,e2=9,e3=10;break;
case 3: e1=11,e2=12,e3=13;break;
}digit();}
if(millis()-times_3231<=500){ lcd.setCursor(7,0);lcd.print(".");lcd.setCursor(7,1);lcd.print(".");}
if(millis()-times_3231>500){ lcd.setCursor(7,0);lcd.print(" ");lcd.setCursor(7,1);lcd.print(" ");}
if(secon!=old_sec){times_3231=millis();}
old_sec=secon;
if(digitalRead(SW)==LOW&&digitalRead(MUTE)==LOW){hour++;if(hour>23){hour=0;} clock.setDateTime(2023, 1, 14, hour, minut, secon);delay(200);}// HH++
if(digitalRead(SW)==LOW&&digitalRead(POWER)==LOW){minut++;if(minut>59){minut=0;} clock.setDateTime(2023, 1, 14, hour, minut, secon);delay(200);}// MM++
}
//////// EEPROM //////////////////////////////////////////////////
if(millis()-times>10000 && w==1 && mute == 0 && power == 0){EEPROM.update(0,vol);EEPROM.update(1,balanc+20);w=0;menu=0;w1=1;lcd.clear();}
} // LOOP
void cl(){ir.value=0;delay(200);lcd.clear();}
void cl1(){ir.value=0;delay(50);}
void audio(){
pga.setVol(vol+balanc+20,vol-balanc+20);// byte 1...255 === -95.5...+31.5 dB (step 0.5 dB)
}
void to_Timer(){newPosition = myEnc.read()/4;}
void vol_func(){if(vol<0){vol=0;}if(vol>235){vol=235;}}
void balanc_func(){if(balanc<-20){balanc=-20;}if(balanc>20){balanc=20;}}
void digit(){switch(a[x]){
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);}