PicManía by RedRaven
 

Búsqueda personalizada

 

FUNDAMENTOS de la TRANSMISIÓN SÍNCRONA

 
 

Artículo sobre los fundamentos de la Transmisión Síncrona, también conocida como Data & Clock y un ejemplo de su implementación en C (tanto para emitir como para recibir).

Utilizada desde antaño en protocolos como PS/2 para ratones y teclados o el archiconocido ABA Track II de las antiguos lectores de Tarjetas de Banda Magnética, pero que aún la mayoría de lectores dispositivos modernos implementan, al menos como emulación del mismo. 

 

 


Fundamentos de la Transmisión Síncrona
Una visión general de qué es, para qué sirve y cómo se utiliza.
 

   Para intentar acercarnos de forma clara a qué es una transmisión Síncrona voy a utilizar mi habitual forma indirecta de atacar las cosas y vamos a empezar por su antagonista por naturaleza: la transmisión Asíncrona.
 

   Primero démosle un vistazo a su propio nombre y veamos qué significa esa palabreja de Asíncrona. Etimológicamente significa exactamente "sin reloj" o sea que no hay ninguna señal que marque los tiempos en que los datos deben leerse o están disponibles.
 

   Esto significa que en una transmisión Asíncrona tanto la información transmitida como los tiempos en que ésta debe leerse son uno y todo va junto. El mejor ejemplo de este tipo de transmisión es la transmisión serie RS232. En esta forma asíncrona de transmitir información binaria cada bit es representado por un estado Alto o Bajo de la línea de transmisión durante un tiempo predeterminado. Este tiempo debe ser siempre el mismo, dentro de los márgenes de tolerancia normales y que son de aproximadamente de un 2% del valor nominal.
 
