USANDO EL PUERTO SERIAL CON MATLAB 7

 

Sucedió que necesité recibir y enviar datos por el puerto serial. Dado que mis aproximadamente 40 líneas de script se los copiaron un montón de gente de la facu, decidí liberar el código (el 90% en realidad) y hacer este pequeño tutorial:

Para configurar el puerto serial, antes de enviar o recibir data, se debe copiar esto al archivo .m (este código me lo pasó un profesor):

clear all;
close all;
clc;

PS=serial('COM1');
set(PS,'Baudrate',9600); % se configura la velocidad a 9600 Baudios
set(PS,'StopBits',1); % se configura bit de parada a uno
set(PS,'DataBits',8); % se configura que el dato es de 8 bits, debe estar entre 5 y 8
set(PS,'Parity','none'); % se configura sin paridad
set(PS,'Terminator','CR/LF');% “c” caracter con que finaliza el envío 
set(PS,'OutputBufferSize',1); % ”n” es el número de bytes a enviar
set(PS,'InputBufferSize' ,1); % ”n” es el número de bytes a recibir
set(PS,'Timeout',5); % 5 segundos de tiempo de espera

fopen(PS);

El dispositivo que envía o recibe los datos (como un Pic o un DSP) debe transmitir o recibir a la misma velocidad que el programa de Matlab (o viceversa) en este caso: 9600 baudios, y enviando un bit a la vez. 

Con la instrucción "fopen" se abre el puerto. 

Para leer datos binarios se usa la instrucción:  variable = fread(PS,1,'uint8');

Esto le dice al Matlab como qué tipo de datos se interpretan los bits que se están recibiendo. Los tipos de datos pueden ser enteros sin signo, enteros con signo, de punto flotante, de 8 bits, de 16 bits, etc. (para más información consultar el archivo de Ayuda de Matlab).

Si el dispositivo, como un pic, está mandando códigos Ascii, se debe poner:

variable= fread(PS,1,'uchar');

"variable" almacenará un número que corresponde al código Ascii del caracter recibido. Si es la 'A', "variable" almacenará el número 65. Para convertir a caracter se hace: variable= char(variable); 

Una vez utilizado el puerto, éste se debe cerrar:

fclose(PS);
delete(PS);
clear PS;

Si no se hace esto, al querer correr nuevamente el programa, nos botará error.

Y ahora, una función que yo hice y que me fue muy útil:

function h=convertir(hh);
q=quantizer('fixed','max',0.9999998,'min',-1,'format',[16 15],'round','wrap');
hexh=num2hex(q,hh);
h=hex2dec(hexh);

Lo que hace esta función es convertir los bits de un dato con coma flotante de 32 bits a uno de tipo entero sin signo de 16 bits (así tenía que hacerse porque así recibía los datos el dispositivo conectado al puerto serial), la información de estos bits se mantiene, pero lo que cambia es cómo lo interpreta el Matlab y cómo los transmite al puerto serial. Cuando le ponía entero con signo, en lugar de un 7FFF transmitía un FFFF, para ahorrarme esos problemas de conversión programé esta función y declaré el tipo de datos a transmitir como entero sin signo. El dispositivo que recibía los bits en este caso fue un DSP Motorola. (muchas veces es mejor trabajar con datos tipo enteros sin signo o char sin signo, que con datos de coma flotante o con bit de signo).

El programa que hace la transmisión es éste:

h=convertir(h);

PS=serial('COM1');
set(PS,'Baudrate',9600); % se configura la velocidad a 9600 Baudios
set(PS,'StopBits',1); % se configura bit de parada a uno
set(PS,'DataBits',8); % se configura que el dato es de 8 bits, debe estar entre 5 y 8
set(PS,'Parity','none'); % se configura sin paridad
set(PS,'Terminator','CR/LF');% “c” caracter con que finaliza el envío 
set(PS,'OutputBufferSize',2); % ”n” es el número de bytes a enviar
set(PS,'InputBufferSize' ,2); % ”n” es el número de bytes a recibir
set(PS,'Timeout',5); % 5 segundos de tiempo de espera

