Revitaliza mandos a distancia antiguos: Crea dispositivos inteligentes DIY con Arduino
Componentes y suministros
| Arduino Nano R3 | 1 |
| LED 5 mm: Rojo | 3 |
| LED 5 mm: Verde | 1 |
| LED 5 mm: Amarillo | 1 |
| LED Azul | 2 |
| Protoboard grande sin soldadura | 1 |
| Cables jumper (genéricos) | 1 |
| Interruptor basculante (Off)-On | 1 |
| Fuente de alimentación para protoboard 5V/3.3V SparkFun | 1 |
| Receptor IR (genérico) - KY-022 37.9KHz | 1 |
Sobre el proyecto
Este proyecto permite reutilizar mandos a distancia sobrantes de viejos videocaseteras, TV, reproductores DVD, etc.

Puedes usar los mandos para encender dispositivos como lámparas, calefactores, etc., mediante relés, transistores de potencia o cualquier cosa que una señal de 5 voltios pueda controlar. Como se muestra aquí, solo conmuta hasta 6 LEDs. La idea es proporcionar el sketch y el diseño en protoboard para que las señales enviadas a los LEDs puedan enviarse en paralelo a lo que el usuario imagine.

Tal como está diseñado, lee 6 códigos IR de cualquier mando y los "memoriza". Me gusta usar los dígitos 1, 2, 3, 4, 5, 6, pero funcionan cualesquiera seis teclas. Cualquier otra tecla con un código IR distinto a los 6 conocidos actúa como reinicio y apaga todas las salidas. Logro esto escribiendo los códigos como enteros largos en la memoria EEPROM del Arduino. Cada uno ocupa 4 bytes, pero como el UNO y el NANO tienen 1024 bytes de EEPROM, hay espacio de sobra. Esta memoria se mantiene tras reinicios y apagados.
Todo cabría en una sola protoboard, salvo el interruptor basculante. Se podrían soldar pines al interruptor para incluirlo en la protoboard; yo usé cinta para sujetarlo a la mesa durante el desarrollo.


El "truco" con el que luché fue la luz parásita o señales débiles de algunos mandos. Lo resolví doblando cuidadosamente el "LED" receptor unos 45 grados hacia abajo y colocando una pequeña caja casera de cartón y cinta sobre él, con un extremo abierto. Captura los códigos consistentemente desde 1,5-2,5 metros o más. No he tenido fallos en más de cinco días de pruebas y ajustes.
Programación
Para programarlo, usa la posición "learn" (aprender). Cambias de modo "run" (ejecución) a "learn" girando el interruptor basculante. Este enciende un LED indicador rojo de modo, señalando que está listo para escuchar. Parpadea el LED 1 y pulsas una tecla en tu mando. El LED 1 parpadeante está programado para reaccionar a ese código. En cuanto lo reconoce, parpadea rápidamente el LED indicador de modo durante uno o dos segundos (¡tan rápido que parece vibrar!) y pasa al siguiente LED. Esto continúa hasta programar los seis. Entonces el LED indicador parpadea lentamente a intervalos de un segundo indicando que el sistema debe volver al modo run.
El error más común al programar es olvidar mover el dedo a la siguiente tecla del mando, programando dos salidas con el mismo código. Cada vez que arranca, busca duplicados. Si los encuentra, parpadea los LEDs "ofensores" unas veces para sugerir reprogramación. Sin embargo, uno puede querer varias teclas haciendo lo mismo, así que no fuerza la reprogramación.
El estado de modo, errores, etc., se indican por la frecuencia de parpadeo del LED rojo de estado. Toda la información indicada por los LEDs parpadeantes se envía al monitor serie. Lo configuré para usar secuencias de parpadeos para que un usuario pudiera configurarlo sin ordenador. Los mensajes en el monitor serie son más fáciles de seguir que memorizar qué significan los parpadeos a distintas velocidades. Como normalmente solo se programa unas pocas veces, probablemente sea más natural conectarlo al PC y ver el texto en el monitor serie.
Hay muchas comprobaciones y equilibrios en el código del sketch. Están bien documentados (¡espero!), así que no daré detalles aquí. Usuarios familiarizados con C, C++ y el Arduino IDE podrán seguir el código y hacer modificaciones si lo desean.
Adenda
He probado esto con 5 relés en paralelo con los LEDs 1 a 5 y funciona como se espera. Todos conmutan una lámpara de mesa de 120 VAC, así que el circuito funciona. Me quedé sin relés, así que hay que suponer que la 6ª señal también funcionará. Nota: esto es solo una prueba de concepto. Tuve que invertir las señales de las primeras cuatro salidas con una compuerta NAND cuádruple CD4011 porque cierran a 0 voltios en lugar de 5 voltios. El relé único funciona con señal de +5 voltios, así que no hizo falta inversión de señal. ¡Ten cuidado al conmutar tensiones de red! Son alto voltaje y pueden dar una mala descarga o incluso matar!
Recuerda, esto es solo un ejemplo. Usa tu imaginación para decidir qué dispositivos conectar a las 6 salidas. ¡Disfruta!



