//****************************************************************************//
//ccs 4.084                                                                   //
//****************************************************************************//
#include <16F876A.h>
#fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP,NOCPD
#use delay (CLOCK = 8000000)

int8 const caracter0_direccion[8]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};
int8 const caracter0_datos[8]={0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,
0b10000,0b0};//Una barra vertical.

int8 const caracter1_direccion[8]={0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};
int8 const caracter1_datos[8]={0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,
0b11000,0b0};//Dos barras verticales.

int8 const caracter2_direccion[8]={0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57};
int8 const caracter2_datos[8]={0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,
0b11100,0b0};//Tres barras verticales.

int8 const caracter3_direccion[8]={0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f};
int8 const caracter3_datos[8]={0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,
0b11110,0b0};//Cuatro barras verticales.

int8 const caracter4_direccion[8]={0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67};
int8 const caracter4_datos[8]={0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,
0b11111,0b0};//Cinco barras verticales.

char const CD[4]={'C','D',' ',' '};
char const CD2[4]={'C','D','2',' '};
char const TV[4]={'T','V',' ',' '};
char const TV2[4]={'T','V','2',' '};
char const DVD[4]={'D','V','D',' '};
char const DVD2[4]={'D','V','D','2'};
char const MIC[4]={'M','I','C',' '};
char const LINE[4]={'L','I','N','E'};
char const LIN2[4]={'L','I','N','2'};
char const VCR[4]={'V','C','R',' '};
char const VCR2[4]={'V','C','R','2'};
char const MP3[4]={'M','P','3',' '};

#byte PORTA                = 0x05
#byte PORTB                = 0x06
#byte PORTC                = 0x07
#bit  GRABAR               = PORTB.2
#bit  ZUMBADOR             = PORTB.3
#bit  PULSADOR             = PORTC.2
#bit  CLK                  = PORTC.5
#bit  SDO                  = PORTC.6
#bit  CS                   = PORTC.7
#define REC_IR             PIN_B0
#define SALIDA_CANAL_SEL   PIN_B1
#define SI                 1
#define NO                 0
#define ON                 1
#define OFF                0
#define MAX_PORCENTAJE     80
#define VOL_MAX            80
#define VOL_MAX_BARRA_LCD  80
#define VOLUMEN            0
#define BALANCE            1
#define CANAL              2
#define PERIODO            0
#define FIN                400
#define INCREMENTAR        1
#define DECREMENTAR        0
#define N_TECLAS           13
#define N_CANAL            6//Numero de canales de audio de entrada.
#define N_NOMBRES          12//Numero de nombres de canales.
/******************************************************************************/
/* Definiciones para la interfaz PIC-LCD                                      */
/******************************************************************************/
# define TRISA 0x85// Registro de direccionamiento Puerto A
# define TRISB 0x86// Registro de direccionamiento Puerto B
# define TRISC 0x87// Registro de direccionamiento Puerto C
//Se definen los terminales de conexion del display
#bit lcd_db4 = PORTA.2
#bit tris_lcd_db4 = TRISA.2
#bit lcd_db5 = PORTA.3
#bit tris_lcd_db5 = TRISA.3
#bit lcd_db6 = PORTA.4
#bit tris_lcd_db6 = TRISA.4
#bit lcd_db7 = PORTA.5
#bit tris_lcd_db7 = TRISA.5

#bit lcd_en = PORTC.0
#bit tris_lcd_en = TRISC.0
#bit lcd_rs = PORTC.1
#bit tris_lcd_rs = TRISC.1
# include <lcd_flex.c>
#define EEPROM_SDA  PIN_C4
#define EEPROM_SCL  PIN_C3
# include <2416.c>
# use i2c(FAST, NOFORCE_SW, RESTART_WDT)
//****************************************************************************//
//   VARIABLES                                                                //
//****************************************************************************//

int EstadoProceso;//Cuando se pulsa la tecla GRABAR, va pasando por todas las
                   //teclas que se están programando, en primera pasada se
                   //captura la tecla; en segunda pasada se captura de nuevo y
                   //se comprueba.
int LecturaTemporal[2];//Almacena temporalmente la lectura de una tecla
                        //pulsada, para su posterior comprobación.
int Direccion;//Almacena la dirección de la EEPROM donde se guardan las teclas.

int TeclaIncVol;//Tecla incrementar volumen.

int TeclaDecVol;//Tecla decrementar volumen.

int TeclaIncCanal;

int TeclaDecCanal;

int TeclaBal_L;//Tecla balance hacia el canal L.

int TeclaBal_R;//Tecla balance hacia el canal R.

int TeclaMute;

int TeclaC1,TeclaC2,TeclaC3,TeclaC4,TeclaC5,TeclaC6;

int Volumen_L;//Almacena el volumen del canal L.

int Volumen_R;//Almacena el volumen del canal R.

int Porcentaje_L;//Almacena el porcentaje de volumen del canal L, para el
                  //balance.
int Porcentaje_R;//Almacena el porcentaje de volumen del canal R, para el
                  //balance.
int VolumenBarraLCD;//Almacena la posicion de la barra indicadora del volumen,
                    //y el estado del volumen.
int nbit, bit;

int Cont_R,Cont_L;

int Menu;

long TiempoLCD;//Sirve para mostrar automaticamente el canal y la barra del
      //volumen cuando pasan unos segundos sin tocar el mando o el encoder.