Fijaos por tanto que esto de Asíncrono no significa sin tiempo sino bien al contrario significa con tiempos perfectamente definidos y acordados de antemano ya que de otra forma no habría manera de poner de acuerdo al emisor y al receptor en cuanto a cuando está disponible cada bit para su lectura.
 
   El sistema asíncrono funcionaría entonces así: En cuanto el receptor detecta el primer cambio de estado, una línea que pasa de Alto a Bajo por ejemplo en el RS232, sabe con total seguridad que tras cierto número de microsegundos transcurridos tendrá disponible el primer bit transmitido por el emisor, y tras otro igual número de microsegundos tendrá el segundo bit y ... así hasta el último bit que debe recibir.
 
   Se detecta el primer flanco de bajada y a partir de ahí solo debe mirar, cada plazo de tiempo acordado, en qué estado está la línea de transmisión, si alto o bajo, para asignar ese valor a cada uno de los bits a recibir.
 
   De esta forma cuando decimos que una comunicación RS232 es a 8 bits y a 9600 baudios lo que estamos diciendo es que vamos a recibir 8 estados consecutivos de la línea de transmisión, separados cada uno de ellos 1/9600 segundos, o sea un estado cada 104 microsegundos, siendo el primero el estado que tenga tras los primeros 104 microsegundos transcurridos desde el primer flanco de bajada.
 
   A 19.200 baudios en "tiempo" de cada bit será la mitad, 52 microsegundos, y a 4.800 baudios será el doble o sea 208 microsegundos. A esta unidad de tiempo la conocemos como el etu de una transmisión, iniciales de elementary time unit. Abajo podemos ver una representación gráfica de esto que estamos tratando, la transmisión Asíncrona de un byte compuesto por 8 bits (un típico 8N1 9.600)
 


 

   Una conclusión a la que podemos llegar después de expuesto todo esto sobre la transmisión Asíncrona es que es imprescindible saber a priori a qué velocidad vamos a recibir los distintos bits para ajustar nuestra rutina de recepción a dicha velocidad y mirar así la línea de transmisión en su momento justo, ni antes ni después, para recibir cada uno de los bits en el momento en que realmente les corresponde. Cualquier error en el cálculo dichos tiempos puede hacernos leer bits fantasmas debido a que leemos dos veces un mismo bit o porque nos saltemos alguno de ellos.
 
   Y por fin llegamos a nuestra transmisión Síncrona de datos.
 
   Síncrono significa "con reloj" y exactamente eso es lo que necesitamos, un reloj (o dicho en inglés un Clock). La transmisión síncrona necesita de dos líneas, una de datos sobre la que se van a representar los distintos estados de los bits a transmitir y una de reloj donde vamos indicando cuando está disponible cada bit en la línea de datos. Esta línea de reloj es la de "sincronización" entre ambos dispositivos, el emisor y el receptor de la transmisión.
 
   De esta forma una transmisión síncrona consiste exactamente en poner el estado de un bit en la línea de datos, generamos un pulso de subida y bajada en la línea del reloj, ponemos otro estado de bit en los datos, volvemos a dar un pulso de subida y bajada en la del reloj ... y así hasta completar el número de bits que deseemos transmitir.
 
   Esta forma de transmisión tiene una clara ventaja, y es que no es necesario poner de acuerdo en velocidad alguna a emisor y receptor de la transmisión. El emisor coloca su bit y genera el pulso en el reloj, el receptor detecta el reloj y mira el estado del bit, y así uno tras otro, a cualquier velocidad, a distinta velocidad cada bit, a toda la velocidad posible. Hay pulso significa hay dato, leo y a esperar otro pulso, mas lento o mas rápido es irrelevante solo es importante aquello de pulso-dato y a empezar de nuevo.
 
   La única limitación es que al receptor le debe dar tiempo a leer el estado de cada bit tras detectar el pulso de reloj antes de que aparezca un nuevo pulso.
 


 

   Notad que en estos ejemplo estamos utilizando la "lógica negativa" es decir que detectamos los pulsos estando la línea en alto cuando cae a bajo, o sea recibiendo primero un un flanco de bajada y después uno de subida para conformar un pulso.
 
   Todo lo que estamos tratando sería exactamente igual con los pulsos al revés, en "lógica positiva" con el  flanco de subida primero y el de bajada después. Esta configuración con las líneas en alto y dando pulsos negativos es la mas utilizada debido a la estabilidad y resistencia al "ruido" que tienen. Se consigue conectando una resistencia a VCC para que mantenga la línea a estado alto y nuestro emisor genera los pulsos poniendo la línea a GND. El receptor está constantemente recibiendo el estado alto y detecta cada pulso cuando pasa a bajo.
 


 

   Bueno, y ahora vamos a ver cómo podemos implementar una simple comunicación Síncrona en C.
 

   Las funciones para Transmitir de forma Síncrona que vamos a implementar son dos: Transmite_Bit_Clock_and_Data y Transmite_Byte_Clock_and_Data. La primera de ellas coloca el estado de un bit en la línea Data y genera un pulso en Clock, la segunda se encarga de extraer, bit a bit, el contenido de un byte (de 8 bits) y llamar a la función anterior.

 
  Funciones para Transmisión Síncrona  
  #define OUT_CLOCK PIN_B0
#define OUT_DATA  PIN_B1

void Transmite_Bit_Clock_and_Data(int1 bit){

   // Coloca Data
   if( bit==0){
      output_high(OUT_DATA);
   }
   else{
      output_low(OUT_DATA);
   }
   // Genero pulso en Clock (500 microsegundos ó 2 Khz)
   delay_us(250);
   output_low(OUT_CLOCK);
   delay_us(250);
   output_high(OUT_CLOCK);
}

void Transmite_Byte_Clock_and_Data(char c){

   int8 i;
   int1 b;

   for(i=0;i<8;i++){
      b = bit_test(c,i);
      Transmite_Bit_Clock_and_Data(b);
   }
}
   
 
 

 

 

 

   Para las funciones de recepción Síncrona vamos a usar el recurso de la Interrupción Externa de los PIC's, eligiendo estratégicamente el PIN del reloj (CLOCK) de forma que tengamos disponible una de estas interrupciones.
 

   La interrupción externa la configuramos para detectar los flancos de bajada (ved la nota anterior sobre la "lógica negativa") De esta forma cada vez que se dispara la interrupción sabemos que tenemos disponible un bit en la línea de los datos (DATA). Lo recogemos sobre nuestro recByte y contamos uno más. Cuando lleguemos a 8 bits recogidos tenemos nuestro Byte completo y podemos indicarlo convenientemente poniendo a uno el flag reccomplete.
 

   Cuando en main detectamos este reccomplete lo monitorizamos por el puerto serie y reiniciamos todo para recoger el siguiente byte.

 
  Funciones para Recepción Síncrona  
  #define IN_CLOCK PIN_B0
