Recibir Señal con un receptor de infrarojos

Hola tengo un TSOP de 38KHz y quería abrir y cerrar un relé cuando el receptor recibiera de un mando universal. He visto algo de información en la cual estudiando el protocolo de cada mando NEC,RC5,etc. reconociera qué tecla se estaba pulsando. Lo mío creo que es más sencillo, simplemente en el caso de mi mando que es un philips, miraría el protocolo del mando, escogería una tecla cualquiera para abrir el relé y el receptor sólo cuando recibiera esa señal actuara. Ésto queria hacerlo siguiendo estas pautas:

1.Recibir en el arduino con el sensor las señales del mando. 2.Decodificar la señal en 1's y 0's ya que viene en hexadecimal no? 3.Hacer un IF de modo que SI la señal es la tecla deseada ENTONCES abre el relé.

No sé si me expliqué muy bien espero que si. Lo que quería eran vuestras opiniones y consejos sobre como debería hacerlo y sobre todo ayuda con el código en el punto 1 y 2.

Muchas gracias y un saludo.

Hola, te buscaré una página donde aparece todo esto. Saludos

Hola, El link es el siguiente http://www.5volt.eu/archives/14 Espero que con esto puedas hacer lo que pretendes. Ya nos contarás que tal

muchas gracias, creo que es más o menos lo que andaba buscando.
Haber si lo pruebo hoy de noche y os cuento.
Un saludo!

Ya lo he hecho y funciona a la perfección, haber si mañana tengo tiempo y cuelgo unas fotos o unos vídeos si es que a alguien le interesa.

Saludos.

Por supuesto que nos interesa...

Postea fotos y videos, pero sobre todo, documenta los componentes usados, el software, etc..

Saludos, Pakoff

Hola, ¿Has logrado abrir y cerrar el relé con la misma tecla? Es decir, si con la tecla "uno" lo accionas, pulsando otra vez la misma tecla (la uno) vuelve al estado inicial. Yo lo estoy intentando, pero no me funciona. Sería interesante, que colgases la parte de programa que has añadido a la inicialmente del control del mando de infrarojo. Saludos.

Vale Pakoff haber si lo documento un poco entonces cuando tenga tiempo.

Soleares en principio lo hago con 2 teclas pero no creo que sea muy latoso hacer lo que dices no? Así de primeras (aunque habrá mil formas mas sencillas de hacerlo pero tiendo a complicar las cosas) se me ocurre por ejemplo lo siguiente:

Imaginemos que el Relé es normalmente cerrado, ahora bien declaramos una variable de tipo entero que le vamos a llamar "caca" por ejemplo y la inicializamos a 0. Si el relé se abre con la tecla "1" del mando la primera vez que lo pulsemos el relé se abrirá y aumentaremos una unidad la variable, es decir "Caca = Caca + 1" y así sucesivamente de modo que el relé estará abierto cuando "caca = impar" y cerrado cuando "caca = par" de modo que haciendo un IF y haciendo "Caca%2" si el resto nos da "0" el relé estará cerrado y mandaremos abrirlo y viceversa.

Me he explicado bien? sino intento explicarlo mejor o directamente lo escribo en código pero a mi a veces me resulta más comodo pensar así las cosas.

Un saludo y ya me contarás.

Hola Outl4w, He entendido bien tu ejemplo. Lo tengo que probar. En principio debería de funcionar, pero es que he probado otros métodos que también deberían de funcionar y no lo hace. Por ejemplo, no funciona código que contenga "delay" El ejemplo siguiente tampoco funciona:

case 0x01: { if (valverde==LOW) valverde=HIGH; else valverde=LOW; digitalWrite(verde,valverde); } break;

Se trataba de encender y apagar un led con la misma tecla, y hacemos que la variable vaya cambiando cada vez que se pulsa la tecla "1". Pues no funciona :'( Creo que el problema es que el programa utiliza interrupciones y no da tiempo a que se ejecute todo la subrutina que introducimos en los "case". Mi intención es controlar una placa de relés con el mando a distancia para comandar todo tipo de instalaciones a 220v, pero quiero controlar con la misma tecla el encendido y apagado del relé en cuestión, para no tener que recordar que activo el relé uno con la tecla "1" y lo desactivo con la tecla "6". Espero que seamos capaces de solucionar este "problema". :D Un saludo

SOLEARES....

prueba con algo parecido a esto:

case 0x01: { valverde = !valverde; digitalWrite(verde,valverde); break; }

el "break" ponlo siempre al final de cada "case" para que se salte el resto de opciones (una vez encuentre la adecuada)

Un Saludo.

