Aplicación - Gianluque/Osciloscopio GitHub Wiki

Introducción

La aplicación de osciloscopio se realizó mediante la guía de matlab “guide” o G.U.I. (Graphic User Interface) y consta de 2 partes principales que son el código de ejecución de la aplicación (en un archivo de texto con extensión .m) y una figura (en un archivo de extensión .fig).

La figura es la imagen que mostrará el osciloscopio al ejecutarse o en otras palabras, la interfaz que será accesible al usuario mientras que el código es el cuerpo de la aplicación que no es accesible al usuario ni se puede cambiar durante la ejecución de la aplicación.


El código consta de multiples funciones que se ejecutan de forma automática como interrupciones o al abrir y cerrar la aplicación. Estas funciones se pueden repartir en las siguientes 4 partes principales:

  1. Una inicialización del objeto puerto serial de matlab y de las variables globales a usar en la aplicación que se realiza en la función de apertura de la aplicación “Osciloscopio_20_OpeningFcn” que se ejecuta antes del resto del código automaticamente.
  2. La interrupción o “callback” de la función graficar “Graficar_Callback” que se ejecuta al pulsar el botón de graficar de la aplicación e inicia un ciclo constante que actualiza los datos leidos y los grafica dependiendo del estado de las otras funciones de la aplicación.
  3. Interrupciones o callbacks de creación y cambio de estado para cada una de las otras funciones del código.
  4. El llamado o solicitud de cierre de la aplicación o función “Osciloscopio_CloseRequestFcn” que automáticamente elimina el objeto correspondiente al puerto usado para poder tenerlo disponible de nuevo en caso de querer volver a abrir la aplicación.

Parte 1: Inicialización de variables

En la función “Osciloscopio_20_OpeningFcn(hObject, ~, handles, varargin)” se declaran las variables a utilizar en la aplicación. Por la estructura predefinida por matlab para GUI el código de la aplicación consta de funciones que son independientes pero pueden interactuar entre si lo que hace necesarias variables globales que puedan ser compartidas por varias funciones. La declaración de estas variables sigue, en general, la siguiente sintáxis:

%Variables utilizadas en la Aplicacion
 
%Bases de Amplitud
global Amplitud_ch1;
global Amplitud_ch2;
Amplitud_ch1=1;
Amplitud_ch2=1;

Es decir, una declaración de la variable como global (global Amplitud_ch1;) seguida de su inicialización de valor (Amplitud_ch1=1). Estas variables se deben declarar de nuevo en cada función que deba acceder a ellas o modificarlas como es el caso de la función de callback ejecutada al presionar el boton de graficar de la interfaz. Como se puede ver en la función “Graficar_Callback(~, ~, handles)” justo después del seteo de parámetros propios de la función, se “declaran” nuevamente las variables globales que la misma necesita para operar. Sin embargo, en este caso no se inicializan de nuevo.

%Variables globales a usar
global puerto;
global Amplitud_ch1;
global Amplitud_ch2;
global dac;
global time;
global ch1_plot;
global ch2_plot;
global digit_1;
global digit_2;

Las variables declaradas en “Osciloscopio_20_OpeningFcn(hObject, ~, handles, varargin)” sirven para configurar: La base de tiempo a la que grafica el osciloscopio, la amplitud de cada canal, el número de puntos al mismo tiempo en la gráfica, un factor de conversión digital-analógico y un arreglo de recepción de valores para cada canal a graficar que inicialmente comienza lleno de ceros. Estas se encuentran agrupadas por propósito y comentadas dentro del código. Adicionalmente se declara y configura otra variable global u objeto que hace de puente entre el puerto serial de la computadora y la aplicación:

global puerto; %Crea el objeto puerto
puerto=serial('COM8','BaudRate',115200,'Terminator','LF');   %Configuracionde los parametros del puerto
fopen(puerto); %abre el puerto

Debe notarse que el nombre del puerto debe ser el mismo al que se conecte el DEMOQE (en nuestro caso 'COM8') o no se recibirán datos. De igual forma el baudrate debe coincidir con el usado en el protocolo de comunicación requerido para el muestreo deseado, es decir, el mismo que en el DEMOQE('BaudRate',115200,). La función “Osciloscopio_20_OpeningFcn(hObject, ~, handles, varargin)” es una función generada automáticamente por matlab que se ejecuta siempre con la apertura de la aplicación; por ello se escogio para incluir la delaración e inicialización de las variables necesarias para la operación del código general.

Parte 2: Callback a Graficar

En el desarrollo de GUI de matlab el equivalente a las interrupciones son los callbacks. Por ello para la ejecución de la aplicación se escogio el callback del boton graficar en la interfaz como cuerpo principal del código. Esto significa que, al presionar Graficar en la aplicación, se inicia el código escrito en la función “Graficar_Callback(~, ~, handles)”.

Esta función declara las variables globales y auxiliares a usar y luego inicia un ciclo “infinito” que se encarga de recolectar, desentramar y graficar los datos recibidos del microprocesador siguiendo los parámetros que el usuario indique mediante la interfaz gráfica; adicionalmente se encarga de “flushear” o limpiar cada cierto número de repeticiones los datos guardados en el objeto puerto para evitar graficar datos “viejos” y tener una gráfica en tiempo real.

