PicManía by RedRaven
 

Búsqueda personalizada

 

PROYECTOS : TRADUCTOR MORSE

 

 

 

Traductor de ASCII a Código MORSE

 
Introducción:
 
  •    Si decís que tengo la cabeza definitivamente perdida no os faltará algo de razón.
  •    Quería empezar algún proyecto que involucrase transmisión / recepción vía infrarrojos ... así que lo primero que me planteé fue definir un protocolo que encapsulase mis transmisiones ... y de momento me llegó un flash: decidí darle a esto una vuelta de tuerca y transmitir y recibir ¡¡¡ EN MORSE !!!

  •    Así que antes de ponerme a infrarrojear el entorno voy a empezar con atronarlo con bip's y biiiiip's de puntos, rayas, rayas y puntos ....

 
Descripción:
 
  •    El concepto, imagino que ya lo sabéis, consiste en traducir cada letra, o número, o símbolo, en una secuencia de pulsos sonoros, o luminosos, o por cualquier otro medio de transmisión, de longitud variable según una tabla adjunta, separados una distancia en tiempo predeterminada, tanto entre pulsos que definen un carácter, como entre caracteres, como entre palabras. Es un problema de tiempos y de tablas por lo demás muy simple.

  • Una mínima tabla de transformación entre caracteres y pulsos podría ser:

A . -
B - . . .
C - . - .
D - . .
E .
F . . - .
G - - .
H . . . .
I . .
J . - - -
K - . -
L . - . .
M - -
N - .
Ñ - - . - -
O - - -
P - . . -
Q - - . -
R - . -
S . . .
T -
U . . -
V . . . -
W . - -
X - . . -
Y - . - -
Z - - . .

0 - - - - -
1 . - - - -
2 . . - - -
3 . . . - -
4 . . . . -
5 . . . . .
6 - . . . .
7 - - . . .
8 - - - . .
9 - - - - .

, . - . - . -    Coma
? - - . . - -    Interrogación
= - . . . -      Igual
- - . . . . -    Guión
/ - . . - .      Barra
" . - . . - .    Dobles Comillas
@ . - - . - .    Arroba

 

  •    La idea es recibir desde el PC por el puerto serie del PIC una secuencia de letras, encontrar cada una de ellas en la tabla precedente y procesarla, estableciendo un tiempo para los puntos, otro mayor para las rayas, uno intermedio para las separaciones entre los anteriores y por fin uno mucho mayor para separar entre si los distintos caracteres.

  •    Una tabla de tiempos pudiera ser:
     
    • Punto . 1/25 Segundo x 1
    • Raya - 1/25 segundo x 3
    • Separación Punto - Raya 1/25 Segundo x 1
    • Separación Letras 1/25 segundo x 3
    • Separación Palabras 1/25 segundo x 5
  •    Con estos tiempos definidos podemos encender o apagar leds, o un Buzzer o un IR .... y estaremos traduciendo de ASCII a MORSE. El receptor debe hacer exactamente lo contrario, recuperar los tiempos recibidos y consultar la tabla para extraer el carácter transmitido.

  •    Yo, como primera aproximación, voy a utilizar los tres leds que incluí en la RRBOARD2 de forma que el Led verde haga la transmisión (traducción) completa, el amarillo solo transmita los puntos y el rojo sólo las rayas.
     


 

  •    Si estáis interesados en manejar strings mediante punteros aquí tenéis un bonito ejemplo. Aunque solo sea por eso os recomiendo que estudiéis el código que os acompaño.
  •    Los caracteres ASCII los recibimos vía RS232 y los vamos almacenando en un buffer hasta recibir el carácter \n (0x0d) que entonces disparamos el proceso de conversión. Durante ésta lo que hacemos es ir tomando uno a uno cada carácter y los vamos convirtiendo, enviando la conversión con "." y "-" de nuevo al canal serie y procesándolos para encender y apagar los puertos del PIC que deseemos. Con ellos encenderemos luces, emitiremos los tonos o haremos lo que creamos oportuno.

  •    Como los códigos ASCII están ordenados y mi tabla de definiciones Carácter-Codigo Morse también, y además coinciden, hago un doble salto mortal carpado hacia delante y extraigo el orden en mi tabla con el mismo código ASCII recibido simplemente restándole el ASCII de la letra "A" al que he recibido, así si recibo "A"-"A"=0 o sea el primero de mi tabla de letras, pero si es "B"-"A" = 1 entonces es el segundo ...

  •    Me copio la definición a un string temporal. Esta definición se compone del carácter 0x01 seguido del carácter a definir, tras él el 0x02 y a continuación los puntos y/o rayas de su código Morse, y por fin el carácter 0x00 terminador de todos los strings C. Esta copia me la hago con una de mis funciones favoritas en CCS C sprintf.
  •    Y ahora llamo a la primera rutina de presentación, que es la de enviar el resultado de vuelta por la RS232, separando el carácter recibido de su código Morse correspondiente. Para ello le envío a morse_rs232 un puntero con lo recién extraído, y desde allí llamo a dos funciones parser, una para el carácter, morse_parse_char , y que es muy sencilla ya que solo ha de tomar el segundo carácter del string que le envío, y otra que extrae los puntos y rayas que le corresponden.

  •    Esta segunda función, morse_parse_code, es más simpática. Le paso como argumento un puntero a la definición y comenzando en el cuarto carácter realizo un bucle de esos que atacan los nervios a los novatos en C, inicializando en la misma definición del mismo bucle un par de variables índice, controlando para la salida del bucle un par de condiciones distintas, longitud máxima o carácter \0, e incrementando las dos variables índice.

  •    En este bucle me copio solo los puntos y rayas correspondientes a lo que busco sobre una variable string temporal y devuelvo como resultado un puntero a ese string temporal

  •    Con lo que tengo como resultado final, traca y explosión de ingeniosidad y grácil donosura los dos trozos por separado de lo que quería: El carácter pulsado y su representación Morse, y ambas las envío, por separado al RS232 dentro de un printf.

 
 

 

     
  // Traductor Morse RS232 -> Lights & Sound

