Hola: Hace tiempo que no doy la lata con este tema, pero he seguido experimentando. Después de que no obtuviera resultados con la primera versión que hice en Pascal debido a los problemas que me daba el compilador, traduje el programa al C de CCS, que me ha ido mucho mejor, pero he llegado a un punto en que no avanzo, pues el micro solo captura algunos caracteres (solo dos o tres) y pierde los demás. Para descartar problemas con el CMX602B, lo configuré para que no usara el ?data retiming? y ?escupiera? los caracteres según los decodificara, viéndolos en el PC previo paso por un MAX232. El resultado es que se recibía perfectamente todo el mensaje, con los bytes de control, fecha, hora y número de teléfono completos, aunque antes y después del mensaje se colaban algunos caracteres aleatorios, de ruido, pero fácilmente eliminables. Mirando el montaje aparecido en ?Todo electrónica?, me di cuenta de que algunos componentes que rodean al CMX eran diferentes respecto a los que aparecen en el data sheet del fabricante, concretamente los del amplificador operacional que incluye, y que es el que amplifica la señal FSK antes de demodularla. Están ajustados de forma que tenga menos ganancia. Lo probé así y se reciben menos caracteres de ?ruido? al principio y final del mensaje, pero los datos útiles se reciben perfectamente de las dos formas. Así descarté que el problema estuviera aquí. Después he dejado los componentes del montaje de ?Todo electrónica? para que capte menos ruido. Después vuelvo a montarlo con el PIC y el CMX configurado en modo ?data retiming? y pensé que el problema pudiera estar en que el programa del PIC fuera demasiado lento y no fuera capaz de seguir el ritmo que le imponía el CMX, por lo que cambié el PIC por uno más rápido, pues estaba usando un 16F84A con la misma señal de reloj del CMX, concretamente a 3,579545 Mhz. Lo he cambiado por un 16F876A con un cristal de 20 Mhz, pues el 16F84A que tenía es de 4 Mhz. El resultado es exactamente el mismo, captura los mismos pocos caracteres. Sospeché que pudiera ser problema de falta de velocidad porque originalmente el programa era para un Atmel AVR, que como sabréis, son unas cuatro veces más rápidos que un PIC a la misma frecuencia de reloj, pues ejecutan una instrucción por cada pulso de reloj, mientras que los PIC necesitan cuatro. Así pues, como mis escasos conocimientos de los PIC no dan para más, incluyo el listado a continuación por si alguno quiere perder un rato en estudiarlo, por si detecta algún error o se le ocurre alguna idea para mejorarlo. El montaje es el siguiente: La pata 10 (MODE) del CMX la he unido a la RB3 del PIC. La pata 11 del CMX (ZP) la he puesto a masa La pata12 (IRQN) a la RB0, la de interrupción externa. La pata 13 (DET) del CMX no la he usado. La pata
14 (RXCK) va a RB2 y la pata 15 (RXD) a RB1. En cuanto al programa, en la función main() he hecho un bucle sin fin que solo hace que cambie de color un LED bicolor conectado a las patas RB6 y RB7, que puse para asegurarme de que el programa estaba funcionando. En la pata RB4 he puesto un pulsador para parar el programa y grabar en la EEPROM una serie de variables que he usado para saber hasta donde llega la decodificación. Después de recibir la llamada, la variable CMX_State me suele alcanzar el valor 2 y cont alcanza 5, aunque si cambio el retardo al principio de la rutina de interrupción (delay_cycles (8)) a un valor muy bajo (0 o 1) o muy alto (mayor de 16) CMX_State solo alcanza 1, o cont solo llega a 2 o 3. En el mejor de los casos, la matriz x solo me captura unas dos ?U?, a veces tres, y después caracteres sin sentido, pues sabéis que antes del mensaje principal, se envía una ráfaga de caracteres U (unas 15 o 20). Como veréis, la mayor parte del trabajo se hace en la rutina de interrupción El programa es tal vez demasiado complicado y confuso, pero es que no lo he hecho yo, sino que lo he ?fusilado? del que hay en--------------------------------------------------------------- // Based on Reinhard Kapeller
#include #fuses HS, NOPROTECT,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOCPD,NODEBUG,WRT #use delay (clock=20000000)
#BIT INTEDG = 0x81.6
//Signals of CMX602B - pins of port B of PIC16F876A #DEFINE IRQN PIN_B0 #DEFINE RXD PIN_B1 #DEFINE RXCK PIN_B2 #DEFINE MODE PIN_B3
#define DTMAX 8 // buffer length for datetime #define NBMAX 20 // buffer length for number // CMX602B CMX_States #define IDLE 0 #define RCV 1 #define RCV_U 2 #define RCV_MSGLEN 3 #define RCV_MSG 4 #define RCV_DTLEN 5 #define RCV_DT 6 #define RCV_NBLEN 7 #define RCV_NB 8 #define RCV_ARLEN 9 #define RCV_AR 10 #define RCV_XLEN 11 #define RCV_DONE 12 #define RCV_ERROR 13
char DateTime[DTMAX]; char Number[NBMAX]; byte CMX_State = IDLE; byte NBLen; byte DTLen; byte MsgLen; byte MsgPos; byte BufPos; byte Checksum; byte AbsenceR;
byte cont = 0; byte i, RX_Byte; char x[8];
void Init() { set_tris_a (0); set_tris_b (0b00010011); set_tris_c (0); output_low (MODE); output_low (RXCK); ext_int_edge (H_TO_L); //IRQ on falling edge enable_interrupts (INT_EXT); //enable interrupt (RB0) enable_interrupts (global); // CMX_State = IDLE; }
/* interrupt service routine */ #int_ext void ext_int_handler(void) { if ((CMX_State >= RCV) && (CMX_State < RCV_DONE)) { /* receive bits */ RX_Byte = 0; for (i = 8; i > 0; i--) { delay_cycles (8); output_high (RXCK); RX_Byte >>= 1; if (input (RXD)) /* get bit */ RX_Byte |= 0x80; output_low (RXCK); } x[cont]=RX_Byte; cont++; if (CMX_State >= RCV_MSGLEN) Checksum += RX_Byte; /* calculate checksum */ if (CMX_State >= RCV_MSG) { MsgPos++; /* current message position */ if (MsgPos > MsgLen) /* last byte: checksum */ { if (Checksum == 0) CMX_State = RCV_DONE; else CMX_State = RCV_ERROR; output_bit (MODE, 0); /* FSK receive mode off */ } }
switch (CMX_State) /* process RX_Byte */ { case RCV: if (RX_Byte == 'U') { MsgPos = 0; DTLen = 0; NBLen = 0; AbsenceR = 0; CMX_State = RCV_U; /* -> RCV_U state */ } break; case RCV_U: if (RX_Byte == 0x80) /* "call setup" message */ { Checksum = RX_Byte; /* start calculating checksum */ CMX_State = RCV_MSGLEN; /* -> RCV_MSGLEN state */ } break; case RCV_MSGLEN: MsgLen = RX_Byte; /* message length */ CMX_State = RCV_MSG; /* -> RCV_MST state */ break; case RCV_MSG: switch (RX_Byte) { case 0x01: /* "date/time" parameter */ CMX_State = RCV_DTLEN; /* -> RCV_DTLEN state */ break; case 0x02: /* number parameter */ CMX_State = RCV_NBLEN; /* -> RCV_NBLEN state */ break; case 0x04: /* "absence reason" parameter */ CMX_State = RCV_ARLEN; /* -> RCV_ARLEN state */ break; default: /* unused/unknown parameter */ CMX_State = RCV_XLEN; /* -> RCV_XLEN state */ } break; case RCV_DTLEN: if (RX_Byte == DTMAX) /* valid "date/time" length */ { DTLen = RX_Byte; BufPos = 0; CMX_State = RCV_DT; /* -> RCV_DT state */ } else CMX_State = RCV_MSG; /* -> RCV_MSG state */ break; case RCV_DT: DateTime[BufPos] = RX_Byte; /* store "date/time" byte */ BufPos++; if (BufPos >= DTMAX) /* end of "date/time" parameter */ CMX_State = RCV_MSG; /* -> RCV_MSG state */ break; case RCV_NBLEN: NBLen = RX_Byte; /* store "RX" length */ BufPos = 0; CMX_State = RCV_NB; /* -> RCV_NB state */ break; case RCV_NB: Number[BufPos] = RX_Byte; /* store "RX" byte */ BufPos++; if ((BufPos >= NBLen) || (BufPos >= NBMAX)) CMX_State = RCV_MSG; /* end of "RX" parameter -> RCV_MSG state */ break; case RCV_ARLEN: if (RX_Byte == 1) /* valid "absence reason" length */ CMX_State = RCV_AR; /* -> RCV_AR state */ else CMX_State = RCV_MSG; /* -> RCV_MSG state */ break; case RCV_AR: AbsenceR = RX_Byte; /* absence reason */ CMX_State = RCV_MSG; /* -> RCV_MSG state */ break; case RCV_XLEN: CMX_State = RCV_MSG; /* -> RCV_MSG state */ break; } } /* if ((CMX_State >= RCV) && (CMX_State < RCV_DONE)) */ else if (INTEDG) /* rising edge => end of ring indication */ { delay_ms (2); output_high (MODE); /* FSK receive mode */ CMX_State = RCV; disable_interrupts (INT_EXT); ext_int_edge (H_TO_L); /* IRQ on falling edge */ enable_interrupts (INT_EXT); } else /* falling edge => ring indication */ { disable_interrupts (INT_EXT); ext_int_edge (L_TO_H); /* IRQ on rising edge */ enable_interrupts (INT_EXT); } }
void main() { // int i; Init(); write_eeprom(0x38, 'S'); write_eeprom(0x39, 'p'); write_eeprom(0x3A, 'o'); write_eeprom(0x3B, 'c'); write_eeprom(0x3C, 'k'); // while 1 do nop; //endless loop while (input(PIN_B4)) { output_high (PIN_B7); output_low (PIN_B6); delay_ms (250); output_low (PIN_B7); output_high (PIN_B6); delay_ms (250); } for (i=0; i