int SelectMenu;

byte data[2];

int state;

int IncDec;

char Cn_1[4],Cn_2[4],Cn_3[4],Cn_4[4],Cn_5[4],Cn_6[4];

int CanalSel;

int NombreCanal;

char a,b,c,d;

int VolAux;//Almacena el volumen temporalmente mientras se activa funcion mute.

int1 Mute;

int VolumenBarraLCD_Temp;
//****************************************************************************//
//Muestra el canal de entrada de audio seleccionado.                          //
//****************************************************************************//
void MostrarCanal(int CanalSel){
lcd_gotoxy(1,1);
switch (CanalSel) {
   case   0x00: printf(lcd_putc,"%c%c%c%c            "
                       ,Cn_1[0],Cn_1[1],Cn_1[2],Cn_1[3]);
      Break;
   case   0x01: printf(lcd_putc,"%c%c%c%c            "
                       ,Cn_2[0],Cn_2[1],Cn_2[2],Cn_2[3]);
      Break;
   case   0x02: printf(lcd_putc,"%c%c%c%c            "
                       ,Cn_3[0],Cn_3[1],Cn_3[2],Cn_3[3]);
      Break;
   case   0x03: printf(lcd_putc,"%c%c%c%c            "
                       ,Cn_4[0],Cn_4[1],Cn_4[2],Cn_4[3]);
      Break;
   case   0x04: printf(lcd_putc,"%c%c%c%c            "
                       ,Cn_5[0],Cn_5[1],Cn_5[2],Cn_5[3]);
      Break;
   case   0x05: printf(lcd_putc,"%c%c%c%c            "
                       ,Cn_6[0],Cn_6[1],Cn_6[2],Cn_6[3]);
      Break;
}
}
//****************************************************************************//
//Asigna al canal pasado como parametro el nombre seleccionado.               //
//****************************************************************************//
void AsignarNombreCanal(int NombCanal){
switch (NombCanal) {
   case    0x00: {a=CD[0];b=CD[1];c=CD[2];d=CD[3];}
      Break;
   case    0x01: {a=CD2[0];b=CD2[1];c=CD2[2];d=CD2[3];}
      Break;
   case    0x02: {a=TV[0];b=TV[1];c=TV[2];d=TV[3];}
      Break;
   case    0x03: {a=TV2[0];b=TV2[1];c=TV2[2];d=TV2[3];}
      Break;
   case    0x04: {a=DVD[0];b=DVD[1];c=DVD[2];d=DVD[3];}
      Break;
   case    0x05: {a=DVD2[0];b=DVD2[1];c=DVD2[2];d=DVD2[3];}
      Break;
   case    0x06: {a=MIC[0];b=MIC[1];c=MIC[2];d=MIC[3];}
      Break;
   case    0x07: {a=LINE[0];b=LINE[1];c=LINE[2];d=LINE[3];}
      Break;
   case    0x08: {a=LIN2[0];b=LIN2[1];c=LIN2[2];d=LIN2[3];}
      Break;
   case    0x09: {a=VCR[0];b=VCR[1];c=VCR[2];d=VCR[3];}
      Break;
   case    0x0A: {a=VCR2[0];b=VCR2[1];c=VCR2[2];d=VCR2[3];}
      Break;
   case    0x0B: {a=MP3[0];b=MP3[1];c=MP3[2];d=MP3[3];}
      Break;
}
lcd_gotoxy(13,1);//col13 fila 1
printf(lcd_putc,"%c%c%c%c",a,b,c,d);//Muestra por pantalla el nombre del canal.
lcd_gotoxy(1,2);//col 1 fila 2
printf(lcd_putc,"                ");//limpiar pantalla
}
//****************************************************************************//
//Actualiza el valor del volumen en el integrado PGA2311.                     //
//****************************************************************************//
void ActualizarVolumen(void){
int i,b;
CS=0; //Activa el PGA2311

b=Volumen_R*3;
for(i=8;i>0;i--){
   int8 x;
   x=1<<(i-1);
   if(b>=x){
      SDO=1;//Enviamos un '1'.
      b-=x;
   }else{
      SDO=0;//Enviamos un '0'.
   }
      CLK=0;//Mandamos un pulso
      CLK=1;//de reloj.
}

b=Volumen_L*3;
for(i=8;i>0;i--){
   int8 x;
   x=1<<(i-1);
   if(b>=x){
      SDO=1;//Enviamos un '1'.
      b-=x;
   }else{
      SDO=0;//Enviamos un '0'.
   }
      CLK=0;//Mandamos un pulso
      CLK=1;//de reloj.
}
CS=1; //Desactiva el PGA2311
}
//****************************************************************************//
//Guarda en la RAM del LCD los nuevos caracteres creados.                     //
//****************************************************************************//
Void GuardaCaracteresLCD(void){
int contador;

for(contador=0;contador<8;contador++){
      lcd_send_byte(0,caracter0_direccion[contador]);   //modo comando
      lcd_send_byte(1,caracter0_datos[contador]);        // modo dato
      lcd_send_byte(0,caracter1_direccion[contador]);   //modo comando
      lcd_send_byte(1,caracter1_datos[contador]);        // modo dato
      lcd_send_byte(0,caracter2_direccion[contador]);   //modo comando
      lcd_send_byte(1,caracter2_datos[contador]);        // modo dato
      lcd_send_byte(0,caracter3_direccion[contador]);   //modo comando
      lcd_send_byte(1,caracter3_datos[contador]);        // modo dato
      lcd_send_byte(0,caracter4_direccion[contador]);   //modo comando
      lcd_send_byte(1,caracter4_datos[contador]);        // modo dato
}
lcd_send_byte(0,0x80);

}
//****************************************************************************//
//Muestra dos cuadros que se desplazan indicando la posición del balance.     //
//****************************************************************************//
void MostrarBalance(int Bal_L, int Bal_R){
int B_L,B_R;

B_L=Bal_L;
if(Bal_L==MAX_PORCENTAJE)
     B_L=100;
B_R=Bal_R;
if(Bal_R==MAX_PORCENTAJE)
     B_R=100;
lcd_gotoxy(1,1);
printf(lcd_putc," L %3u%%  %3u%% R ",B_L,B_R);

lcd_gotoxy(1,2);
printf(lcd_putc,"                ");//limpiar pantalla

if( (Bal_L==MAX_PORCENTAJE) && (Bal_R==MAX_PORCENTAJE) ){
      lcd_gotoxy(8,2);
      printf(lcd_putc,"%c",4);
      lcd_gotoxy(9,2);
      printf(lcd_putc,"%c",4);
}
if(Bal_R<MAX_PORCENTAJE){
      lcd_gotoxy(Bal_R/10+1,2);
      printf(lcd_putc,"%c",4);
      lcd_gotoxy(Bal_R/10+2,2);
      printf(lcd_putc,"%c",4);
}
if(Bal_L<MAX_PORCENTAJE){
      lcd_gotoxy(16-Bal_L/10,2);
      printf(lcd_putc,"%c",4);
      lcd_gotoxy(15-Bal_L/10,2);
      printf(lcd_putc,"%c",4);
}
}
//****************************************************************************//
//Muestra en el LCD mediante una barra el nivel seleccionado.                 //
//****************************************************************************//
void MostrarBarraVolumenLCD(int Vol){
int  aux, Columna;

lcd_gotoxy(1,2);
printf(lcd_putc,"                ");//limpiar pantalla

aux=Vol;
Columna=1;
while(aux>=5){//Por cada pasada muestra un cuadro.
   aux=aux-5;
   lcd_gotoxy(Columna,2);
   printf(lcd_putc,"%c",4);
   Columna++;
}
lcd_gotoxy(Columna,2);
switch (aux) {
   case    0x01: printf(lcd_putc,"%c",0);
      Break;
   case    0x02: printf(lcd_putc,"%c",1);
      Break;
   case    0x03: printf(lcd_putc,"%c",2);
      Break;
   case    0x04: printf(lcd_putc,"%c",3);
      Break;
}
}
//****************************************************************************//
void GuardarVolumen(int CanalSel, int Vol){
switch (CanalSel) {
   case   0x00: write_ext_eeprom(76,Vol);
      Break;
   case   0x01: write_ext_eeprom(78,Vol);
      Break;
   case   0x02: write_ext_eeprom(80,Vol);
      Break;
   case   0x03: write_ext_eeprom(82,Vol);
      Break;
   case   0x04: write_ext_eeprom(84,Vol);
      Break;
   case   0x05: write_ext_eeprom(86,Vol);
      Break;
}
}
//****************************************************************************//
//Asigna el valor del volumen segun el porcentaje del balance.                //
//****************************************************************************//
int8 AsignarVolumen(int Vol, int Bal){
Float aux;
int Resultado;

aux=(float)Bal/MAX_PORCENTAJE;
aux=(float)aux*Vol;
Resultado=(int)aux;
return(Resultado);

}
//****************************************************************************//
//Incrementa el volumen.                                                      //
//****************************************************************************//
void IncrementaVolumen(void){

lcd_gotoxy(1,1);
printf(lcd_putc," VOLUMEN:       ");

VolumenBarraLCD++;
if(VolumenBarraLCD>VOL_MAX_BARRA_LCD)
      VolumenBarraLCD=VOL_MAX_BARRA_LCD;
GuardarVolumen(CanalSel,VolumenBarraLCD);

Volumen_L=AsignarVolumen(VolumenBarraLCD,Porcentaje_L);

Volumen_R=AsignarVolumen(VolumenBarraLCD,Porcentaje_R);

ActualizarVolumen();

MostrarBarraVolumenLCD(VolumenBarraLCD);
}
//****************************************************************************//
//Decrementa el volumen.                                                      //
//****************************************************************************//
void DecrementaVolumen(void){

lcd_gotoxy(1,1);
printf(lcd_putc," VOLUMEN:       ");

VolumenBarraLCD--;
if(VolumenBarraLCD==0xFF)
      VolumenBarraLCD=0;
GuardarVolumen(CanalSel,VolumenBarraLCD);

Volumen_L=AsignarVolumen(VolumenBarraLCD,Porcentaje_L);

Volumen_R=AsignarVolumen(VolumenBarraLCD,Porcentaje_R);

ActualizarVolumen();

MostrarBarraVolumenLCD(VolumenBarraLCD);
}
//****************************************************************************//
//Desplaza el balance hacia el canal R, bajnado el volumen del L.             //
//****************************************************************************//
void BalanceR(void){

Cont_L=0;
Porcentaje_R++;
if(Porcentaje_R>=MAX_PORCENTAJE){
     Porcentaje_R=MAX_PORCENTAJE;
     Cont_R++;
     if(Cont_R>1){//La primera pasada no entra, para L y R maximos.
         Cont_R=2;
         Porcentaje_L--;
         if(Porcentaje_L==0xFF)
            Porcentaje_L=0;
     }
}
Volumen_L=AsignarVolumen(VolumenBarraLCD,Porcentaje_L);

Volumen_R=AsignarVolumen(VolumenBarraLCD,Porcentaje_R);

write_ext_eeprom(72,Porcentaje_L);
write_ext_eeprom(74,Porcentaje_R);

ActualizarVolumen();

MostrarBalance(Porcentaje_L,Porcentaje_R);
}
//****************************************************************************//
//Desplaza el balance hacia el canal L, bajnado el volumen del R.             //
//****************************************************************************//
void BalanceL(void){

Cont_R=0;
Porcentaje_L++;
if(Porcentaje_L>=MAX_PORCENTAJE){
     Porcentaje_L=MAX_PORCENTAJE;
     Cont_L++;
     if(Cont_L>1){//La primera pasada no entra, para L y R maximos.
         Cont_L=2;
         Porcentaje_R--;
         if(Porcentaje_R==0xFF)
            Porcentaje_R=0;
     }
}

Volumen_L=AsignarVolumen(VolumenBarraLCD,Porcentaje_L);

Volumen_R=AsignarVolumen(VolumenBarraLCD,Porcentaje_R);

write_ext_eeprom(72,Porcentaje_L);
write_ext_eeprom(74,Porcentaje_R);

ActualizarVolumen();

MostrarBalance(Porcentaje_L,Porcentaje_R);
}
//****************************************************************************//
//Lee de la EEPROM los códigos de mando que se hayan memorizado               //
//****************************************************************************//
void LeerCodigosMando(void){

TeclaIncVol=read_ext_eeprom(2);

TeclaDecVol=read_ext_eeprom(4);

TeclaIncCanal=read_ext_eeprom(6);

TeclaDecCanal=read_ext_eeprom(8);

TeclaBal_L=read_ext_eeprom(10);

TeclaBal_R=read_ext_eeprom(12);

TeclaMute=read_ext_eeprom(14);

TeclaC1=read_ext_eeprom(16);

TeclaC2=read_ext_eeprom(18);

TeclaC3=read_ext_eeprom(20);

TeclaC4=read_ext_eeprom(22);

TeclaC5=read_ext_eeprom(24);

TeclaC6=read_ext_eeprom(26);


}
//****************************************************************************//
//Guarda en la EEPROM el nombre de cada canal.                                //
//****************************************************************************//
void GuardarNombreCanal(int CanalSel,int a,int b,int c,int d){
write_ext_eeprom(CanalSel*4+40,a);
write_ext_eeprom(CanalSel*4+41,b);
write_ext_eeprom(CanalSel*4+42,c);
write_ext_eeprom(CanalSel*4+43,d);
}
//****************************************************************************//
void LeerNombreCanal(void){
int i;
for(i=0;i<4;i++){
Cn_1[i]=read_ext_eeprom(40+i);
Cn_2[i]=read_ext_eeprom(44+i);
Cn_3[i]=read_ext_eeprom(48+i);
Cn_4[i]=read_ext_eeprom(52+i);
Cn_5[i]=read_ext_eeprom(56+i);
Cn_6[i]=read_ext_eeprom(60+i);
}
}
//****************************************************************************//
void GuardarCanal(CanalSel){
write_ext_eeprom(70,CanalSel);
}
//****************************************************************************//
void LeerCanal(void){
CanalSel=read_ext_eeprom(70);
}
//****************************************************************************//
void LeerBalance(void){

Porcentaje_L=read_ext_eeprom(72);
Porcentaje_R=read_ext_eeprom(74);
}
//****************************************************************************//
void LeerVolumen(int CanalSel){
switch (CanalSel) {
   case   0x00: VolumenBarraLCD=read_ext_eeprom(76);
      Break;
   case   0x01: VolumenBarraLCD=read_ext_eeprom(78);
      Break;
   case   0x02: VolumenBarraLCD=read_ext_eeprom(80);
      Break;
   case   0x03: VolumenBarraLCD=read_ext_eeprom(82);
      Break;
   case   0x04: VolumenBarraLCD=read_ext_eeprom(84);
      Break;
   case   0x05: VolumenBarraLCD=read_ext_eeprom(86);
      Break;
}
}
//****************************************************************************//
//Reproduce un pitido corto de 200msg.                                        //
//****************************************************************************//
void PitidoCorto(void){
int i;
for(i=0;i<200;i++){
   ZUMBADOR=ON;
   delay_us(500);
   ZUMBADOR=OFF;
   delay_us(500);
}
}
//****************************************************************************//
//Reproduce un pitido corto de 600msg.                                        //
//****************************************************************************//
void PitidoLargo(void){
long i;
for(i=0;i<600;i++){
   ZUMBADOR=ON;
   delay_us(500);
   ZUMBADOR=OFF;
   delay_us(500);
}
}
//****************************************************************************//
//Graba las cinco teclas: Subir volumen, bajar volumen, seleccion del canal,  //
//balance L, balance R.                                                       //
//****************************************************************************//
void AlmacenaTecla(void){
int cont;
if(EstadoProceso%2==1){//Paso impar.
   //Captura de tecla.
   LecturaTemporal[0]=data[0];
   EstadoProceso++;
   PitidoCorto();//Indica tecla leida.
}else{//Paso par.
   //Comprobacion de tecla.
   if(LecturaTemporal[0]==data[0]){
   //Tecla correcta.
   Direccion=EstadoProceso;//Guarda en direcciones pares
   write_ext_eeprom(Direccion,data[0]);
   EstadoProceso++;
   PitidoLargo();//Indica tecla almacenada correctamente.
   }else{//Comprobacion fallida.
   EstadoProceso--;
   LecturaTemporal[0]=0;
   for(cont=0;cont<4;cont++){//Indica fallo de lectura, se repite esa tecla.
       PitidoCorto();
       Delay_ms(200);
   }
   }
}
if( EstadoProceso== (N_TECLAS*2+1) ){//13 teclas grabadas correctamente.
      LeerCodigosMando();
      EstadoProceso=1;
      for(cont=0;cont<4;cont++){//Indica fin de teclas almacenadas.
         PitidoLargo();
         Delay_ms(200);
      }
      Delay_ms(4000);
}
}
/******************************************************************************/
/*Envia el numero del canal por un canal de un hilo al pic receptor encargado */
/*de conmutar el rele del canal seleccionado.                                 */
/******************************************************************************/
void ConmutarCanal(void){
int dato, i;

output_bit(SALIDA_CANAL_SEL,0);//iniciamos bit de arranque a '0'.
Delay_ms(4);
dato=CanalSel;
for(i=0;i<=7;i++){//Envia el numero de canal (8bit), almacenado en 'CanalSel'.
     output_bit(SALIDA_CANAL_SEL,shift_right(&dato,1,0));
     delay_ms(4);
}
output_bit(SALIDA_CANAL_SEL,1);//Ponemos salida en reposo '1'.
Delay_ms(8);
}
/******************************************************************************/
/*Hace la primera conmutacion, la del encendido, subiendo el volumen despacio.*/
/******************************************************************************/
void SubirVolumenSuave(void){
ConmutarCanal();
While(VolumenBarraLCD_Temp!=VolumenBarraLCD){
      VolumenBarraLCD_Temp++;
      MostrarBarraVolumenLCD(VolumenBarraLCD_Temp);
      Volumen_L=AsignarVolumen(VolumenBarraLCD_Temp,Porcentaje_L);
      Volumen_R=AsignarVolumen(VolumenBarraLCD_Temp,Porcentaje_R);
      ActualizarVolumen();
      Delay_ms(4);
}
}
/******************************************************************************/
/*Actualiza el canal bajando el volumen del canal anterior a cero, y sube el  */
/*del nuevo canal progresivamente.                                            */
/******************************************************************************/
void ActualizarCanal(void){

MostrarCanal(CanalSel);
GuardarCanal(CanalSel);
LeerVolumen(CanalSel);//Guarda en 'VolumenBarraLCD' el volumen del canal actual.
while(VolumenBarraLCD_Temp!=0){//VolumenBarraLCD_Temp guarda el vol. anterior.
      VolumenBarraLCD_Temp--;
      MostrarBarraVolumenLCD(VolumenBarraLCD_Temp);
      Volumen_L=AsignarVolumen(VolumenBarraLCD_Temp,Porcentaje_L);
      Volumen_R=AsignarVolumen(VolumenBarraLCD_Temp,Porcentaje_R);
      ActualizarVolumen();
      Delay_ms(4);
}
ConmutarCanal();
While(VolumenBarraLCD_Temp!=VolumenBarraLCD){
      VolumenBarraLCD_Temp++;
      MostrarBarraVolumenLCD(VolumenBarraLCD_Temp);
      Volumen_L=AsignarVolumen(VolumenBarraLCD_Temp,Porcentaje_L);
      Volumen_R=AsignarVolumen(VolumenBarraLCD_Temp,Porcentaje_R);
      ActualizarVolumen();
      Delay_ms(4);
}
}
//****************************************************************************//
//Procesa las pulsaciones de las teclas del mando.                            //
//****************************************************************************//
void ProcesaTecla(void){

if(data[0]==TeclaIncVol){
      IncrementaVolumen();
      Menu=VOLUMEN;
      //lcd_gotoxy(1,1);//fila 1, col 1
      //printf(lcd_putc,"%03u %03u %03u %03u",Volumen_L,Volumen_R,Porcentaje_L,Porcentaje_R);
}
if(data[0]==TeclaDecVol){
      DecrementaVolumen();
      Menu=VOLUMEN;
      //lcd_gotoxy(1,1);//fila 1, col 1
      //printf(lcd_putc,"%03u %03u %03u %03u",Volumen_L,Volumen_R,Porcentaje_L,Porcentaje_R);
}
if(data[0]==TeclaBal_L){
      BalanceL();
      Menu=BALANCE;
      //lcd_gotoxy(1,1);//fila 1, col 1
      //printf(lcd_putc,"%03u %03u %03u %03u",Volumen_L,Volumen_R,Porcentaje_L,Porcentaje_R);
}
if(data[0]==TeclaBal_R){
      BalanceR();
      Menu=BALANCE;
      //lcd_gotoxy(1,1);//fila 1, col 1
      //printf(lcd_putc,"%03u %03u %03u %03u",Volumen_L,Volumen_R,Porcentaje_L,Porcentaje_R);
}
if(data[0]==TeclaC1){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel=0;
      ActualizarCanal();
}
if(data[0]==TeclaC2){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel=1;
      ActualizarCanal();
}
if(data[0]==TeclaC3){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel=2;
      ActualizarCanal();
}
if(data[0]==TeclaC4){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel=3;
      ActualizarCanal();
}
if(data[0]==TeclaC5){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel=4;
      ActualizarCanal();
}
if(data[0]==TeclaC6){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel=5;
      ActualizarCanal();
}
if(data[0]==TeclaIncCanal){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel++;
      if(CanalSel>=N_CANAL)
         CanalSel=0;
      ActualizarCanal();
}
if(data[0]==TeclaDecCanal){
      Menu=CANAL;
      VolumenBarraLCD_Temp=VolumenBarraLCD;
      CanalSel--;
      if(CanalSel==0xFF)
         CanalSel=N_CANAL-1;
      ActualizarCanal();
}
if(data[0]==TeclaMute){
      if(Mute){
         VolAux=VolumenBarraLCD;
         VolumenBarraLCD=0;
         Mute=FALSE;
         lcd_gotoxy(1,2);
         printf(lcd_putc,"      MUTE      ");
      }
      else{
         VolumenBarraLCD=VolAux;
         Mute=TRUE;
         LeerVolumen(CanalSel);
         MostrarBarraVolumenLCD(VolumenBarraLCD);
      }
}
TiempoLCD=0;
enable_interrupts(INT_TIMER0);
}
/******************************************************************************/
/* Interrupción por cambio en RB4-RB7 para leer el encoder.                   */
/******************************************************************************/
#int_rb
void detect_rb_change() {
int current;
static int last=0;

#asm movf PORTB,0 //Sin estas instrucciones no funciona bien.
     movwf current
#endasm
//current=*PORTB;
// Canal A = PORTB.5
// Canal B = PORTB.4
if ((bit_test(current,4)) && (bit_test(current,5))){
   if ((bit_test(last,4)) ^ (bit_test(current,5))){
      //sentido agujas del reloj, incrementar.
      IncDec=INCREMENTAR;
   }
   else{
        //sentido contrario agujas del reloj, decrementar.
        IncDec=DECREMENTAR;
   }
}
last=current;
TiempoLCD=0;
enable_interrupts(INT_TIMER0);
}
//****************************************************************************//
#INT_EXT
void MandoDistancia(){
// Sin este trozo de programa va igual
/*
while( i++ != 4)
{                                  // Test si REC_IR au repos prolongé
if(REC_IR == 0) i=0;
delay_us (889);      }
*/
//while(input(REC_IR)==1);    // Espera al 1er bit de START (flanco de bajada)
delay_us(444);                // Se posiciona en el medio
while((nbit++ != 13) && (state == 0)){
   // 2º bit de START + 1 bit TOGGLE + 5 bits DIR + 6 bits COMANDO
   // nbit varía de 0 a 12 = 13 bits
   delay_us (889);// Mide en el primer semiperiodo del bit, para que invierta
   //el código y dé el original RC5 del emisor.
   if(input(REC_IR)==0){
        delay_us (889);
        if(input(REC_IR) != 1)
            state=1;
        bit=0;    // Es un 0
   }else{
         delay_us(889);
         if (input(REC_IR) != 0)
               state=1;
         bit=1;   // Es un 1
   }
   shift_left(data,2,bit);// data=data[0], 2·8=16bits, bit=0 ó 1
}
   if(state){
         //Error.
         //PitidoCorto();
         /*lcd_gotoxy(1,1);//fila 1, col 1
         printf(lcd_putc,"Error           ");*/
         Delay_cycles(1);
   }else{//Dato correcto.
         if(!GRABAR)
            AlmacenaTecla();
         else
            ProcesaTecla();
   }
data[0]=0;
data[1]=0;
state=0;
nbit=0;

Delay_ms(200);
}
//****************************************************************************//
#INT_TIMER0
void tempo(){
set_timer0(Periodo);
TiempoLCD++;
}
//****************************************************************************//
void AsignacionesPrimeraEjecucion(void){
int Testigo;
Testigo=read_ext_eeprom(101);
if(Testigo!=0x44){
     Porcentaje_L=80;
     Porcentaje_R=80;
     CanalSel=0;
     write_ext_eeprom(76,0);
     write_ext_eeprom(78,0);
     write_ext_eeprom(80,0);
     write_ext_eeprom(82,0);
     write_ext_eeprom(84,0);
     write_ext_eeprom(86,0);
     VolumenBarraLCD=0;
     write_ext_eeprom(101,0x44);
}
}
//****************************************************************************//
//****************************************************************************//
void main()
{

disable_interrupts(GLOBAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);
//setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
//setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(FALSE);
enable_interrupts(INT_RB);
enable_interrupts(INT_EXT);
ext_int_edge(H_TO_L);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);