#include <18f4550.h>
#fuses HS,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN,NOLVP,NOCPD,NODEBUG,NOWRT,NOVREGEN // Fuses
#use delay(clock=20000000) // Clock a 20 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Canal serie con el PC

const int maxlendefinition=12; // Maxima longitud de la definicion Morse en las tablas
const long lapsus=1000; // Tiempo en milisegundos para Leds al reset
const long periodo=75; // Tiempo en milisegundos para unidad Morse = . (un punto)
const int lenrecbuffer=64; // Tamaño en bytes del buffer de recepcion
const int COMMAND_NULL=0; // COMANDO NULO -> No hay comando
const int COMMAND_PROCESS=1; // COMANDO PROCESA TEXTO -> Convertir buffer a Morse

char Version[]="1.5.0\0"; // Version del programa
char CharRcv=0; // Caracter recibido por la USART
char Command=0; // Caractar a enviar al main para su procesado
char recbuffer[lenrecbuffer]; // Buffer de recepción
int nextc=0; // Indice de siguiente caracter en recbuffer

char Numeros[10][maxlendefinition]={ // Tabla de definicion de los Numeros

"\x010\x02-----\0 ",
"\x011\x02.----\0 ",
"\x012\x02..---\0 ",
"\x013\x02...--\0 ",
"\x014\x02....-\0 ",
"\x015\x02.....\0 ",
"\x016\x02-....\0 ",
"\x017\x02--...\0 ",
"\x018\x02---..\0 ",
"\x019\x02----.\0 "};


char Letras[27][maxlendefinition]={ // Tabla de definicion de las Letras

"\x01A\x02.-\0 ",
"\x01B\x02-...\0 ",
"\x01C\x02-.-.\0 ",
"\x01D\x02-..\0 ",
"\x01E\x02.\0 ",
"\x01F\x02..-.\0 ",
"\x01G\x02--.\0 ",
"\x01H\x02....\0 ",
"\x01I\x02..\0 ",
"\x01J\x02.---\0 ",
"\x01K\x02-.-\0 ",
"\x01L\x02.-..\0 ",
"\x01M\x02--\0 ",
"\x01N\x02-.\0 ",
"\x01O\x02---\0 ",
"\x01P\x02-..-\0 ",
"\x01Q\x02--.-\0 ",
"\x01R\x02-.-\0 ",
"\x01S\x02...\0 ",
"\x01T\x02-\0 ",
"\x01U\x02..-\0 ",
"\x01V\x02...-\0 ",
"\x01W\x02.--\0 ",
"\x01X\x02-..-\0 ",
"\x01Y\x02-.--\0 ",
"\x01Z\x02--..\0 ",
"\x01Ñ\x02--.--\0 "};

char Signos[7][maxlendefinition]={ // Tabla de definicion de las Letras

"\x01 \x02 \0 ", // Espacio
"\x01,\x02.-.-.-\0 ", // Coma
"\x01?\x02--..--\0 ", // Interrogación
"\x01=\x02-...-\0 ", // Igual
"\x01-\x02-....-\0 ", // Guión
"\x01/\x02-..-.\0 ", // Barra
"\x01@\x02.--.-.\0 "}; // Arroba


