Hay dos sistemas básicos para generar la secuencia que enviaremos a un LED emisor de infrarrojos, o bien utilizar la orden "tone (pin, frecuencia)", que no es demasiado estable debido al firmware interno del Arduino, o mejor programar directamente los "timers" del microcontrolador Atmega328, opción que elegí, aunque en el momento de realizar este proyecto aún no me había metido en con el tema de los Timers, que cuesta un algo entender porque las descripciones que normalmente se encuentran en la Red o son demasiado simples o demasiado complejas y confusas, y por tanto en este caso utilicé las órdenes de configuración de un código de Nick Gammon que encontré en una búsqueda.
TCCR2A = _BV (COM2A0) | _BV(WGM21); // configura Timer 2
TCCR2B = _BV (CS20); // Sin preescaler
OCR2A = 209; // compara valor registro A (210 * clock)= 13.125 nS. Frequencia 1/(2*13.125)=38095
...Esta rutina genera una señal continua de 38 Khz que sale por el pin 11 y no puede interrumpirse. Para modular los IR con los pulsos concretos de la señal NEC, es necesario utilizar otro pin en lógica negativa (el 7), y que el LED emisor (con su resistencia en serie) esté conectado con el positivo al pin 11 y el negativo al pin 7. De esta manera, si el pin 7 está en HIGH el cátodo del LED es siempre positivo y no emitirá infrarrojos. En el instante que el pin 7 se ponga a LOW, el cátodo se lleva a masa y entonces se emitirán infrarrojos al ritmo de 38 Khz del pin 11, conectado al ánodo del LED...
El código del programa es el siguente:
// Control IR de lámpara Lidl Livarno HG04230, Llorens Mercadal (Anilandro) jul 2019
int dato=-1;
int secuencia[33]; // Secuencia NEC a emitir + 1 bit a 0 de final
int pinLED = 11; // Pin salida de 38 Khz
int pinCOM = 7; // Pin de modulación señal NEC
void setup()
{
Serial.begin(9600);
pinMode (pinLED, OUTPUT); // Pin salida de 38 Khz
pinMode (pinCOM, OUTPUT); // Pin de modulación señal NEC
digitalWrite (pinCOM, HIGH); // Desactiva salida
TCCR2A = _BV (COM2A0) | _BV(WGM21); // configura Timer 2
TCCR2B = _BV (CS20); // Sin preescaler
OCR2A = 209; // compara valor registro A (210 * clock)= 13.125 nS. Frequencia 1/(2*13.125)=38095
}
void loop()
{
dato = -1;
datoSerie(); // Entrada de datos serie
if (dato>-1) // Si se ha introducido un dato
{
montarSec(); // Montar secuencia NEC
sendData(); // Emitir por IR la secuencia NEC
dato = -1; // Borra dato
}
delay(100);
}
//****** FUNCIONES ******************************************************
void datoSerie() // Captura dato serie desde el PC
{
if (Serial.available()==0) return;
while (Serial.available()>0) // Mientras hay datos serie (max 2 bytes)
{
if (dato== -1) dato = (Serial.read()-48); // Lee primer byte
delay(200);
if (Serial.available()==0) return; // Si no hay más bytes, regresa a loop()
if (Serial.available()>0) // Si hay otro dato
{
dato = dato * 10; // multiplica x 10
dato = dato + (Serial.read()-48); // lee nuevo y lo suma
}
}
}
//***********************************************************************
void montarSec() // Monta la secuencia NEC
{
for (int f=0; f<=32; f++)
{
if (f>-1 && f<=7) secuencia [f] = 0; // Byte de dirección a 0
if (f>=8 && f<=15) secuencia [f] = 1; // Byte inverso de dirección a 1
if (f>=16 && f<=23) // Byte dato
{
if (bitRead(dato, f-16)==0) secuencia [f] = 0;
if (bitRead(dato, f-16)==1) secuencia [f] = 1;
}
if (f>=24 && f<=31) // Crea byte inverso de dato
{
if (secuencia [f-8]== 0) secuencia [f] = 1 ;
if (secuencia [f-8]== 1) secuencia [f] = 0 ;
}
if (f==32) secuencia [f] = 0; // Añade bit de finalización a 0
}
}
//***********************************************************************
void sendData() // Envía secuencia NEC a través de IR
{
digitalWrite(pinCOM, LOW); // activa marca
delayMicroseconds(9000); // marca, 9 mS
digitalWrite(pinCOM, HIGH); // desactiva marca
delayMicroseconds(4500); // espacio, 4,5 mS
for (int x=0;x<=32;x++) // bucle de envio de 32 pulsos
{
digitalWrite(pinCOM, LOW); // activa marca
delayMicroseconds(560); // marca 560 uS
digitalWrite(pinCOM, HIGH); // desactiva marca
if (secuencia[x]==0) delayMicroseconds(560); // espacio de 560 uS en caso de ser un 0
if (secuencia[x]==1) delayMicroseconds(1690); // espacio de 1690 uS en caso de ser un 1
}
}
//***********************************************************************
El programa se maneja desde el PC, no utiliza librerías IR y tiene tres funciones. La "void datoSerie()" que captura un dato serie enviado desde el PC que debe corresponder al código de botón del mando IR que pulsaríamos.
...Una vez recibido el código del botón desde el PC, la función "void montarSec()" monta la secuencia completa del protocolo NEC correspondiente a este código y la guarda en el array "secuencia[]" en forma de 1 y 0.
...Y la función "void sendData()" lee el array "secuencia[]" y traduce los bits a impulsos con una marca de 560 mSec, y un tiempo variable entre ellos según sea el impulso de inicio (9 ms), o un "0" (560 uSec), o un "1" (1690 uSec). Estos impulsos modulan la portadora de 38 Khz del pin 11 a través del pin 7...
Continuará...
Saludos
Llorens