Al principio, esto me parecía imposible, ya que había que calcular con precisión el tema tiempos, frecuencia interna que depende a su vez de la tensión de una batería, la cual también es variable, por ende Lambda también. Así que se me ocurrió medir ese Lambda cada vez que se manda el código. Los resultados fueron óptimos.
Luego de un tiempito de renegar, finalmente pude con él, filtrando o eliminando aquellos paquetes que no corresponden. Sin más preámbulos, les paso el código en CCS. Lo hice para un PIC16F628 (con su memoria EEPROM se pueden almacenar hasta 30 llaveros y controlar diferentes dispositivos o lo que ustedes quieran).
#include <16f628a.h>
#fuses INTRC_IO, NOWDT, BROWNOUT, NOPROTECT, MCLR
#use delay (internal = 4M)
#use fast_io (B)
#define Margen (int16)40
#define RX PIN_B4
#define LCD_RS_PIN PIN_A7 ////
#define LCD_RW_PIN PIN_A4 ////
#define LCD_ENABLE_PIN PIN_A6 ////
#define LCD_DATA4 PIN_A0 ////
#define LCD_DATA5 PIN_A1 ////
#define LCD_DATA6 PIN_A2 ////
#define LCD_DATA7 PIN_A3 ////
#include <lcd.c>
int32 Datos;
int32 Verif;
char contador_bits;
int16 Lambda;
int16 L;
int16 H;
enum {
Lambda_1=0,
Lambda_2,
Obtener_datos,
Datos_correctos,
Datos_incorrectos,
Paquete_obtenido,
Mostrar_resultados,
Paquete_fallido
};
Struct Supervisor {
int Tarea;
int Resultado;
}Supervisor;
void display();
#INT_RB
void int_rb_sir (){
switch (Supervisor.Tarea){
case Lambda_1:
if(input(RX)){
Lambda = 0;
L = 0;
H = 0;
set_timer0(0);
clear_interrupt(int_timer0);
enable_interrupts(int_timer0);
set_timer1(0);
Supervisor.Tarea = Lambda_2;
}
break;
case Lambda_2: //Se obtiene el valor de Lambda
if(!input(RX)){
Lambda = get_timer1();
L = 0;
H = 0;
contador_bits = 0;
set_timer0(0);
set_timer1(0);
Supervisor.Tarea = Obtener_datos;
}
break;
case Obtener_datos: //Comienza a medirse la duración del pulso bajo
if(input(RX)){
set_timer0(0);
L = get_timer1();
set_timer1(0);
}
else { //Comienza a medirse la duración del pulso alto
set_timer0(0);
H = get_timer1();
set_timer1(0);
}
if (H>0 && L>0){
if(L>((2*Lambda)+Margen)){
disable_interrupts(global);
Supervisor.Resultado = Datos_incorrectos;
}
else if(L<(Lambda-Margen)){
disable_interrupts(global);
Supervisor.Resultado = Datos_incorrectos;
}
else if(H>((2*Lambda)+Margen)){
disable_interrupts(global);
Supervisor.Resultado = Datos_incorrectos;
}
else if(H<(Lambda-Margen)){
disable_interrupts(global);
Supervisor.Resultado = Datos_incorrectos;
}
else {
if (L>H){
bit_set(Datos,contador_bits);
}
else if (L<H){
bit_clear(Datos,contador_bits);
}
L = 0;
H = 0;
contador_bits++;
Supervisor.Tarea = Obtener_datos;
}
}
break;
case Paquete_obtenido:
break;
case Mostrar_resultados:
break;
case Paquete_fallido:
break;
default:
clear_interrupt(int_timer0);
clear_interrupt(int_rb);
enable_interrupts(int_rb);
enable_interrupts(int_timer0);
enable_interrupts(global);
break;
}
}
#int_timer0
void interr_timer0(int32) {
clear_interrupt (int_timer0);
disable_interrupts (GLOBAL);
Supervisor.Tarea = Paquete_fallido;
}
void main () {
disable_interrupts(global);
set_tris_B (0x14); // RB4 = 1, RB2 = 1
setup_timer_0 (RTCC_DIV_4 | RTCC_INTERNAL);
setup_timer_1 (T1_DIV_BY_1 | T1_INTERNAL);
setup_oscillator(OSC_4MHZ);
setup_ccp1 (CCP_OFF);
enable_interrupts (INT_RB);
lcd_init();
Datos = 0;
contador_bits = 0;
Lambda = 0;
H = 0;
L = 0;
Supervisor.Tarea = Lambda_1;
Supervisor.Resultado = Datos_correctos;
enable_interrupts (GLOBAL);
while (true) {
switch(Supervisor.Tarea){
case Lambda_1:
break;
case Lambda_2:
break;
case Obtener_datos:
if(contador_bits < 28){
Supervisor.Tarea = Obtener_datos;
}
else {
Verif = Datos & 0x0A000000;
if(Verif == 0x0A000000){
Supervisor.Tarea = Mostrar_resultados;
Supervisor.Resultado = Datos_correctos;
}
else{
Supervisor.Tarea = Paquete_fallido;
Supervisor.Resultado = Datos_incorrectos;
}
}
break;
case Paquete_obtenido:
if(Supervisor.Resultado == Datos_correctos){
Supervisor.Tarea = Mostrar_resultados;
}
else{
Supervisor.Tarea = Paquete_fallido;
}
break;
case Mostrar_resultados:
display();
case Paquete_fallido:
disable_interrupts(int_timer0);
default:
Datos = 0;
Supervisor.Resultado = Datos_correctos;
Supervisor.Tarea = Lambda_1;
contador_bits = 0;
Lambda = 0;
L = 0;
H = 0;
clear_interrupt(int_rb);
clear_interrupt(int_timer0);
enable_interrupts(global);
break;
}
}
}
void display(){
contador_bits = 0;
lcd_gotoxy(1,1);
printf(lcd_putc,"%LX",Datos);
delay_ms(500);
}
También agrego el circuito de prueba para que puedan comprobar su funcionamiento.