#int_rda // Declaración de Interrupción ...
void rda_handler() { // Manejador de la interrupción recepcion USART

  CharRcv=0; // Inicializo caracter a recibir
  Command=COMMAND_NULL; // Inicializo comando para main
  if(kbhit()){ // Si hay algo pendiente de recibir ...
    CharRcv=getc(); // lo recibo sobre RecRcv.
    if(CharRcv!=0){ // Si no es un \0 ...
      recbuffer[nextc]=CharRcv; // lo copio en el buffer, ...
      if(CharRcv==0x0D){ // Si he recibido un [Intro] 0x0D 13 ...
        recbuffer[nextc]='\0'; // Sustituyo el 0x0D en recbuffer por el terminador \0
        Command=COMMAND_PROCESS; // lo copio sobre command para procesarlo en main
      } else {
        putc(CharRcv); // lo envío de vuelta como eco y continuo ...
      }
      if(++nextc==lenrecbuffer){ // Y si despues de incrementar nextc es igual a lenrecbuffer ...
        nextc=0; // lo vuelvo a poner a cero
      }
    }
  }
}

void limpia_recbuffer(void){

  int i; // Declaro variable de índice

  for(i=0;i!=lenrecbuffer;i++){ // Bucle de 0 a lenrecbuffer
    recbuffer[i]='\0'; // Pongo a \0
  }
  nextc=0;
}

void wait_nperiodos(int n){ // Rutina que espera n peridos

  int x; // Declaro variable de índice

  for(x=0;x<n;++x){ // Bucle de n periodos
    delay_ms(periodo); // Espero un periodo en milisegundos
  }
}

char morse_parse_char(char* mistring){ // Rutina que extrae el Caracter de la tabla de definiciones
                                       // Entrada : Puntero a la definicion Devuelve: Caracter pulsado
  return mistring[1]; // Devuelvo el segundo caracter de la tabla

}

char* morse_parse_code(char* mistring){ // Rutina que extrae el código Morse de la tabla
                                        // Entrada: Puntero a la definicion, Devuelte: Puntero al codigo
  int i,j=0; // Declaro variables de indices para copiar ...
  char c=' '; // Caracter a procesar uno a uno
  char result[maxlendefinition]; // Buffer para el resultado

  for(i=3;i<maxlendefinition,c!='\0';i++,j++){ // Bucle que comienza en el caracter 3º y termina al \0 ó en Mñáxima longitud
    c=mistring[i]; // Tomo los caracteres uno a uno ...
    result[j]=c; // y lo copio en el resultado
  }
  result[j]='\0'; // Finalizo el string del resultado con el estandar \0
  return result; // Devuelvo el resultado

}

void morse_rs232(char* mistring){ // Rutina que monitoriza el código Morse extraído
                                  // Entrada : Puntero a la definicion
  char crtr; // Variable para el Carácter pulsado
  char* code; // Puntero a la Variable con el Código correspondiente

  crtr = morse_parse_char(mistring); // Extraigo el caracter pulsado de la definicion
  code = morse_parse_code(mistring); // Extraigo el codigo morse correspondiente a ese caracter

  printf("%c -> %s\r\n",crtr,code); // Lo envio a la RS232
}

void morse_light_punto(void){

  output_High(PIN_E1); // Enciendo Led1 -> Puntos y Led0 -> Completo
  output_High(PIN_E0);
  wait_nperiodos(1); // Espero 1 x "periodo" de puntos
  output_Low(PIN_E1);
  output_Low(PIN_E0); // Apago Led1 -> Puntos y Led0 -> Completo
  wait_nperiodos(1); // Espero 1 "periodo" de separacion entre puntos y rayas

}

void morse_light_raya(void){

  output_High(PIN_E2); // Enciendo Led2 -> Rayas y Led0 -> Completo
  output_High(PIN_E0);
  wait_nperiodos(3); // Espero 3 x "periodo" de rayas
  output_Low(PIN_E2);
  output_Low(PIN_E0); // Apago Led2 -> Rayas y Led0 -> Completo
  wait_nperiodos(1); // Espero 1 "periodo" de separacion entre puntos y rayas
}

void morse_lights(char* mistring){ // Rutina que enciende los Led's de la RRBOARD2

  char* code; // Puntero a la Variable con el Código correspondiente
  int i; // Declaro variable de indice para procesar ...
  char c=' '; // Caracter a procesar uno a uno e inicializo en blanco

  code = morse_parse_code(mistring); // Extraigo el codigo morse correspondiente a ese caracter

  for(i=0;i<maxlendefinition-3,c!='\0';i++){ // Bucle que recorre el contenido de code hasta \0
    c=code[i]; // Tomo los caracteres a representar uno a uno ...
    switch(c){
      case ' ': wait_nperiodos(5); // Espero 5 x "periodo" ( espacio entre palabras)
                break;
      case '.': morse_light_punto();
                break;
      case '-': morse_light_raya();
               break;
    }
  }
}