Es importante notar que, por la manera en la que opera matlab, el botón Graficar se configuró en la interfaz “guide” del programa para aceptar callbacks o interrupciones. Esto significa que, si el usuario realiza un cambio en algun control de la GUI, cada vez que el ciclo grafica (cuando se ejecuta el comando drawnow) se interrumpe el ciclo y se ejecutan los callback que esten acumulados. El efecto obtenido es que al cambiar un parámetro en la interfaz este se ve reflejado rápidamente en la gráfica. La condición que mantiene el ciclo como “infinito” es la revisión del estado del selector On/Off en la GUI cuyo “handles” tendrá valor 1 para On y 0 para Off. Mientras el selector este en On el ciclo se repetirá indefinidamente.

Al iniciar el ciclo toma datos del objeto puerto, se les guarda en un “buffer” auxiliar aux tras lo cual se revisa cuantos ciclos van y de ser necesario limpia la memoria del puerto y se ejecuta un pequeño ciclo que busca la posición i del arreglo que corresponde al primer byte del primer paquete de 4 bytes de data recibida:

    %busqueda de inicio y adquisicion de bytes
    aux=fread(puerto,[1,buffersize],'uint8'); 
        %flush del puerto
    flush=flush+1;
    if flush>2
    flushinput(puerto)
    flush=0;
    end
    i=1;
    while aux(i)>127
        i=i+1;
    end  
    bin=dec2bin(aux);  

Luego se convierte el arreglo a binario para poder realizar su desentramado y se inicia un ciclo más que comienza desentramando un bytenuevo a graficar mediante la concatenacion de las partes específicas de los byte leidos para los canales analógicos y la extracción del bit de interés para los canales digitales.

       chauxAlog1= strcat(bin(i,3:8),bin(i+1,3:8));
       chauxdig1= bin(i,2); 
       chauxAlog2= strcat(bin(i+2,3:8),bin(i+3,3:8)); 
       chauxdig2= bin(i+2,2);

Como se ve en el código anterior esto se logra concatenando con la función strcat los últimos 6 bit del primer y segundo byte de cada paquete para el canal analógico 1 y del tercer y cuarto byte para el 2. De manera similar se toma el segundo bit del primer byte para el canal digital 1 y del tercer byte para el canal digital 2.

El resultado son cuatro datos nuevos para incluir en la gráfica de tiempo real para cada canal de interés.

Para generar el efecto "móvil" de una gráfica de osciloscopio estos datos se van añadiendo de a uno por ciclo a cada canal, y se realiza un shifteo de los arreglos auxiliares que se grafican. Como el shifteo de matlab es circular cuando el arreglo este lleno el primer dato vuelve a la primera posición y es sobreescrito por el dato nuevo que este entrando a la gráfica.

               %shifteo y actualizacion de canales
        digit_1 = circshift(digit_1,1);
        digit_2 = circshift(digit_2,1);
        digit_1(1)=bin2dec(chauxdig1)*Amplitud_ch1*dac;
        digit_2(1)=bin2dec(chauxdig2)*Amplitud_ch2*dac;    
        ch1_plot = circshift(ch1_plot,1);
        ch2_plot = circshift(ch2_plot,1);        
        ch1_plot(1)=bin2dec(chauxAlog1)*Amplitud_ch1*dac;
        ch2_plot(1)=bin2dec(chauxAlog2)*Amplitud_ch2*dac;

Es importante notar que los valores de los datos pasaron por una conversión analógica-digital en el microprocesador a una presición de 12 bits. Por ello antes de graficar los valores desentramados es necesario multiplicarlos por un factor que termina de regresar la conversión. En nuestro caso es el valor guardado en la variable global "dac" que se puede ver en el segmento de código superior.

Lo último que se ejecuta en el ciclo es una revisión del estado de los selectores de la interfaz que le dicen a la aplicación que canales se deben mostrar en la gráfica.

Parte 3: Creación y callbacks de las demás funciones del código

Al ser una aplicación realizada mediante la interfaz "guide" de matlab, esta genera de forma automática una función de creación para cada selector, imágen o botón que se incluya en la interfaz que verá el usuario. Estas no se modificaron porque se actualizan de manera automática por matlab al editar la figura .fig mediante la interfaz "guide" para configurar cada parte de la interfaz a coincidir con la figura editada.

Los callbacks de los selectores modifican sus valores que son revisados por los ciclos en la función de callback de Graficar para ajustar el estado de la aplicación como sea deseado. Sin embargo en los callback de los selectores de Amplitud de canal y de Base de Tiempo se incluyó código adicional que le da acceso a esos callback a las variables globales que configuran cada uno de esos parámetros y las modifican como sea necesario segun indique el selector.

Parte 4: Solicitud de cierre de la Aplicación

Al cerrar la aplicación es necesario que esta deje disponible el puerto serial utilizado porque si no este queda ocupado. Por ello en la función de solicitud de cierre de la aplicación "Osciloscopio_CloseRequestFcn(hObject, eventdata, handles)" se incluyó un segmento extra de código que de forma automática pone el selector de On/Off en el valor para Off, limpia los datos de los instrumentos (estos son los del puerto usado) y elimina el objeto de la aplicación correspondiente al puerto.

%Cerrado de la Aplicacion
function Osciloscopio_CloseRequestFcn(hObject, eventdata, handles)
set(handles.On_Off,'Value',2);
instrreset;
delete(hObject);
end

Esto evita errores al cerrar la aplicación y al intentar abrirla nuevamente o disponer el puerto serial de la computadora con otra aplicación tras cerrar el osciloscopio digital.

Debe notarse que esta función se ejecuta de manera automática al intentar cerrar la aplicación del osciloscopio digital independientemente del estado de cualquier selector o variable.