Gracias Imagina, pero eso es el primer código que probé y no funciona. Cuando pulsamos por vez primera el "1", nos enciende el led, puesto que la variable valverde inicialmente está en LOW, pero cuando pulsas de nuevo la tecla "1", ya no hace nada, es decir, se queda la variable en HIGH. No entiendo porque ocurre esto, pero es lo que pasa. Supongo que debe ser por el programa que decodifica el código RC5 del mando IR, que utiliza interrupciones y no debe de dejar que se ejecute la subrutina (es una hipótesis, porque no se me ocurre otro motivo por el cual no funcione). Cualquier sugerencia sobre el código a utilizar será bienvenido. Saludos

Sinceramente no tengo experiencia con un receptor de infrarojos, pero si con un "simple" teclado Ps2.

bueno, supongo que al igual que el teclado el R. de Infrarojos tendrá su propio protocolo, y entre toda la información que te envia está la que a ti te interesa, te pongo como ejemplo el teclado:

Envia 10 bits (10 interrupciónes), los buenos los 8 centrales, dicho byte tienes que almacenarlo en una variable global (mejor un array por si envias muchas teclas) y tratarlas dentro del programa principal (independiente de la interrupción).

Otra cosa que puede que le suceda a tu codigo es que si no borras el valor de la tecla, una vez utilizada, es posible que esté continuamente encendiendo y apagando puesto que la condición se sigue cumpliento (una explicación de porque te funciona solo la primera vez, pasa de no tener valor a tenerlo...)

Hola Imagina, No creo que sea problema de borrar la tecla, puesto que si pulso la tecla 1, me enciende el led que corresponde (verde). Después pulso la tecla 2 y me enciende el led que corresponde (amarillo). Si después vuelvo a pulsar la tecla 1, se supone que debería de apagar el led verde, puesto que debería de cambiar de estado la variable valverde. El código de descifrar el protocolo RC5 del mando IR no es mio. Lo saqué de la página que indiqué en el post anterior. El ejemplo que trae, de poner en HIGH o LOW algunos pins digitales funciona correctamente, pero en el momento que queremos que haga cambio de estados o introducimos delays, deja de funcionar. Si se os ocurre algo nuevo, quedo a la espera. Saludos,

Dónde has declarado las variables? a mi me dió algo de lata eso. Si lo tienes a mano pon el código haber si damos con el problema.

Salu2.

Hola Outl4w,
Yo declaro las variables al comienzo del código para que sean globales.
Salvo el código de las variables y el de los case, el resto del código no es mío. Está sacado como indiqué con anterioridad de:

http://www.5volt.eu/archives/14

El código es el siguiente, haber si entre todos somos capaces de sacar el problema

int verde = 5;
int amarillo = 6;
int rojo = 7;
int verde2= 10;
int amarillo2 = 11;
int rojo2 = 12;
int valverde;
int valamarillo;
int valrojo;
int valverde2;
int valamarillo2;
int valrojo2;

#define F_CPU 16000000UL // CPU clock in Hertz.
#define TMR0_PRESCALER 256UL
#define IR_BIT 1778UL // bit duration (us) in use for IR remote (RC5 std)
#define IR_IN 8 //IR receiver is on digital pin 8 (PORT B, bit0)

#define TMR0_T (F_CPU/TMR0_PRESCALER*IR_BIT/1000000UL)
#define TMR0_Tmin (TMR0_T - TMR0_T/4UL) // -25%
#define TMR0_Tmax (TMR0_T + TMR0_T/4UL) // +25%
#if TMR0_Tmax > 255
#error "TMR0_Tmax too big, change TMR0 prescaler value ", (TMR0_Tmax)
#endif

// Variables that are set inside interrupt routines and watched outside
// must be volatile
volatile uint8_t tmr0_OC1A_int; // flag, signals TMR0 timeout (bad !)
volatile uint8_t no_bits; // RC5 bits counter (0…14)
volatile uint16_t ir_data_word; // if <> holds a valid RC5 bits string (good !)

void start_timer0(uint8_t cnt) {
OCR0A = cnt;
TCNT0 = 0;
tmr0_OC1A_int = 0;
TIMSK0 |= _BV(OCIE0A); // enable interrupt on OC0A match
TCCR0B |= _BV(CS02); // start timer0 with prescaler = 256
}

// Interrupt service routines
ISR(PCINT0_vect) { // signal handler for pin change interrupt
if(no_bits == 0) { // hunt for first start bit (must be == 1)
if(!digitalRead(IR_IN)){
start_timer0(TMR0_Tmax);
no_bits++;
ir_data_word = 1;
}
}
else {
if(!tmr0_OC1A_int) { // not too much time,
if(TCNT0 > TMR0_Tmin) { // not too little.
// if so wait next (mid bit) interrupt edge
start_timer0(TMR0_Tmax);
no_bits++;
ir_data_word <<= 1;
if(!digitalRead(IR_IN)){
ir_data_word |= 1;
}
else {
ir_data_word &= ~1;
}
}
}
}
}

