MONTAJE
Osciloscopio por USB de 40MHz Séptima Parte:
Estructura del Software Continuando con la explicación paso a paso del funcionamiento e implementación de un osciloscopio de 40MHz para utilizarlo en una computadora, a través de su puerto USB, estamos en condiciones de comenzar a describir el software empleado. Aclaramos que estamos realizando la descripción com pleta de este equipo desde hace varias edi ciones y que ya publicamos los temas refe rentes al hardware y firmeware del equipo. En esta oportunidad indicaremos cómo es la estructura del software.
Por: Pablo Hoffman y Martín Szmulewicz http://www.pablohoffman.com Introducción Tenemos que realizar la implementación del software, que es la aplicación utilizada en el PC para controlar el osciloscopio. Incluye información sobre el diseño, selección de las herramientas, métodos de programación empleados, estructura del código e funcionamiento del software. La primera decisión a la hora de desarrollar la aplicación para controlar el osciloscopio fue la selección de las herramientas a utilizar, en particular:
demasiado al desarrollo de este trabajo. Sin embargo, quienes deseen descargar el trabajo completo y todas las notas publicadas en saber Electrónica, pueden dirigirse a nuestra web: www.webelectronica.com.ar, haciendo click en el ícono password e ingresando la clave: “oscusb”. También puede contactar al autor a través de la página dada al comienzo de este artículo.
Toolkit Gráfico
El lenguaje de programación a usar. En cuanto al toolkit gráfico la decisión no fue tan senEl toolkit gráfico (librería para el manejo de ventanas cilla. Las bindings más populares disponibles para python y creación de la interfaz gráfica). son: Las librerías a utilizar para controlar diversos aspec tos de la aplicación. o tkInter - para trabajar con el toolkit tk. El entorno de desarrollo a utilizar para crear la aplica o GTK+ - utilizando los bindings PyGTK. ción gráfica. o qt - utilizando los bindings PyQt. o wxWidgets - utilizando los bindings wxPython No derscribiremos las razones que nos llevaron a la tkinter. elección del software por considerar que no contribuye
Saber Electrónica 60
Estructura del Software de un Osciloscopio de 40MHz Tk es el toolkit nativo de python para trabajar con interfaces gráficas, pero la razón de esto es que era el mejorcito que existía en el momento que python fue diseñado, y de eso hace mucho tiempo. Tk tiene dos grandes desventajas: requiere mucho código para implementar cosas simples y además no es muy presentable. Por estas razones, tkinter fue descartado inmediatamente. GTK+ A través de los bindings PyGTK se puede utilizar el popular toolkit GTK+ de la Free Software Foundation. Sin embargo lo descartamos por las siguientes razones: o GTK no es muy lindo estéticamente en Windows. o GTK no tiene implementación para Mac OS X. o GTK no tiene un buen entorno rápido de desa rrollo (RAD) para el diseño de ventanas.
Lenguaje de programación Para tomar la decisión del lenguaje a utilizar para la elaboración del sofate del software gráfico que se instalará en el PC para el control del osciloscopio desarrollado se han tenido en cuenta los siguientes requisitos: 1. Debe tener interfaz gráfica. 2. Debe ser multi-plataforma (Windows, Linux, Mac OS X). 3. Debe ser de rápido desarrollo. 4. Debe poder comunicarse con puertos virtuales de Windows (para hablar con el driver RS232-USB de CDC de Microchip) de forma sencilla. 5. Debe ser un lenguaje gratuito que no requiera de licencias para compilar o distribuir el código compilado. El lenguaje que seleccionamos para programar la aplicación fue python, ya que es un lenguaje robusto y extremadamente portable (multi-plataforma, requisito 2) puesto que existen interpretadores para todas las plataformas, dos de las cuales (Linux y Mac OS X) ya lo traen incluido dentro del propio sistema operativo. Además, es un lenguaje interpretado lo cual elimina los tediosos ciclos de edición-compilación-enlazado-ejecución y permite un desarrollo rápido y ágil (requisito 3). Por eso es comúnmente utilizado en el prototipado de aplicaciones, y lo hace ideal para nuestro caso. Además python cuenta con una extensión llamada pySerial que permite el acceso transparente a puertos series (virtuales o reales) de Windows y, a la vez, a puertos series en linux, lo cual nos permite desentendernos
del problema de la comunicación (requisito 4). Otras aplicaciones como Java, si bien son portables, exigen más tiempo de diseño e implementación (pues el lenguaje es más estricto) y requieren tener instalada una máquina virtual Java (JRE o JDK) en la máquina del cliente donde se vaya a correr la aplicación. Al hacerlo en python se puede evitar esa restricción compilando la aplicación para que corra nativamente en cada arquitectura y sistema operativo. La plataforma “.Net” de Microsoft no es portable para sistemas operativos fuera de windows y además su licencia tiene algunas restricciones respecto al código generado con ella, por lo cual fue descartada inmediatamente.
Clases Dado que “python” es un lenguaje preferentemente orientado a objetos, el software se compone de varias clases, las cuales a su vez contienen métodos que son las funciones encargadas de implementar las diferentes funcionalidades. A continuación se presenta un resumen de las mismas. Las clases que componen el software son las siguientes: Osc La clase Osc es la encargada de la comunicación con el osciloscopio. Implementa el protocolo de comunicación proveyendo primitivas para el envío y recepción de comandos al osciloscopio. El constructor de la clase acepta como parámetro el puerto serie donde se encuentra el osciloscopio. Las funciones de esta clase son: Clase Osc connect() intenta conectarse al osciloscopio. Devuelve TRUE en caso de lograrlo, o FALSE en caso contrario. getVersion() devuelve la versión de firmware del osciloscopio. getPort() devuelve el puerto por el cual se encuentra conectado el osciloscopio. getData() devuelve los datos obtenidos por el último comando de datos (ej. AQHI, AQME, AQLO). getSample() se bloquea hasta recibir un byte del osciloscopio y, una vez recibido, lo devuelve. Utilizado para capturas de baja velocidad en tiempo real. stop() envía un comando STOP al osciloscopio y limpia el buffer de entrada. acquire(type, chan, vdv1, vdv2, dual, chop) solicita una captura de datos al osciloscopio. Una vez finalizada la misma retorna TRUE (si la captura fue exitosa) o FALSE si hubo algún error. Para obtener los datos capturas usar la función getData().
Saber Electrónica 61
Montaje Los parámetros que acepta esta función son los siguientes: * type - el tipo de captura a realizar (AQHI, AQME, AQLO). * chan - el canal a utilizar (1 ó 2). * vdv1 - el divisor vertical a usar en el canal 1 (0, 1, 2 ó 3). * vdv2 - el divisor vertical a usar en el canal 2 (0, 1, 2 ó 3). * dual - habilita (1) o deshabilita (0) el modo dual. * chop - habilita (1) o deshabilita (0) el modo chop. debug() escribe en un archivo el texto pasado como parámetro. Utilizado para dejar un registro de la comunicación con el osciloscopio con fines depurativos. send(cmd, param, retry) envía un comando al osciloscopio. Los parámetros que acepta son: * cmd - el comando a enviar (string de 4 carac teres, obligatorio). * param - el parámetro del comando (número entero, opcional). * retry - indica si debe reintentar enviar el comando en caso de error (por defecto es TRUE). disconnect() se desconecta del osciloscopio. Frame1 La clase Frame1 es la encargada de desplegar la ventana del osciloscopio en pantallas, así como también de llevar a cabo todas las funciones de interacción con el usuario. Las funciones de esta clase son las siguientes: cleantrigger() aplica el trigger por software descartando las muestras irrelevantes del principio. triggerlevelup() rutina que implementa el algoritmo de trigger por software. Es utilizada por la función cleantrigger. updatevalues() actualiza los parámetros numéricos de la señal (voltaje medio, voltaje pico-pico y voltaje eficaz) updatefft() actualiza los análisis espectrales de las señales. updatedivs() actualiza los valores seleccionables de divisiones de voltaje para la vista actual (en modo dual separado dichos valores se duplican). updatetriggers() actualiza los valores seleccionable de los triggers de voltaje. updatezeros() actualiza el nivel de los ceros en el display del osciloscopio. Dicho nivel depende del modo dual y de si se está utilizando etapa de entrada. savetofile() guarda las muestras recibidas en el archivo especificado en la interfaz gráfica. acqstart() inicia el proceso de captura de datos. Es ejecutada al activar el botón de captura. acqstop() detiene el proceso de captura. Es ejecutada
Saber Electrónica 62
al desactivar el botón de captura. connectosc() intenta conectarse al osciloscopio barriendo todos los puertos disponibles en la PC. Devuelve TRUE si pudo conectarse, o FALSE en caso contrario. doconnect() se conecta al osciloscopio utilizando la función connectosc() y actualiza los controles de la aplicación según la conexión hayá sido exitosa o no. Además de las funciones ya mencionadas, esta clase tiene otras rutinas especiales que son disparadas por eventos de la aplicación, desde la pulsación de un botón hasta la llegada de los datos del osciloscopio. En particular, las más importantes son las siguientes: OnOscDisplayPaint() es disparada cuando el display necesita actualizarse, ya sea porque la ventana se movió o porque llegaron nuevas muestras del osciloscopio. OnAqcuireData() es disparada cuando llegan nuevos datos del osciloscopio. Se encarga de actualizar todos los displays y valores a través de las funciones update*. AcquireThread La clase AcquireThread es la encargada de llevar a cabo la captura de datos. Corre en forma paralela a la clase Frame1 y se comunica con ésta a enviándole mensaje, los cuales también son clases (AcquireEvent). Esta clase tiene una única función (run()) en donde se realiza la comunicación con el osciloscopio (a través de la clase Osc) y se ejecuta toda la lógica necesaria para procesara una nueva secuencia de muestras del osciloscopio. AcquireEvent La clase AcquireEvent es el tipo de objeto utilizado para el transporte de las muestras del osciloscopio entre la clase AcquireThread y la clase Frame1. Por consiguiente, carece de funciones. Archivos La estructura del código fuente es bastante simple y consta de los siguientes archivos: oscapp.py - este es el código que dispara toda la aplicación. Es el que llama a la ventana (ver clase Frame1) para controlar el programa oscframe.py - aquí está el código que define el comportamiento, la apariencia y el funcionamiento de la ventana de la aplicación. En este archivo se encuentran implementadas las clases: Frame1, AcquireThread y AcquireEvent osc.py - aquí se encuentra el código de comunicación con el osciloscopio. En este archivo está implementada la clase Osc setup.py - este archivo no es código del progama, sino que son las directivas utilizadas para compilar el programa en Windows utilizando el compilador py2exe. ✪
Montaje
Saber Electr贸nica 63