Lo tengo "casi" todo, y ese "casi" hace que esté contento con el resto. Quiero tenerlo todo y vamos a ver si con vuestra ayuda lo logro porque me tiene desconcertado.
Introducción:Los que me conocéis de antiguo estáis al tanto de un proyecto que acometí cuando mis conocimientos de los PIC's no eran los que son hoy, que no es que sean muchos pero si que son bastantes mas que en aquella época.
El proyecto era el
Analizador lógico de 3 Canales y a pesar de todo me siento me siento muy orgulloso de él que sin embargo era difícil de manejar, sobre todo a la hora de iniciar el "sensado" y también después en el PC que había que "tratar" los datos recibidos para una correcta visualización.
Además de haber, digamos, "ampliado" el tema con cosas como la
Serie Técnicas en C y los
Decodificando el protocolo ABA Track 2 y el
El Protocolo Wiegand explicado que tratan mas o menos con el mismo asunto.
Decidí hace poco re-acometer el tema pero empezando de nuevo desde el principio, de forma mas simple, con un paso intermedio de transmisión de datos en un formato en que no hiciese falta un Software especial, como mi Analyzer realizado en Delphi, sino que en modo texto pudiesen recogerse las medidas y que después pudiesen ser tratadas algebraica o gráficamente con cualquier programa "ad hoc", incluso con el mio en Delphi pero no solo con él.
Me he tirado a la piscina y he empezado con el asunto, leyendo flancos de subida (y de bajada) y transmitiendo los resultados vía serie para poder recogerlos en el PC y guardarlos en modo texto. Después veré que hago con los datos y con qué software.
Lo primero es lo primero y eso es lo que he atacado, recoger flancos, guardarlos y transmitirlos.
ProcedimientoAunque mas abajo os pongo el fuente en
CCS de lo que llevo hecho primero os describiré lo que he implementado.
Utilizo un
18F4550 rodando a
48 Mhz, usando la PLL para obtener la máxima velocidad posible. A esta velocidad el
Timer1 de 16 bits tiene un ciclo de Tick de 0.0833 uS y un desborde (Overflow) de 5,461333 mS.
Los distintos desbordes del Timer1 los recojo sobre una variable con la #int_timer1.
Senso al inicio los
PIN_B0, PIN_B1 y
PIN_B2 para conocer su estado y con esta información configuro las
#int_ext, #int_ext1 y
#int_ext2 de forma que interrumpan a la llegada del flanco correspondiente al cambio al estado contrario. Así si leo un H en PIN_B0 configuro #int_ext para H_TO_L y si leo al inicio un L la configuro para recibir el flanco L_TO_H.
A partir de ahí habilito las tres interrupciones mas la del Timer1 y me quedo a la espera de la llegada de los distintos flancos, sean estos los que sean. Cuando llega el primero, por cualquiera de los tres canales pongo a cero tanto el Timer1 como el contador de Overflows del Timer1 para que los distintos flancos sean recogidos en unidades de tiempo de distancia del Timer1 con respecto a ese primer flanco.
Tengo en
RAM tres
ARRAYS donde voy a guardar los datos de cada flanco cuando llegue por cada una de las tres interrupciones. Estos datos van a ser:
- Canal por el que llega (1,2 ó 3) y si es L_TO_H ó H_TO_L
- Valor del Timer1 (16 bits) en el momento de su llegada
- Número de Desbordes del Timer1 ocurridos en el momento de su llegada
Cada vez que llega un flanco
Conmuto la interrupción correspondiente al flanco contrario y me tomo nota del siguiente flanco que estoy esperando.
Cuando lo estimo oportuno le pido al PIC que me envíe los datos y entonces vuelca la información recogida en los ARRAYS al canal serie y puedo o visualizarlos o recogerlos en el PC.
El formato es:
<D,Index,Channel,Overflows,Timer>
Con estos datos es fácil calcular el tiempo de llegada de cada flanco ya que es:
timeF = (
Overflows * 5461,333 uS) + (
Timer 0.0833 uS) expresado en microsegundos.
Aquí tenéis un ejemplo de una lectura realizada en la que se ven datos de los tres canales:

Paso ahora a mostraros el código fuente pertinente que he escrito:
Fuses y configuración:
#fuses HSPLL,NOMCLR,PUT,BROWNOUT,BORV43,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,CCP2B3
#use delay(clock=48000000)
#use rs232(baud=115200, xmit=TTL_TX, rcv=TTL_RX)
#define MaxRecords 255
Variables en RAM:
int8 timer1_overflows;
char next_Interrupt_1;
char next_Interrupt_2;
char next_Interrupt_3;
int8 flagFirstEdge;
char ChannelEdge[MaxRecords];
int8 Overflows[MaxRecords];
int16 Timer[MaxRecords];
int8 Index;
Código de Inicialización del sistema:
void limpia_data_records(void){
for(Index=0;Index<MaxRecords;Index++){
ChannelEdge[Index] = 0x00;
Overflows[Index] = 0x00;
Timer[Index] = 0x00;
}
Index=0;
}
void exec_COMMAND_START(void){
limpia_data_records();
flagFirstEdge = 0x00;
ext_int_edge(0,H_TO_L); next_Interrupt_1='L';
ext_int_edge(1,H_TO_L); next_Interrupt_2='L';
ext_int_edge(2,H_TO_L); next_Interrupt_3='L';
if( !input(PIN_B0) ){ ext_int_edge(0,L_TO_H); next_Interrupt_1='H'; }
if( !input(PIN_B1) ){ ext_int_edge(1,L_TO_H); next_Interrupt_2='H'; }
if( !input(PIN_B2) ){ ext_int_edge(2,L_TO_H); next_Interrupt_3='H'; }
enable_interrupts(int_ext);
enable_interrupts(int_ext1);
enable_interrupts(int_ext2);
enable_interrupts(int_timer1);
printf("<%c,%c,%c,%c>\r\n",COMMAND_ACK,next_Interrupt_1,next_Interrupt_2,next_Interrupt_3);
}
Y las interrupciones para la Captura de Datos:
// Base de Tiempos //////////////////////////////////////////////////
#int_timer1
void timer1_handler(void){
++timer1_overflows; // One Tick: 0.0833 uS, One Overflow: 5,461333 mS
}
// Canal 1 : RB0 ////////////////////////////////////////////////////
#int_ext
void channel_1_handler(void){
if(flagFirstEdge==0x00){
flagFirstEdge=0x01;
timer1_overflows=0x00;
set_timer1(0);
}
ChannelEdge[Index] = '1' + next_Interrupt_1;
Overflows[Index] = timer1_overflows;
Timer[Index] = get_timer1();
++Index;
if(next_Interrupt_1=='H'){
ext_int_edge(0,H_TO_L);
next_Interrupt_1='L';
}
else{
ext_int_edge(0,L_TO_H);
next_Interrupt_1='H';
}
}
// Canal 2 : RB1 ////////////////////////////////////////////////////
#int_ext1
void channel_2_handler(void){
if(flagFirstEdge==0x00){
flagFirstEdge=0x01;
timer1_overflows=0x00;
set_timer1(0);
}
ChannelEdge[Index] = '2' + next_Interrupt_2;
Overflows[Index] = timer1_overflows;
Timer[Index] = get_timer1();
++Index;
if(next_Interrupt_2=='H'){
ext_int_edge(1,H_TO_L);
next_Interrupt_2='L';
}
else{
ext_int_edge(1,L_TO_H);
next_Interrupt_2='H';
}
}
// Canal 3 : RB2 ////////////////////////////////////////////////////
#int_ext2
void channel_3_handler(void){
if(flagFirstEdge==0x00){
flagFirstEdge =0x01;
timer1_overflows=0x00;
set_timer1(0);
}
ChannelEdge[Index] = '3' + next_Interrupt_3;
Overflows[Index] = timer1_overflows;
Timer[Index] = get_timer1();
++Index;
if(next_Interrupt_3=='H'){
ext_int_edge(2,H_TO_L);
next_Interrupt_3='L';
}
else{
ext_int_edge(2,L_TO_H);
next_Interrupt_3='H';
}
}
Como podéis ver el tratamiento en las tres interrupciones externas es absolutamente idéntico. Y en cualquiera de ellas se controla únicamente si es el primero en llegar y se inicializa Timer1 en lo que corresponde mediante el código:
if(flagFirstEdge==0x00){
flagFirstEdge=0x01;
timer1_overflows=0x00;
set_timer1(0);
}
Conclusiones y preguntaAquí tenéis un fichero de texto con un volcado completo de datos leídos.
Las primeras líneas son:
<D, 0,3,L,125, 6>
<D, 1,1,L, 0, 339>
<D, 2,1,H, 0, 2396>
<D, 3,1,L, 0, 4444>
<D, 4,1,H, 0, 6500>
...
"Teóricamente" debería andar todo bien, y tal como se ve en la datos recogidos (las pruebas las he hecho con un dispositivo emisor de los trenes de pulsos conocido y sé que los tiempos recibidos son compatibles al 100% con lo esperado). Tengo perfectamente el canal, el tipo de flanco y el tiempo de llegada de cada uno de los flancos .... menos el primero.
<D, 0,3,L,125, 6> El primero se recoge en el canal 3, #int_ext2 como debe ser, y por lo tanto el trocito de código que controla el flag
flagFirstEdge se ejecuta en él,
timer1_overflows y el
timer1 se ponen a
cero e inmediantamente se guardan donde se debe ... de echo el valor del timer1 de esa primer línea parece ser también correcto ya que 6 es lo esperado que tardaría en recogerse tras ejecutar el propio código de dentro de la interrupción.
Pero lo que no es posible creerse que los
overflows sean
125. Simplemente no es posible.
Si se ejecuta
timer1_overflows=0x00; y tres lineas mas abajo se ejecuta
Overflows[Index] = timer1_overflows; no es posible que se recoja
125 en lugar de
0x00. Y Index no ha podido cambiar .... uffff
Lo dicho estoy desconcertado con este único "bug" y no se a que es debido.
Y quiero saberlo.
¿Se os ocurre algo?