ISR(TIM0_COMPA_vect) { // timer0 OC1A match interrupt handler
TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00)); // stop timer
tmr0_OC1A_int = 1; // signal timeout
no_bits = 0; // start over with hunt for valid stream
ir_data_word = 0;
}

void setup() {

pinMode(verde, OUTPUT);
pinMode(amarillo, OUTPUT);
pinMode(rojo, OUTPUT);
pinMode(verde2, OUTPUT);
pinMode(amarillo2, OUTPUT);
pinMode(rojo2, OUTPUT);
valverde=0;
valamarillo=0;
valrojo=0;
valverde2=0;
valamarillo2=0;
valrojo2=0;

Serial.begin(9600); // opens serial port, sets data rate to 9600 bps

// IR remote control receiver is on IR_IN digital port
pinMode(IR_IN, INPUT);

// pin change interrupt enable on IR_IN port
PCMSK0 |= _BV(PCINT0);
PCICR |= _BV(PCIE0);

// Timer 0 : Fast PWM mode. Stopped, for now.
TCCR0A = _BV(WGM00) | _BV(WGM01);
TCCR0B = _BV(WGM02);
no_bits = 0;
sei(); // enable interrupts
}

void loop() {

uint8_t data_word; // 0…63 holds a valid RC5 key code.

for(;:wink: {
if((no_bits == 14) && ((ir_data_word & 0x37C0) == 0x3000)){
no_bits = 0; // prepare for next capture
data_word = ir_data_word & 0x3F; // extract data word

Serial.print(data_word, HEX); // output code to console
Serial.print("\n\r"); // output code to console

switch(data_word) {

case 0x01:
{
if (valverde==LOW)
valverde=HIGH;
else
valverde=LOW;
digitalWrite(verde,valverde);
}
break;
case 0x02:
{
if (valamarillo==LOW)
valamarillo=HIGH;
else
valamarillo=LOW;
digitalWrite(amarillo,valamarillo);
}
break;
case 0x03:
{
if (valrojo==LOW)
valrojo=HIGH;
else
valrojo=LOW;
digitalWrite(rojo,valrojo);
}
break;
case 0x04:
{
if (valverde2==LOW)
valverde2=HIGH;
else
valverde2=LOW;
digitalWrite(verde2,valverde2);
}
break;
case 0x05:
{
if (valamarillo2==LOW)
valamarillo2=HIGH;
else
valamarillo2=LOW;
digitalWrite(amarillo2,valamarillo2);
}
break;
case 0x06:
{
if (valrojo2==LOW)
valrojo2=HIGH;
else
valrojo2=LOW;
digitalWrite(rojo2,valrojo2);
}
break;

case 0x0C: // button POWER ON/OFF on most RC5 TV remotes
// do something
digitalWrite(5,0);
digitalWrite(6,0);
digitalWrite(7,0);
digitalWrite(10,0);
digitalWrite(11,0);
digitalWrite(12,0);
break;
// etcetera for other codes, some are in the table below
}
}
}
}

El icono que sale del guiño ;), se ha de cambiar por ; (punto y coma) No se porqué se ha colado este icono.

Vale luego le echo un vistazo. Si te interesa en mi web : http://www.opengeek.es/ hice un post hablando un poco sobre el tema. Salu2.

Hola de nuevo...

algunas cosillas raras en el condigo:

======================== case 0x01: { if (valverde==LOW) valverde=HIGH; else valverde=LOW; digitalWrite(verde,valverde); } break;

======================== según este trozo de código, el valor que le das a la variable valverde, siempre es LOW (y supongo que te dará un error de compilación por no tener definido conrrectamente el IF... ELSE pues faltan los corchetes...)

case 0x01: { if (valverde==LOW) { valverde=HIGH; } else { valverde=LOW; } digitalWrite(verde,valverde); break; }

Otra cosa que no entiendo es el "for(;;) {.....}"

Que yo sepa, eso no tiene ningún sentido (si es que funciona) y de todas formas, es totalmente prescindible puesto que, según entiendo, lo que quieres es que se repita indefinidamente... y esa es la misión de "void loop()" por lo tanto puedes eliminarlo...

Por lo demás, y suponiendo que el código de la interrupción funciona correctamente, yo lo vería bien...

jejeje... lo mismo que te ha pasado a ti... en vez del ;) va.. "; )"

Hola Imagina, Lo de los corchetes no es el problema, cuando compilo no me da error, y además, después del if (...), si solo hay una acción como es el caso valverde=HIGH, no hace falta poner corchetes. Lo del for ;; si que es un bucle infinito, pero en el código original venía así, y yo lo dejo. Yo también veo bien el código, pero no funciona. Solo hace que se ponga la salida verde en HIGH, y aunque vuelva a pulsar la misma tecla, ya no cambia de estado, es como si la variable valverde siempre estuviese en LOW y por tanto me pone la salida a verde en HIGH.