output_bit(SALIDA_CANAL_SEL,1);//Ponemos salida datos serie en reposo '1'.

lcd_init();

set_tris_a(0b11000011);
set_tris_b(0b00110101);
set_tris_c(0b00011100);

init_ext_eeprom();

ZUMBADOR=OFF;
LeerBalance();
LeerCanal();
LeerVolumen(CanalSel);
LeerNombreCanal();
VolumenBarraLCD_Temp=0;
SubirVolumenSuave();

AsignacionesPrimeraEjecucion();
Volumen_L=AsignarVolumen(VolumenBarraLCD,Porcentaje_L);
Volumen_R=AsignarVolumen(VolumenBarraLCD,Porcentaje_R);

LeerCodigosMando();
GuardaCaracteresLCD();
EstadoProceso=1;

Cont_R=0;
Cont_L=0;

SelectMenu=0;
TiempoLCD=0;

Mute=FALSE;

MostrarCanal(CanalSel);
MostrarBarraVolumenLCD(VolumenBarraLCD);

data[0]=0;
data[1]=0;
state=0;
nbit=0;

while(1){

if(!PULSADOR && GRABAR){//Procesamos menu encoder.
   enable_interrupts(INT_TIMER0);
   TiempoLCD=0;

   switch (SelectMenu) {
   case    VOLUMEN: {Menu=VOLUMEN;
                    lcd_gotoxy(1,1);
                    printf(lcd_putc," VOLUMEN:       ");
                    MostrarBarraVolumenLCD(VolumenBarraLCD);}
      Break;
   case    BALANCE: {Menu=BALANCE;
                     MostrarBalance(Porcentaje_L,Porcentaje_R);}
      Break;
   case      CANAL: {Menu=CANAL;
                     MostrarCanal(CanalSel);
                     lcd_gotoxy(1,2);
                     printf(lcd_putc,"                ");//limpiar pantalla
                     }
      Break;
   }
   SelectMenu++;
   if(SelectMenu>2)
       SelectMenu=0;
   Delay_ms(400);
}

if(IncDec==INCREMENTAR && GRABAR){//Procesamos giro derecha.
      switch (Menu) {
   case    VOLUMEN: IncrementaVolumen();
      Break;
   case    BALANCE: BalanceL();
      Break;
   case      CANAL: {VolumenBarraLCD_Temp=VolumenBarraLCD;
                     CanalSel++;
                     if(CanalSel>=N_CANAL)
                           CanalSel=0;
                     ActualizarCanal();
                     }
      Break;
   }
   IncDec=2;
}

if(IncDec==DECREMENTAR && GRABAR){//Procesamos giro izquierda.
        switch (Menu) {
   case    VOLUMEN: DecrementaVolumen();
      Break;
   case    BALANCE: BalanceR();
      Break;
   case      CANAL: {VolumenBarraLCD_Temp=VolumenBarraLCD;
                     CanalSel--;
                     if(CanalSel==0xFF)
                           CanalSel=N_CANAL-1;
                     ActualizarCanal();
                     }
      Break;
   }
   IncDec=2;
}

if(TiempoLCD>=FIN){
      Disable_interrupts(INT_TIMER0);
      TiempoLCD=0;
      MostrarCanal(CanalSel);
      if(!Mute){//El mute está activo.
         lcd_gotoxy(1,2);
         printf(lcd_putc,"      MUTE      ");
      }else{
      MostrarBarraVolumenLCD(VolumenBarraLCD);
      }
}

if(!PULSADOR && !GRABAR){//Grabamos los nombres de los canales de entrada.

while(!PULSADOR);//Se espera a dejar de pulsar el encoder.
lcd_gotoxy(1,1);
printf(lcd_putc," Canal 1:       ");
NombreCanal=0;
delay_ms(400);
while(PULSADOR){//al pulsar el boton del encoder se sale.
   if(IncDec==INCREMENTAR){
      NombreCanal++;
      if(NombreCanal>=N_NOMBRES)
         NombreCanal=N_NOMBRES-1;
      AsignarNombreCanal(NombreCanal);
      Cn_1[0]=a;Cn_1[1]=b;Cn_1[2]=c;Cn_1[3]=d;
      IncDec=2;
   }
   if(IncDec==DECREMENTAR){
      NombreCanal--;
      if(NombreCanal==0xFF)
         NombreCanal=0;
      AsignarNombreCanal(NombreCanal);
      Cn_1[0]=a;Cn_1[1]=b;Cn_1[2]=c;Cn_1[3]=d;
      IncDec=2;
   }
}
GuardarNombreCanal(0,Cn_1[0],Cn_1[1],Cn_1[2],Cn_1[3]);//Se guarda el nombre
                                                      //del canal 1 (0).
//----------------------------------------------------------------------------//
while(!PULSADOR);//Se espera a dejar de pulsar el encoder.
lcd_gotoxy(1,1);
printf(lcd_putc," Canal 2:       ");
NombreCanal=0;
delay_ms(400);
while(PULSADOR){//al pulsar el boton del encoder se sale.
   if(IncDec==INCREMENTAR){
      NombreCanal++;
      if(NombreCanal>=N_NOMBRES)
         NombreCanal=N_NOMBRES-1;
      AsignarNombreCanal(NombreCanal);
      Cn_2[0]=a;Cn_2[1]=b;Cn_2[2]=c;Cn_2[3]=d;
      IncDec=2;
   }
   if(IncDec==DECREMENTAR){
      NombreCanal--;
      if(NombreCanal==0xFF)
         NombreCanal=0;
      AsignarNombreCanal(NombreCanal);
      Cn_2[0]=a;Cn_2[1]=b;Cn_2[2]=c;Cn_2[3]=d;
      IncDec=2;
   }
}
GuardarNombreCanal(1,Cn_2[0],Cn_2[1],Cn_2[2],Cn_2[3]);//Se guarda el nombre
                                                      //del canal 2 (1).
//----------------------------------------------------------------------------//
while(!PULSADOR);//Se espera a dejar de pulsar el encoder.
lcd_gotoxy(1,1);
printf(lcd_putc," Canal 3:       ");
NombreCanal=0;
delay_ms(400);
while(PULSADOR){//al pulsar el boton del encoder se sale.
   if(IncDec==INCREMENTAR){
      NombreCanal++;
      if(NombreCanal>=N_NOMBRES)
         NombreCanal=N_NOMBRES-1;
      AsignarNombreCanal(NombreCanal);
      Cn_3[0]=a;Cn_3[1]=b;Cn_3[2]=c;Cn_3[3]=d;
      IncDec=2;
   }
   if(IncDec==DECREMENTAR){
      NombreCanal--;
      if(NombreCanal==0xFF)
         NombreCanal=0;
      AsignarNombreCanal(NombreCanal);
      Cn_3[0]=a;Cn_3[1]=b;Cn_3[2]=c;Cn_3[3]=d;
      IncDec=2;
   }
}
GuardarNombreCanal(2,Cn_3[0],Cn_3[1],Cn_3[2],Cn_3[3]);//Se guarda el nombre
                                                      //del canal 3 (2).
//----------------------------------------------------------------------------//
while(!PULSADOR);//Se espera a dejar de pulsar el encoder.
lcd_gotoxy(1,1);
printf(lcd_putc," Canal 4:       ");
NombreCanal=0;
delay_ms(400);
while(PULSADOR){//al pulsar el boton del encoder se sale.
   if(IncDec==INCREMENTAR){
      NombreCanal++;
      if(NombreCanal>=N_NOMBRES)
         NombreCanal=N_NOMBRES-1;
      AsignarNombreCanal(NombreCanal);
      Cn_4[0]=a;Cn_4[1]=b;Cn_4[2]=c;Cn_4[3]=d;
      IncDec=2;
   }
   if(IncDec==DECREMENTAR){
      NombreCanal--;
      if(NombreCanal==0xFF)
         NombreCanal=0;
      AsignarNombreCanal(NombreCanal);
      Cn_4[0]=a;Cn_4[1]=b;Cn_4[2]=c;Cn_4[3]=d;
      IncDec=2;
   }
}
GuardarNombreCanal(3,Cn_4[0],Cn_4[1],Cn_4[2],Cn_4[3]);//Se guarda el nombre
                                                      //del canal 4 (3).
//----------------------------------------------------------------------------//
while(!PULSADOR);//Se espera a dejar de pulsar el encoder.
lcd_gotoxy(1,1);
printf(lcd_putc," Canal 5:       ");
NombreCanal=0;
delay_ms(400);
while(PULSADOR){//al pulsar el boton del encoder se sale.
   if(IncDec==INCREMENTAR){
      NombreCanal++;
      if(NombreCanal>=N_NOMBRES)
         NombreCanal=N_NOMBRES-1;
      AsignarNombreCanal(NombreCanal);
      Cn_5[0]=a;Cn_5[1]=b;Cn_5[2]=c;Cn_5[3]=d;
      IncDec=2;
   }
   if(IncDec==DECREMENTAR){
      NombreCanal--;
      if(NombreCanal==0xFF)
         NombreCanal=0;
      AsignarNombreCanal(NombreCanal);
      Cn_5[0]=a;Cn_5[1]=b;Cn_5[2]=c;Cn_5[3]=d;
      IncDec=2;
   }
}
GuardarNombreCanal(4,Cn_5[0],Cn_5[1],Cn_5[2],Cn_5[3]);//Se guarda el nombre
                                                      //del canal 5 (4).
//----------------------------------------------------------------------------//
while(!PULSADOR);//Se espera a dejar de pulsar el encoder.
lcd_gotoxy(1,1);
printf(lcd_putc," Canal 6:       ");
NombreCanal=0;
delay_ms(400);
while(PULSADOR){//al pulsar el boton del encoder se sale.
   if(IncDec==INCREMENTAR){
      NombreCanal++;
      if(NombreCanal>=N_NOMBRES)
         NombreCanal=N_NOMBRES-1;
      AsignarNombreCanal(NombreCanal);
      Cn_6[0]=a;Cn_6[1]=b;Cn_6[2]=c;Cn_6[3]=d;
      IncDec=2;
   }
   if(IncDec==DECREMENTAR){
      NombreCanal--;
      if(NombreCanal==0xFF)
         NombreCanal=0;
      AsignarNombreCanal(NombreCanal);
      Cn_6[0]=a;Cn_6[1]=b;Cn_6[2]=c;Cn_6[3]=d;
      IncDec=2;
   }
}
delay_ms(400);
GuardarNombreCanal(5,Cn_6[0],Cn_6[1],Cn_6[2],Cn_6[3]);//Se guarda el nombre
                                                      //del canal 6 (5).
//----------------------------------------------------------------------------//
{int cont;
for(cont=0;cont<4;cont++){//Indica fin de nombres almacenados.
         PitidoLargo();
         Delay_ms(200);
   }
}
}
}
}
//****************************************************************************//
