Estoy intentando hacer un sistema de control inalámbrico para luces mediante infrarrojos y arduino nano. lo quiero hacer a travez del protocolo NEC pero sin librerías, quiero hacer el código desde cero solo para mandar códigos NEC. Ya encontré un código para recibir NEC sin librería le hice unas modificaciones y anda perfecto enviando desde otro arduino con la librería IRRemote. Ahora como la idea es hacerlo sin librería empece a trabajar con el código emisor. No encontré mucho asi que me puse a hacerlo. mando los pulsos a 38 KHz con las pausas definidas tal y como lo dice el protocolo. pero al receptor no me llegan los datos correctamente. Utilice la función Tone() para mandar los pulsos modulados.y noTone() para las pausas seguido de delayMicroseconds()
Si alguien sabe algo de este protocolo y me puede ayudar... dejo código de receptor y de emisor.
CODIGO EMISOR
#define ledIR 4
#define Hz 38000
unsigned long codigo;
int x;
void setup() {
pinMode(ledIR,OUTPUT);
pinMode(2,INPUT);
Serial.begin(9600);
}
void loop() {
if (digitalRead(2)){ //si aprieto un pulsador...
codigo=0x11111111; //asigno el código a enviar de 32 biits
tone(ledIR,Hz);
delayMicroseconds(9000); //envio un pulso de 9 mseg a 38 Khz
noTone(ledIR);
delayMicroseconds(4500);//envio una pausa de 4.5 mseg (inicio de código)
for (x=31;x>=0;x--){ //envio el pulso uno por uno de todos los 32 bits de 560 useg
tone(ledIR,Hz);
delayMicroseconds(560);
if (bitRead(codigo,x)){
noTone(ledIR);
delayMicroseconds(1690); //envio una pausa de 1690useg para asignar un bit en 1
}else{
noTone(ledIR);
delayMicroseconds(560);
Serial.print("0"); //envio una pausa de 1690useg para asignar un bit en 0
}
}
tone(ledIR,Hz); //envio el bit de parada
delayMicroseconds(560);
noTone(ledIR);
delay (1000);
}
}
CODIGO RECEPTOR
#define IR 11 //Pin al que va conectado nuestro receptor de infrarrojos.
long duracion[32]; //array que contiene la duracion de cada pulso en microsegundos (uS)
int x = 0; //Contador para moverse por las distintas variables de los arrays
int pulso_comienzo; //En esta variable se almacena el valor del pulso de inicio de 4,5mS
unsigned long codigo_tecla = 0; //Valor de la tecla pulsada convertido de binario a decimal
/********************************************************************************************/
/********************************************************************************************/
// CONFIGURACION DEL MICROPROCESADOR
void setup() {
Serial.begin(9600);
}
void loop() {
if (digitalRead(IR) == 0) //Esperamos que se pulse una tecla
{ //PASO 1: DETECCION DEL PULSO DE INICIO DE SECUENCIA (4,5mS)
pulso_comienzo = pulseIn(IR, HIGH);
if (pulso_comienzo > 4000 && pulso_comienzo < 5000) //...comprobamos si es el pulso de comienzo de 4,5mS (inicio de secuencia)
{
lecturaCodigoIr(); //Funcion que lee la tecla pulsada y la almacena en la variable (codigo_tecla)
}
}
//Accion a realizar segun la tecla pulsada.
Serial.println(codigo_tecla, HEX);
codigo_tecla = 0;
}
// SUBRUTINAS
//Subrutina que lee que tecla del mando a distancia se ha pulsado y
//la almacena en la variable codigo_tecla
void lecturaCodigoIr()
{ //PASO 2: CRONOMETRAJE DE TIEMPOS DE CADA PULSO(uS) (empezando desde el bit de la derecha)
for (x = 31; x >= 0; x--) {
duracion[x] = pulseIn(IR, HIGH); //Duracion de cada pulso (uS)
}
//PASO 3: SEGUN EL TIEMPO DE CADA PULSO, DETERMINAMOS SI ES UN 0 O UN 1 LOGICO (Ver protocolo NEC)
for (x = 31; x >= 0; x--)
{
if (duracion[x] > 500 && duracion[x] < 700) //Si el pulso dura entre 500 y 700uS...
{
bitClear(codigo_tecla, x); //... es un 0 logico
}
if (duracion[x] > 1500 && duracion[x] < 1750) //Si el pulso dura entre 1500 y 1750uS
{
bitSet(codigo_tecla, x); //... es un 1 logico
}
}
}
//FIN SUBRUTINAS ************************************************************************************/
Buenas... por si a alguien le interesad ejo código para enviar código nec sin librería. ocupa 32 bytes de datos de variables y 2.6 kbytes de sketch. no solo se puede usar para mandar NEC sino que se puede mandar datos por infrarrojo en paquetes de 32 bits.
/*Programa para enviar protocolo infrarrojo NEC sin libreria
* recomendacion: estudiar el protocolo NEC para entender mejor este programa
* En este codigo utilizo la funcion tone() y noTone() para prender el led infrarrojo a 38 Khz
* y con un delayMicroseconds regulo el tiempo de las pausas para la diferenciacion de bits
* "cero" o "uno".
* Uso un pulsador para activar la funcion enviarCodigo pero se puede modificar a criterio y
* necesidad de cada uno, junto con la funcion se especifica el codigo que puede ser ingresado
* mediante numeros puros expresados en HEXADECIMAL o en forma de variable o constante. Pero
* siempre como unsigned long por los 32 bits que se necesitan.
*/
#define ledIR 4 //pin donde estara el led infrarrojo
#define Hz 38000 //frecuencia de la señal
#define inicio 9600 //bit de inicio
#define arranque 4500 //pausa antes del envio del codigo
#define pulso 560 //pulso de bit
#define cero 560 //pausa de bit a cero
#define uno 1690 //pausa de bit a uno
void setup() {
pinMode(ledIR,OUTPUT);
pinMode(2,INPUT);
}
void loop() {
//si se apreta un pulsador (en este caso) llama a la funcion que lee el codigo
if (digitalRead(2)){
enviarCodigo(0x18182012); //se puede reemplazar el codigo con una constante ON OFF siempre en unsigned long
}
}
void enviarCodigo(unsigned long codigo){//codigo=variable donde estara alojado el codigo (32 bits)
tone(ledIR,Hz); //mando el pulso a determinada frecuencia.
delayMicroseconds(inicio); //dejo de mandar el pulso a los 9 mseg (con esto se crea el pulso de inicio de 9 mseg)
noTone(ledIR);//desactivo el pulso anteriormente activado a 38 Khz
delayMicroseconds(arranque);//mando el espacio de 4,5 mseg para empezar a leer el codigo
for (byte nbit=31;nbit>=0;nbit--){//leo el estado de los 32 bits del codigo 1 x 1
tone(ledIR,Hz); //mando el pulso de inicio del primer bit y...
delayMicroseconds(pulso);
noTone(ledIR);//mando una pausa para determinar el bit a cero o a uno
if (bitRead(codigo,nbit)){//si es un 1 mando una pausa de 1690 useg...
delayMicroseconds(uno);
}else{
delayMicroseconds(cero);//en cambio si es un 0 mando una pausa de 560 useg...
}
}
tone(ledIR,Hz); //mando un pulso de 560 useg para diferenciar el ultimo bit si es 0 o 1.
delayMicroseconds(pulso);
noTone(ledIR); //desactivo el led infrarrojo
}
No me queda claro como el programa descifra el valor hexadecimal, dentro del for solo veo que reconoce "1" y el resto de valores como "0". Tomando como referencia la llamada de la función con el valor (enviarCodigo(0x18182012);), como el programa sabe que en ese valor hay un 2 y un 8 ?.
Porque por lo que veo lo que envía es un valor binario.
Si fueran tan amables en explicarme como funciona se los agradezco!
Porque lo que se envía, almacena y trabaja el arduino son realmente ceros y unos. Por ejemplo, se puede enviar esta trama de dieciseis bits:
0110 0110 1100 1101
En el arduino se almacenará en dos posiciones de memoria que contienen cada una espacio para ocho bits (también llamado byte).
A la hora de mostrarlo en pantalla, puedes escoger entre ver directamente el binario (1000000011110000), decimal(26317) o hexadecimal (66CD) o interpretarlo como dos caracteres ASCII ("f═") , pero lo que hay almacenado es binario. Todo lo demás son interpretaciones distintas de un mismo dato binario.
@jorge-869 Tengo la solución a medias, suceden 2 cosas. Me inspire en los 2 códigos que posteaste!!
1 - Falta cumplir parte del protocolo NEC (Explicación del protocolo NEC).
2 - Si se baja el delay del código que envía el mensaje falla, por ahora menos de 1800 no funciona correctamente.
Intuyo que el punto 2 se soluciona modificando el código y aplicando bien lo del punto 1.
Te dejo los 2 códigos, probalos, y si solucionas lo del punto 1 y 2 compartí el nuevo código ;D
Por lo que leí, la mejor opción para ampliar el alcance de la señal se colocan varios leds emisores. Yo no tengo mucha idea y me gustaría saber cuantos leds necesitaría para detectar la señal a 5 o 6 mts y en concreto el circuito necesario.
llegaron a ver como aplicar la repetición del comando en caso de mantener apretado el botón ??
No hay manera de que me quede, no encuentro el problema, debería tener un delay de 10000microsegundos para luego mandar la señal de repetición y no logro que funcione.
Quizás este comprendiendo mal lo que dice...
si lo veo desde el serial plotter en vez de mostrarme los espacios en "blanco" me representa todo como el mensaje inicial.