#define IN_DATA  PIN_B1

char recByte=0;
int8 nextBit=0;
int1 reccomplete=0;

// INTERRUPCIÓN por EXT0 Clock CK (Data - Clock) --------

#int_ext
ext_isr() {

   int1 bit;

   bit=!input(IN_DATA);
   bit_clear(recByte,nextBit);
   if(bit==1) bit_set(recByte,nextBit);
   if(++nextBit=8){
      nextBit=0;
      reccomplete=1;
   }
}

// MAIN ------------------------------------------------

void main(void){

   ext_int_edge(0,H_TO_L);
   enable_interrupts(int_ext);
   enable_interrupts(global);

   do {
      // Lectura Completa
      if(reccomplete==1){
         readcomplete=0;
         putc(recByte);
      }
   } while (TRUE);
}
   
 
 

 

 

Decodificando el protocolo ABA Track 2
Un protocolo usado desde que la electrónica era poco mas que magia.

 

   Como complemento ideal a nuestro artículo anterior sobre los Fundamentos de la Transmisión Síncrona qué mejor que un ejemplo real como la vida misma. Me propongo ahora que veamos juntos un protocolo, usado por las antiguas lectoras de tarjetas magnéticas, que lleva decenas de años en uso y aún hoy viene implementado en la gran mayoría de lectores de tarjetas modernas, Chip, Proximidad, Mifare ... etc como emulación de aquellas para mantener cierta compatibilidad entre los distintos dispositivos a los que están conectados.
 

   Este protocolo ABA Track 2 es un invento de la American Banking Association (de ahí lo de ABA) y todos y cada uno de sus detalles aparecen absolutamente descritos hasta su último detalle en la norma ISO-7813.
 

   No es nuestro propósito describir esta ISO-7813 como si en ello nos fuese la vida, sino mas bien acercarnos a ella desde un punto de vista mucho mas práctico y útil para Picmaníacos de pro que lo único que desean es poder leer e interpretar uno de estos aparatos con protocolo ABA Track 2.
 

   Empecemos pues manos a la obra y demos un primer vistazo a lo que se nos viene encima, y que no es mas que un "cronograma". O sea una representación gráfica del estado de un par de líneas en función del tiempo:
 


 

   Supongamos que tomamos las dos líneas de salida de un dispositivo que transmite en ABA Track II y somos capaces de monitorizarlas en algún tipo de visualizador de líneas digitales (en mi caso he usado mi anterior proyecto RR Logical Analyzer) No es necesario pero para que veáis qué ocurre nos viene pero que muy bien.
 

   Tened en cuenta que lo que describimos en el anterior artículo es únicamente el cómo se transmite la información, y no dijimos ni una sola palabra del qué se está transmitiendo, del significado de lo que se transmite ni de la interpretación que podíamos hacer de lo que recibimos de esa transmisión.
 

    Un protocolo nos obliga a más cosas que al simple método a usar para ser capaces de recibir o emitir una información. Nos dice también qué se va a transmitir y qué significado tiene eso que es transmitido y/o recibido. Es lo que coloquialmente conocemos como "trama". La trama es lo que realmente aplicamos a lo recibido para obtener una interpretación válida de los datos. El protocolo pone de acuerdo al emisor y al receptor en todos y cada uno de los detalles para conseguir una completa, eficaz y coherente transmisión y recepción de los datos.
 

   Con lo aprendido en el artículo sobre la Transmisión Síncrona podemos dar un paso más con solo interpretar nuestro cronograma anterior.
 
   En aquél veíamos cómo una línea de reloj (CLOCK) nos indicaba cuando debíamos mirar, sensar, catar, leer la otra línea, la de datos (DATA). De manera tal que al recibir un pulso del CLOCK si la línea DATA estaba en alto, a nivel de VCC, lo interpretábamos como que habíamos recibido un bit 0, y si por el contrario la línea DATA estaba en bajo, a nivel de GND, lo leíamos como un bit 1.
 
   Con esta simple norma íbamos recibiendo toda un ristra de bits, uno a uno sobre la línea de DATA, y cada uno de ellos al golpe de batuta de nuestra línea de CLOCK.
 
   Con lo cuál estamos en disposición de añadir a nuestro cronograma la interpretación en Bits de lo que significa:
 


 

   Quedémonos por ahora con los quince primeros bits recibidos: 000001101000001.
 

   ¿Significan algo? Es difícil de decidir con la sola vista de esos bits. Podríamos intentar decidir si se ajustan a los patrones de la tabla ASCII, pero parece complicado ya que no son divisibles por 8, que son los bits que tiene un byte y que la tabla ASCII nos dice qué significan, o si por el contrario los dividimos en bloques de 4 bits ... o de cinco ... o ... Así que vamos a concluir que: ¡No! No significan nada salvo que digamos mas cosas.
 

   Y entonces viene en nuestro salvamento el Séptimo de Caballería, que a nuestros efectos es nuestro viejo amigo el Protocolo ABA Track II, y que dice en primer lugar, como Dios hablándole a Moisés con voz profunda y sentenciosa cu Primer Mandamiento: Primero recibirás un montón de ceros, de cinco a quince, pero no más ... ni menos. Ni cuatro, ni tres, ni dos, ni uno, sino cinco o mas.
 

   ¡Hombre! y vemos que en verdad así ocurre en nuestra ristra de bits, primero nos llegan un montón de ceros (originalmente venían quince pero los he dejado en cinco, editando la imagen del cronograma y dejándolos en cinco hasta que no inventen una pantallas realmente panorámicas, simplemente no caben a lo ancho).
 

   Y sigue nuestro ABA Track 2 con su segundo mandamiento: A continuación cada Byte de información llegará con cinco bits, los cuatro primeros definen el dato a enviar y el quinto es la paridad. Que porque me da la gana va a ver Impar. El Primer bit de los cinco es el Menos Significativo.
 

   ¡Ea! pues ya tenemos un poco mas de información y podemos empezar a intentar descifrar la "trama". A partir del primer 1 que encontremos vamos a dividir nuestro "churrete" de bits en bloques de 5, de los cuales los 4 primeros son "el dato" y el quinto se calcula en función de los anteriores.
 

   Troceando, que es gerundio, tomamos nuestro afilado cuchillo ritual y nos quedan dos pequeños bloques: 11010 y 00001 .... y ya sabemos que ambos son "datos+paridad_impar" Luego el primero vamos a escribirlo en la forma 1101-0 y el segundo como 0000-1.
 

   Como hemos visto el -0 del primero y el -1 del segundo nos dicen que es la Paridad Impar. Esto significa que nos sirve para ajustar en cada bloque de 5 bits el número de unos que aparecen en él, y que por definición debe ser un número impar. Así 1101 son tres bits a 1, que es número impar donde los haya, por lo que el bit de paridad impar debe ser 0 para que no se nos convierta en par, por manos del demonio. Y el segundo dato recibido es 0000 que no tiene ningún 1 y por ello debemos poner el bit de paridad a 1 para que en ese bloque también haya un número impar de unos.
 

   Y ahora otro palito mas a la burra. San ABA TKII, santo virgen y mártir, nos dijo que los primeros serán los últimos en el Reyno de los Bytes, así que tenemos la obligación de darle la vuelta a los Bits recibidos y ponerlos como dios manda 1101 es en verdad 1011, o escrito en hexadecimal resulta que es el número 'Bh', y que el 0000 es 0000, o sea el hexadecimal '0h', como no podía ser de otra forma.
 

    Resumiendo: Recibimos un montón de ceros, recibimos el dato 'Bh', recibimos el dato '0h' ...
 

   Y continúa esta feria de vanidades. El ABA Track 2 nos dice muchas mas cosas. Sus mandamientos no acaban en los dos primeros sino que se añaden por lo menos cuatro mas a la lista.
 

   Tercer mandamiento: Tras la recepción del dato 'Bh', recuerda que era 11010 en binario sin darle la vuelta como un calcetín, Recibirás mas datos en la misma forma que los anteriores, hasta un máximo de 79, pero que pueden ser 78 ó 77 ó 76 ... o ... ¡Yá!
 

   Tras el tercero ha de venir un Cuarto Mandamiento: Los datos se acaban del todo cuando recibas un dato 'Fh', o sea una tira de bits de la forma 11111 (Nota que son 4 unos, número par de unos, por lo que la paridad debe ser también un 1 para que sean 5 unos, impar y no violemos la paridad impar)
 

   Con esto ya podríamos leer todos los datos completos de una transmisión ABA Track II pero ... San ABA es persona quisquillosa y metódica que quiere dejar todo atado y bien atado. Y como no podemos tener un pez sin cola, ni una vaca sin rabo, ni un hombre sin ... ¡vamos a dejarlo aquí, haya paz hermanos!
 

   Nuestro amantísimo protocolo nos dice que tras enviarnos el 'Fh' aún nos ha de enviar una dato más para que seamos capaces de saber si todo lo anterior que nos envió es correcto o no. Para ello nos envía un dato especial (especial pero no tanto, son cuatro bits mas paridad también) que no es cualquiera sino el resultado de calcular los sucesivos OR EXCLUSIVOS de todos los anteriores que nos ha enviado, empezando por el 'Bh' y terminando por el 'Fh'. A esto se les ocurre llamarlo el LRC o sea el Longitudinal Redundancy Chek o Comprobación Longitudinal Redundante o Redundancia de la Comprobación Longitudinal o .... ¡Yá!
 

   Y como no, por último, como traca final fin de fiesta, como estertor de una celebración de altura, otro sano, largo y completo montón de ceros final, diciendo hasta aquí hemos llegado, amigos.
 
   O sea esto:
 

 
   Aquí tenemos toda una transmisión (real) de una serie de datos en Protocolo Serie Asíncrono ABA Track 2 que consiste en:
  • Una serie de 10 ceros.
  • Start Character 'Bh' también conocido como "Sentinel"
  • Los datos 0321215679127
  • End Character 'Fh'
  • LRC o dato calculado para comprobar transmisión
  • Otra serie de 9 ceros.
