TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: micro_pepe en 30 de Marzo de 2009, 16:05:18
-
No se si este codigo es correcto, creo que si pero no me funciona.
Se trata de leer un mando a distancia JVC, el protocolo es este: http://www.sbprojects.com/knowledge/ir/jvc.htm
Y mi programa es este:
#include <16F84A.h>
#use delay(clock=4000000)
#fuses XT,NOWDT,NOPROTECT
#byte PORTA = 0x05
#byte PORTB = 0x06
#bit GRABAR = PORTA.0
#bit LED = PORTA.1
#define REC_IR PIN_B0
#bit SALIDA_1 = PORTB.1
#bit SALIDA_2 = PORTB.2
#bit SALIDA_3 = PORTB.3
#bit SALIDA_4 = PORTB.4
#define ON 1
#define OFF 0
#define N_TECLAS 4
int1 bit;
int i, nbit,data[3],state;
int EstadoProceso;
int LecturaTemporal[3];
//****************************************************************************//
void AlmacenaTecla(void){
int cont,Direccion;
restart_wdt();
if(EstadoProceso%2==1){//Paso impar.
//Captura de tecla.
LecturaTemporal[0]=data[0];
LecturaTemporal[1]=data[1];
LecturaTemporal[2]=data[2];
EstadoProceso++;
PitidoCorto();//Indica tecla leida.Da un destello corto a un led
}else{//Paso par.
//Comprobacion de tecla.
if((LecturaTemporal[0]==data[0])&&
(LecturaTemporal[1]==data[1])&&
(LecturaTemporal[2]==data[2])){
//Tecla correcta.
Direccion=EstadoProceso*2-4;
write_eeprom(Direccion,data[0]);
write_eeprom(Direccion+1,data[1]);
write_eeprom(Direccion+2,data[2]);
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();//Da un destello corto a un led
Delay_ms(200);
}
}
}
if( EstadoProceso== (N_TECLAS*2+1) ){//teclas grabadas correctamente.
LeerCodigosMando();
EstadoProceso=1;
for(cont=0;cont<4;cont++){//Indica fin de teclas almacenadas.
PitidoLargo();//Da un destello largo a un led
Delay_ms(200);
}
Delay_ms(400);
}
}
//****************************************************************************//
void main(){
set_tris_a(0b11111101);
set_tris_b(0b11100001);
EstadoProceso=1;
while(1){
data[0]=0;
data[1]=0;
data[2]=0;
state=0;
nbit=0;
i=0;
while(input(REC_IR)==1); // Espera al 1er bit de START (flanco de bajada)
delay_us(8400);//Saltamos el
delay_us(4200);//bit de inicio.
delay_us(263);//Nos situamos a la mitad del primer nivel del primer bit.
while((nbit++ != 16) && (state == 0)){
// 8 bits DIR + 8 bits COMANDO.
// nbit varía de 0 a 15 = 16 bits
if(input(REC_IR)==0){//Todos los bit empizan por 0 (invertido).
delay_us (526);//Sobrepasamos la mitad del primer nivel.
if(input(REC_IR) != 1)//Si no es un 1, no es codigo Samsumg.
state=1;
delay_us (526);//Si sigue siendo un 1, es un 1, sino es un 0.
if(input(REC_IR)==0){
bit=0;//Es un cero.
}else{
bit=1;//Es un uno
delay_us(1048);//Sobrepasamos el nivel alto (invertido) del 1.
if(input(REC_IR) != 0)
state=1;
}
}else{
state=1;//No es codigo JVC.
}
shift_left(data,2,bit);// 2·8=16bits, bit=0 ó 1
}
if(state){//Error.
/*lcd_gotoxy(1,1);//fila 1, col 1
printf(lcd_putc,"Error ");*/
}else{//Dato correcto.
if(!GRABAR)//Jumper de programacion de teclas.
AlmacenaTecla();
else
ProcesaTecla();
}
Delay_ms(200);
}
}
Al pulsar una tecla del mando, el led deberia dar un destello, pero no lo hace. Con el codigo de PHILIPS RC5 hice un programa similar y funcionaba, la funcion Almacenatecla es la misma.
-
La parte que lee la trama de datos es esta:
while(input(REC_IR)==1); // Espera al 1er bit de START (flanco de bajada)
delay_us(8400);//Saltamos el
delay_us(4200);//bit de inicio.
delay_us(263);//Nos situamos a la mitad del primer nivel del primer bit.
while((nbit++ != 16) && (state == 0)){
// 8 bits DIR + 8 bits COMANDO.
// nbit varía de 0 a 15 = 16 bits
if(input(REC_IR)==0){//Todos los bit empizan por 0 (invertido).
delay_us (526);//Sobrepasamos la mitad del primer nivel.
if(input(REC_IR) != 1)//Si no es un 1, no es codigo Samsumg.
state=1;
delay_us (526);//Si sigue siendo un 1, es un 1, sino es un 0.
if(input(REC_IR)==0){
bit=0;//Es un cero.
}else{
bit=1;//Es un uno
delay_us(1048);//Sobrepasamos el nivel alto (invertido) del 1.
if(input(REC_IR) != 0)
state=1;
}
}else{
state=1;//No es codigo JVC.
}
shift_left(data,2,bit);// 2·8=16bits, bit=0 ó 1
}
Sucede que si acorto el numero de bits a 10, me funciona el programa con algunas teclas del mando.
No encuentro forma de ver la trama que me envia el mando, en el osciloscopio analogico que tengo no se ve bien, y no tengo un analizador logico.
Estoy usando un mando universal, quizas la trama no sea igual a la original...
Un saludo.
-
Yo no lo haría con delays, porque si la tabla de tiempos no coincide exactamente, vas arrastrando error bit tras bit y puede que al final te encuentres con algún problema.
Creo que lo ideal es utilizar la interrupción externa en combinación con el timer para saber el tiempo que transcurre entre un flanco ascendente y el siguiente (o descendente, si tu receptor es de lógica inversa).
De esta manera, el bit de start será identificado porque el siguiente flanco llegará después de 12,6ms; el bit 0 después de 1,05ms y el bit 1 después de 2,1ms por lo que el código de tu interrupción externa quedaría sencillito:
if (TiempoTranscurrido<1200) // se ha recibido un 0
Trama<<1;
else if (TiempoTranscurrido<3000) // se ha recibido un 1
Trama=Trama<<1 + 1;
else Trama=0; // comienzo de recepción
-
Efectivamente es un problema de retardos arrastrados. He probado a reducir un poco los delay, y funciona correctamente, pero tengo que probar de la manera que me has comentado, es mucho mejor.
Muchas gracias por la ayuda Nocturno. Cuando tenga funcionando con la interrupcion lo comento.
Un saludo.
-
Codigo de Nocturno funcionando :-/ :-/
La rutina de interrupción queda así:
#INT_EXT
void Leer_Trama(void){
TiempoTranscurrido=GET_TIMER0();
SET_TIMER0(0x00);
if (TiempoTranscurrido<TIEMPO_CERO) // se ha recibido un 0
shift_left(data,2,0);
else if (TiempoTranscurrido<TIEMPO_UNO) // se ha recibido un 1
shift_left(data,2,1);
else { data[0]=0;data[1]=0;data[2]=0; } // comienzo de recepción
cont++;
}
Y la parte de codigo para saber cuando terminamos de leer:
while(input(REC_IR)==1);
cont=0;
SET_TIMER0(0x00);
enable_interrupts(INT_EXT);
ext_int_edge(H_TO_L);
enable_interrupts(GLOBAL);
while(cont!=N_BIT+1);
disable_interrupts(GLOBAL);
Un saludo.
-
!Guay!
-
Ahora trato de hacer lo mismo con el protocolo RC5 de PHILIPS, es decir por interrupcion. Es diferente porque los bit '0' o '1' tienen la misma duracion:
http://www.sbprojects.com/knowledge/ir/rc5.htm
Tengo la siguiente interrupcion para leer una trama del mando:
//****************************************************************************//
#INT_EXT
void Leer_Trama(void){
int bit;
TiempoTranscurrido=GET_TIMER1();
SET_TIMER1(0x0000);
if(TiempoTranscurrido<MEDIO_BIT){
FlancoParImpar++;
if(FlancoParImpar%2==0){//Si el tiempo es de medio bit, tenemos dos '0'o
//dos '1' seguidos, se salta el primer flanco para situarse en medio del
//bit para poder determinar si es un '0' o un '1'.
if(FlancoSubidaBajada==Subida)//es un cero(invertido por receptor IR)
bit=0;
else
bit=1;
shift_left(data,2,bit);
ContadorBitsLeidos++;
}
}else if(TiempoTranscurrido<UN_BIT){
if(FlancoSubidaBajada==Subida)//es un cero(invertido por receptor IR)
bit=0;
else
bit=1;
shift_left(data,2,bit);
ContadorBitsLeidos++;
}
if(FlancoSubidaBajada==Subida){
FlancoSubidaBajada=Bajada;
ext_int_edge(H_TO_L);
}else{
FlancoSubidaBajada=Subida;
ext_int_edge(L_TO_H);
}
}
//****************************************************************************//
Y la inicializacion del main:
void main(){
set_tris_a(0b11111101);
set_tris_b(0b11100001);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);
SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_1);
EstadoProceso=1;
LED=OFF;
LeerCodigosMando();
while(1){
while(input(REC_IR)==1);
cont=0;
data[0]=0;data[1]=0;data[2]=0;
FlancoParImpar=2;//inicio en par.
SET_TIMER1(0x0000);
FlancoSubidaBajada=Subida;
enable_interrupts(INT_EXT);
ext_int_edge(L_TO_H);
enable_interrupts(GLOBAL);
ContadorBitsLeidos=0;
while(contadorBitsLeidos!=N_BIT);
disable_interrupts(GLOBAL);
data[1]=data[1]&0b00000111;//Se ignoran bits de inicializacion.
if(!GRABAR)
AlmacenaTecla();
else
ProcesaTecla();
}
}
Para grabar una tecla hago dos lecturas de la tecla pulsada, osea se pasa dos veces por la funcion AlmacenaTecla();, la primera pasada la hace, pero en la segunda me da una lectura erronea. He dado mil vueltas pero no encuentro el error. Sospecho que el error está en el codigo que he puesto, pues el resto del codigo funciona con la lectura inicial que usaba con delays en lugar de con interrupciones.
Un saludo.
-
HOLA micro pepe estoy investigando sobre controles jvc podrias colocar el codigo completo del JVC para poderlo estudiar
gracias