| |
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.
|
|
|
|
|
|
|
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.
|
|
|
-
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
|