void morse_process(char* mitext){

  int i,x,y,z; // Variables indice de ratreo de mitext, índice relativas
               // a las tablas y al caracter recibido
  char xdefinition[maxlendefinition]; // Buffer para seleccionar la definicion correspondiente
  char c=' '; // Caracter a procesar uno a uno e inicializo en blanco

  for(i=0;i<lenrecbuffer,c!='\0';i++){
    // Cargo siguiente caracter a procesar
    c=mitext[i];
    if(c!='\0'){
      // Inicializo índices de tablas a un valor imposible
      x=0xff;
      y=0xff;
      z=0xff;
      // Letras Minúsculas, las convierto a mayúsculas
      if( (c>'a'- 1) && (c<'z'+ 1)){
        c = c - 'a' + 'A';
      }
      // Letras Mayúsculas, calculo el índice en la tabla según su código ASCII
      if( (c>'A'- 1) && (c<'Z'+ 1)){
        x = c-'A';
      }
      // Letras Especiales, puestas a güebo
      if( (c=='Ñ') || (c=='ñ')){ // Ñ
        x =26;
      }
      // Números, calculo el índice en la tabla según su código ASCII
      if( (c>'0'- 1) && (c<'9'+ 1)){
        y = c-'0';
      }
      //Signos y puntuación, puestos a güebo
      if(c==' ') z = 0; // Espacio
      if(c==',') z = 1; // Coma
      if(c=='?') z = 2; // Interrogación
      if(c=='=') z = 3; // Igual
      if(c=='-') z = 4; // Guión
      if(c=='/') z = 5; // Barra
      if(c=='@') z = 6; // Arroba
      // Guardo en el buffer de main la definicion correspondiente a lo pulsado
      if(x < 255){sprintf(xdefinition,"%s",Letras[x]);}
      if(y < 255){sprintf(xdefinition,"%s",Numeros[y]);}
      if(z < 255){sprintf(xdefinition,"%s",Signos[z]);}
      // Presenta y/o suena (Ahora solo presenta)
      morse_rs232(xdefinition);
      morse_lights(xdefinition);
    }
  }
}

void on_reset(){

  disable_interrupts(global); // Deshabilito todas las interrupciones
  disable_interrupts(int_timer1); // Deshabilito ...
  disable_interrupts(int_rda);
  disable_interrupts(int_ext);
  disable_interrupts(int_ext1);
  disable_interrupts(int_ext2);

  setup_adc_ports(NO_ANALOGS); // Configuro todo lo que voy
  setup_adc(ADC_OFF); // a usar y lo que no ...
  setup_spi(FALSE);
  setup_psp(PSP_DISABLED);
  setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  setup_timer_0(RTCC_OFF);
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  setup_timer_2(T2_DISABLED,0,1);
  setup_timer_3(T3_DISABLED);
  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);
  port_b_pullups(FALSE);
  set_tris_e(0b00010000);
  set_tris_c(0b10000000);
  enable_interrupts(global); // Habilito todas las interrupciones (que esten habilitadas)
  enable_interrupts(int_rda); // Habilito la interrupcion por recepcion USART

  delay_ms(333); // Espero 333 milisegundos a que todo se estabilice

  printf("\r\n"); // Me presento como deben hacer todos los PIC's de
  printf("Morse with 18F4550 in RRBOARAD2"); // buena familia
  printf("\r\n");
  printf(" v.%s by Redpic\r\n\n\n",Version);

  output_High(PIN_E0); // Enciendo los tres Led's de la RRBOARD2
  output_High(PIN_E1);
  output_High(PIN_E2);
  wait_nperiodos(lapsus/periodo); // Espero lo que indica "lapsus" expresado en unidades de "periodo"
  output_Low(PIN_E0);
  output_Low(PIN_E1);
  output_Low(PIN_E2); // Apago los tres Led's de la RRBOARD2
  wait_nperiodos(lapsus/periodo);
  limpia_recbuffer(); // Limpio el buffer de recepción
}

void main(){

  On_reset();

  do{ // Bucle Infinito

    if(Command!=COMMAND_NULL){

      if(Command==COMMAND_PROCESS){ // COMMAND_PROCESS : Convierte a Morse el contenido de recbuffer
        printf("\r\n\n"); // Paso una linea en el monitor rs232
        morse_process(recbuffer); // Mando procesar el contenido de recbuffer
        printf("\r\n"); // Paso otra linea en el monitor rs232
        limpia_recbuffer(); // Limpio el buffer de recepción
        Command=COMMAND_NULL; // Limpio el ultimo comando procesado
      }
    }
  }while(TRUE);
}
  
 
 

Descargar _morse_232.c

 

 

 

 

 

 

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 : 7907 Hoy: 1 Activas: 1 Vistas: 7907

Esta página fue modificada el 07-08-2010 22:42:20

           
 DmSoft WAMP Escribir Unreal