fopen(PS);
fwrite(PS,2,'uint16');

for i=1:1000
end;

for j=1:length(h)
fwrite(PS,h(j),'uint16');
end;

fclose(PS); 
delete(PS);
clear PS;

Como se notará, este programa envía dos bytes cada vez. "h" es un vector. para enviar más de un dato es necesario un bucle. El Matlab ya se encarga de la velocidad de transmisión y las esperas entre dato y dato a medida que se ejecuta el bucle. Se ve que hay un bucle vacío. En la práctica, con ese DSP Motorola, era necesario un pequeño retardo en la transmisión, por eso le metí un bucle vacío (es probable que otros dispositivos no lo necesiten, el número 2 que se envía inicialmente era un aviso al DSP que llegaban los datos, esto ya lo hice acorde a cómo mi compañero El Giove lo programó).

Para leer varios datos desde el puerto serial, datos del tipo char, hice el siguiente programita, el cual recibía los datos desde un pic, las condiciones eran que cada cuatro bytes hacían una muestra de una señal capturada desde un sensor. Si el sensor registraba 2.03 el pic enviaba los caracteres '2' '.' '0' '3' los que el Matlab lee como sus respectivos códigos Ascii: 50 46 48 51:

clear all;
close all;
clc;

PS=serial('COM1');
set(PS,'Baudrate',9600); % se configura la velocidad a 9600 Baudios
set(PS,'StopBits',1); % se configura bit de parada a uno
set(PS,'DataBits',8); % se configura que el dato es de 8 bits, debe estar entre 5 y 8
set(PS,'Parity','none'); % se configura sin paridad
set(PS,'Terminator','CR/LF');% “c” caracter con que finaliza el envío 
set(PS,'OutputBufferSize',1); % ”n” es el número de bytes a enviar
set(PS,'InputBufferSize' ,1); % ”n” es el número de bytes a recibir
set(PS,'Timeout',5); % 5 segundos de tiempo de espera

fopen(PS);

K1= [];


for j=1:4
K1 = [K1 fread(PS,1,'uchar')];
end;

K1=char(K1);
K1= str2num(K1);

fclose(PS);
delete(PS);
clear PS;
INSTRFIND

La función str2num es para convertir la cadena '2' '.' '0' '3' en el número 2.03 con el cual ya se puede operar.

Para recibir todo un vector de una señal capturada a través de un sensor se hace:

clear all;
close all;
clc;

PS=serial('COM1');
set(PS,'Baudrate',9600); % se configura la velocidad a 9600 Baudios
set(PS,'StopBits',1); % se configura bit de parada a uno
set(PS,'DataBits',8); % se configura que el dato es de 8 bits, debe estar entre 5 y 8
set(PS,'Parity','none'); % se configura sin paridad
set(PS,'Terminator','CR/LF');% “c” caracter con que finaliza el envío 
set(PS,'OutputBufferSize',1); % ”n” es el número de bytes a enviar
set(PS,'InputBufferSize' ,1); % ”n” es el número de bytes a recibir
set(PS,'Timeout',5); % 5 segundos de tiempo de espera

fopen(PS);

K1= [];
K= [];


for i=1:lo_que_dure_el_muestreo

for j=1:4
K1 = [K1 fread(PS,1,'uchar')];
end;


K1=char(K1);
K=[K str2num(K1)];

K1=[];

end;

fclose(PS);
delete(PS);
clear PS;
INSTRFIND

La señal se va acumulando en el vector K. K1 sólo recoge cada cuatro caracteres (una muestra). 

 

Acerca de INSTRFIND: Esta instrucción nos dice el estado del puerto serial. Siempre debe estar cerrado una vez finalizado el programa que lo utiliza. Si el puerto está cerrado, INSTRFIND nos botará:

 

Si el puerto está abierto, nos botará: 

 

O cualquier otra información acerca del puerto o puertos que se hayan abierto.