Código
Sketch para reutilizar mando IR Arduino
/* Conmuta 6 LEDs usando un mando IR para ilustrar cómo reutilizar mandos sobrantes para controlar casi cualquier dispositivo. Este sketch aprende los códigos del fabricante para las teclas 1,2,3,4,5,6 y 0 de cualquier mando IR cuando el interruptor basculante está en posición "Learn" o programar. Estos valores se guardan en la EEPROM del Arduino Nano. Cuando el interruptor se pone en modo "Run", estos valores determinan qué tecla se pulsa. 6 LEDs asociados se conmutan on/off por el mando. Esto demuestra cómo aprender y usar los códigos independientemente del tipo de mando IR. Además de LEDs, las salidas pueden ampliarse para encender/apagar dispositivos con relés, transistores de potencia, etc. Paul M Dunphy VE1DX Marzo 2020 */
// Incluir librería IR Remote desarrollada por Ken Shirriff
#include <IRremote.h>
// Capacidad de leer/escribir en los 1024 bytes de EEPROM
#include <EEPROM.h>
long unsigned int intIRCode;
long unsigned int savedIRCodes[6];
long unsigned int dupeCheck[6];
// Pin para sensor IR
const int Recv_Pin = 2;
// Pines para conmutar LEDs
const int PinOne = 12;
const int PinTwo = 11;
const int PinThree = 10;
const int PinFour = 9;
const int PinFive = 8;
const int PinSix = 7;
// Pines para leer e indicar estado interruptor Run/Learn
const int switchPin = 4;
const int statusPin = 5;
const unsigned long int repeatKeyPress = 0xFFFFFFFF;
boolean learnMode;
boolean first_iteration;
// Enteros para recordar estados de conmutación de cada LED
int togglestate1, togglestate2, togglestate3, togglestate4, togglestate5, togglestate6;
int current_remote_code;
int remote_code_1, remote_code_2, remote_code_3, remote_code_4, remote_code_5, remote_code_6;
// Objetos IR Receiver y Results
IRrecv irrecv(Recv_Pin);
decode_results results;
void EEPROMWritelong(int address, long value) {
byte four = (value & 0xFF);
byte three = ((value >> 8) & 0xFF);
byte two = ((value >> 16) & 0xFF);
byte one = ((value >> 24) & 0xFF);
EEPROM.write(address, four);
EEPROM.write(address + 1, three);
EEPROM.write(address + 2, two);
EEPROM.write(address + 3, one);
}
long EEPROMReadlong(long address) {
long four = EEPROM.read(address);
long three = EEPROM.read(address + 1);
long two = EEPROM.read(address + 2);
long one = EEPROM.read(address + 3);
return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & repeatKeyPress);
}
int Flip_LED(int led, int toggle_state) {
if(toggle_state==0) { digitalWrite(led, HIGH); toggle_state=1; }
else { digitalWrite(led, LOW); toggle_state=0; }
return toggle_state;
}
void Reset() {
digitalWrite(PinOne, LOW); digitalWrite(PinTwo, LOW); digitalWrite(PinThree, LOW);
digitalWrite(PinFour, LOW); digitalWrite(PinFive, LOW); digitalWrite(PinSix, LOW);
togglestate1 = togglestate2 = togglestate3 = togglestate4 = togglestate5 = togglestate6 = 0;
}
void guessType() {
Serial.print("Remote appears to be a ");
switch (results.decode_type){
case NEC: Serial.println("NEC "); break;
case SONY: Serial.println("SONY "); break;
case RC5: Serial.println("RC5 "); break;
case RC6: Serial.println("RC6 "); break;
case DISH: Serial.println("DISH "); break;
case SHARP: Serial.println("SHARP "); break;
case JVC: Serial.println("JVC "); break;
case SANYO: Serial.println("SANYO "); break;
case MITSUBISHI: Serial.println("MITSUBISHI "); break;
case SAMSUNG: Serial.println("SAMSUNG "); break;
case LG: Serial.println("LG "); break;
case WHYNTER: Serial.println("WHYNTER "); break;
case AIWA_RC_T501: Serial.println("AIWA_RC_T501 "); break;
case PANASONIC: Serial.println("PANASONIC "); break;
case DENON: Serial.println("DENON "); break;
default: case UNKNOWN: Serial.println("UNKNOWN "); break;
}
}
int learnCodeRead(int pinCode) {
if (irrecv.decode(&results)) { pinCode = results.value; }
return pinCode;
}
void Confirm() {
for(int i=0; i<=20; i++) { digitalWrite(statusPin, HIGH); delay(50); digitalWrite(statusPin, LOW); delay(50); }
digitalWrite(statusPin, HIGH);
}
void learn_Mode() {
boolean goodCode; int i, j; int location; int pins[6] = {12,11,10,9,8,7};
if (first_iteration) { Serial.println(); Serial.println("Entering learn mode"); Serial.println(); }
intIRCode = 0; location = 0; goodCode = true; j = 0;
while ((goodCode=true) and (j<=5)) {
for(i=0; i<=25; i++) {
digitalWrite(pins[j], HIGH); delay(200);
intIRCode = learnCodeRead(intIRCode);
digitalWrite(pins[j], LOW); delay(200);
intIRCode = learnCodeRead(intIRCode);
goodCode = ((intIRCode !=repeatKeyPress) and (intIRCode !=0));
if (goodCode) { i=30; }
irrecv.resume();
}
goodCode = (intIRCode !=repeatKeyPress and intIRCode !=0);
if (goodCode) {
if (j==0) { guessType(); }
Serial.print("Writing to EEPROM Location ");Serial.print(location); Serial.print(" IR code = ");Serial.println(intIRCode,HEX);
EEPROMWritelong(location, intIRCode); location = location + 4; j++; Confirm(); intIRCode = 0; irrecv.resume();
}
}
Serial.println(); Serial.println("Put Arduino back in run mode.");
while (digitalRead(switchPin) == HIGH) { digitalWrite(statusPin, HIGH); delay(1000); digitalWrite(statusPin, LOW); delay(1000); }
Serial.println(); Serial.println("Returning to run mode.");
delay(50); Serial.flush(); delay(50); asm volatile (" jmp 0");
}
void run_Mode() {
if (first_iteration) { Serial.println("Entering run mode"); }
if (irrecv.decode(&results)) {
if (results.value!=repeatKeyPress) {
current_remote_code = results.value;
Serial.print("Key press detected, IR code = "); Serial.println(current_remote_code,HEX);
if (current_remote_code == remote_code_1) { togglestate1 = Flip_LED(PinOne,togglestate1); }
else if (current_remote_code == remote_code_2) { togglestate2 = Flip_LED(PinTwo,togglestate2); }
else if (current_remote_code == remote_code_3) { togglestate3 = Flip_LED(PinThree,togglestate3); }
else if (current_remote_code == remote_code_4) { togglestate4 = Flip_LED(PinFour,togglestate4); }
else if (current_remote_code == remote_code_5) { togglestate5 = Flip_LED(PinFive,togglestate5); }
else if (current_remote_code == remote_code_6) { togglestate6 = Flip_LED(PinSix,togglestate6); }
else { Reset(); }
}
delay(500); irrecv.resume();
}
}
void setup() {
first_iteration = true; int i,j,k; int location; int dupeFlash[6] = {12,11,10,9,8,7};
Serial.begin(9600); irrecv.enableIRIn(); pinMode(PinOne, OUTPUT); pinMode(PinTwo, OUTPUT); pinMode(PinThree, OUTPUT); pinMode(PinFour, OUTPUT); pinMode(PinFive, OUTPUT); pinMode(PinSix, OUTPUT); Reset(); pinMode(statusPin, OUTPUT); pinMode(switchPin, INPUT);
// Comprobación EEPROM nuevo Arduino
boolean defaultToSony = false; long unsigned int IRCode = 0; location = 0;
for(i=0; i<=5; i++) { IRCode = EEPROMReadlong(location); if (IRCode==repeatKeyPress) { defaultToSony = true; } location = location + 4; }
if (defaultToSony) {
Serial.println("HEX FFFFFFFF found in EEPROM memory. Setting codes"); Serial.println("for a Sony RM-YD104 remote. Running 'learn' mode now"); Serial.println("is recommended unless that's the remote you have.");
EEPROMWritelong(0, 0x10); delay(50); EEPROMWritelong(4, 0x810); delay(50); EEPROMWritelong(8, 0x410); delay(50); EEPROMWritelong(12, 0xC10); delay(50); EEPROMWritelong(16, 0x210); delay(50); EEPROMWritelong(20, 0xA10); delay(50);
}
// Leer códigos guardados
Serial.println(); Serial.println("Reading stored IR remote codes . . . "); location = 0;
for(j=0; j<=5; j++) { savedIRCodes[j] = EEPROMReadlong(location); Serial.print("Reading from EEPROM Location ");Serial.print(location); Serial.print(" IR code = ");Serial.println(savedIRCodes[j],HEX); location = location + 4; dupeCheck[j]=savedIRCodes[j]; }
// Buscar duplicados consecutivos
for (i = 0; i <5 - 1; i++) { for (j = i + 1; j <6; j++) { if (dupeCheck[i] == dupeCheck[j]) { Serial.println("Duplicate codes found. Suggest re-running learn mode"); for(k=0; k<=5; k++) { digitalWrite(dupeFlash[i],HIGH); digitalWrite(dupeFlash[j],HIGH); delay(1000); digitalWrite(dupeFlash[i],LOW); digitalWrite(dupeFlash[j],LOW); delay(1000); } } } }
remote_code_1 = savedIRCodes[0]; remote_code_2 = savedIRCodes[1]; remote_code_3 = savedIRCodes[2]; remote_code_4 = savedIRCodes[3]; remote_code_5 = savedIRCodes[4]; remote_code_6 = savedIRCodes[5]; delay(1000); Serial.println("Stored codes read."); Serial.println();
}
void loop() {
learnMode = (digitalRead(switchPin) == HIGH);
if (learnMode) { first_iteration = true; Reset(); digitalWrite(statusPin, HIGH); learn_Mode(); Reset(); first_iteration = false; }
else { digitalWrite(statusPin, LOW); run_Mode(); first_iteration = false; }
}
Esquemáticos
Proceso de manufactura
- Diodos Emisores de Luz (LED): Desde sus Inicios a Vidas de 100 Años
- Monitorización meteorológica remota con Raspberry Pi 3 y PubNub
- Construya un Mando Universal Profesional para Raspberry Pi con LIRC
- Sistema de Monitorización Remota de Frecuencia Cardíaca con Alertas AWS IoT
- Proyecto Arduino Melodía Coffin Dance: Construya y Reproduzca el Viral Tune
- Convierte tu viejo teléfono en un interruptor remoto inteligente
- Pintura de Luz con un Solo LED: Crea Imágenes Dinámicas con Sistema Motorizado DIY
- Pantalla de 8 LED activada por sonido con Arduino
- Construye un Robot Cuadrúpedo Inteligente con Arduino: Guía Paso a Paso
- Los 5 Criterios Clave para Seleccionar una Plataforma de Control
- Eliminación segura y eficiente de maquinaria industrial obsoleta