que podemos representar de esta forma:
 
 
 
  Rutinas en C para la transmisión de Data & Clock en ABA Track 2  
   

void Transmite_Bit_Clock_and_Data(char c){

  // Data
  if((c&0x01)==0){
    output_high(OUT_DATA);
  }
  else{
    output_low(OUT_DATA);
  }
  // Clock
  delay_us(250);
  output_low(OUT_CLOCK);
  delay_us(250);
  output_high(OUT_CLOCK);
}

void Transmite_Byte_Clock_and_Data(char c){

  int i;
  char bt,paridad=0;

  for(i=0;i<4;i++){
    bt=(c>>i)&0x01;
    Transmite_Bit_Clock_and_Data(bt);
    paridad+=bt;
  }
  bt=~(paridad&0x01);
  Transmite_Bit_Clock_and_Data(bt);
}

void output_Code_clock_and_data(void){

  int i;
  char c,LCR=0x0B;

  // transmite cabecera de 15 ceros
  for(i=0;i<15;i++) Transmite_Bit_Clock_and_Data(0);
  // identificador de TX pista2
  Transmite_Byte_Clock_and_Data(0x0B);
  // bytes de code
  for(i=0;i<nextCodeChar;i++){
    c=(Code[i]-'0') & 0x0F;
    LCR=LCR^c;
    Transmite_Byte_Clock_and_Data(c);
  }
  // identificador fin
  Transmite_Byte_Clock_and_Data(0x0F);
  LCR=LCR^0x0F;
  // transmite LCR
  Transmite_Byte_Clock_and_Data(LCR);
  // transmite cola de 15 ceros
  for(i=0;i<15;i++) Transmite_Bit_Clock_and_Data(0);
}
   

 
 

 

 

 

 

 

 

Esta página se modificó el 27/12/2008


Esta página usa la letra Ñ

Nota pública importante sobre las consultas al Webmaster de PicManía.


Sugerencias a Picmanía... (que serán leídas pero seguramente no podrán ser contestadas)

Esta página pertenece al grupo de páginas de Diego RedRaven

 

 



Nota: Esta página Web esta repleta de imágenes, textos, logotipos y demás material extraídos de los mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de autor, uso y/o reproducción. Si Ud. es depositario de dichos derechos y desea que el material correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y será inmediatamente retirado. Gracias.
 
Visitas
Totales : 13774 Hoy: 1 Activas: 1 Vistas: 13774

Esta página fue modificada el 07-08-2010 15:41:25

           
 DmSoft WAMP Escribir Unreal