Control de Dispositivos Por USB
Short Description
Download Control de Dispositivos Por USB...
Description
Control de dispositivos mediante el puerto USB: Desarrollo de proyectos en Visual C# Moyano Jonathan 2011
PIC18F2550 Control de dispositivos mediante el puerto USB: Desarrollo de proyectos en Visual C#
Autor: Moyano Jonathan Año: 2011
INTRODUCCIÓN: En este manual veremos como crear una pequeña aplicación en Visual C# y CCS para poder controlar dispositivos USB usando el microcontrolador PIC18F2550. Este apartado no pretende ser una explicación completa del funcionamiento del puerto USB, sino una guía para poder crear aplicaciones de manera rápida. Como elemento hardware usaremos la placa de desarrollo USB trainer v0.1, desarrollada para este curso en particular. Esta herramienta está diseñada para usarse en conjunto con el programador PicKit2. Las características de la placa son las siguientes: -
4 pulsadores NA usados para simular las entradas digitales. 4 Led’s verdes de 3mm para simular las salidas digitales. 2 potenciómetros multivuelta de 10K para simular entradas analógicas. 2 Led’s de alta luminosidad para las salidas PWM. 1 Led bicolor para indicar el estado de conexión al puerto USB. 1 Conector USB hembra tipo B. 1 Puerto ICSP para la programación. 1 cable ICSP de 10cm para la conexión al programador.
Con esto ya podemos empezar a crear una aplicación demo o aplicación de prueba, con la que demostraremos como comunicar nuestra placa con la PC mediante USB. Todas las aplicaciones que escribiremos son compatibles y fueron testeadas con Windows 7 y Windows XP, así también como versiones intermedias.
2
Introducción a Visual C#: Como habíamos dicho anteriormente, diseñaremos una aplicación para la PC en visual C#. Para esto debemos tener instalada la suite Visual Studio 2008 o en su defecto Visual C# 2008 Express. Para el desarrollo de este curso usaré Visual Studio 2008, que es la herramienta que tengo a mano. Visual C# Express es la versión gratuita del programa la cuál podemos descargarla directamente de la página de Microsoft. Una vez instalado el programa procederemos a crear nuestro proyecto. Al abrir Visual Studio 2008, nos tendría que quedar una ventana como la Fig. nº1:
A simple vista podemos ver el menú superior, el cuadro de herramientas a la izquierda, el explorador de soluciones a la derecha y el cuadro de errores, mensajes y advertencias abajo. Para poder crear un nuevo proyecto de Visual C#, nos dirigimos hacia Archivo – Nuevo Proyecto. Una vez realizado esto, nos aparecerá una ventana con los diferentes tipos de lenguajes disponibles y los tipos de aplicaciones que se pueden llegar a crear con ellos. También aparecerá al costado derecho, la plataforma de trabajo elegida, a la que conocemos por Framework. En mi proyecto usaremos .Net Framework 3.5.
3
En la Fig. nº 2, podemos apreciar los tipos de proyectos que se pueden crear con Visual C#.
Como podemos ver, hemos elegido el tipo “Aplicación de Windows form” y le agregamos un nombre. Luego de aceptar, nos quedará la ventana como se ve en la Fig. nº 3:
Ahora tenemos listo nuestro proyecto para empezar a trabajar, pero antes lo guardaremos en caso de alguna eventualidad. Para ello presionaremos sobre el botón Guardar todo; cuando nos aparezca el cartel para guardar tenemos que elegir la carpeta donde se guardará y quitar la opción que dice: Crear directorio para esta solución. 4
Fig. nº 4:
Lo primero que vamos hacer es configurar el espacio de diseño para poder trabajar cómodos. Lo que haremos será dejar fija la barra de herramientas para tenerla siempre a mano como lo muestra la Fig. nº 5:
Ya tenemos todo listo para empezar a programar, pero antes veremos un poco del entorno de trabajo de visual C#. Al principio necesitamos ver donde introduciremos código de programación, para esto podemos usar 3 formas: - Hacer doble clic sobre el control o formulario. - Presionar con el botón derecho del Mouse sobre el control o formulario y seleccionar “Ver código” - Pulsar “Ver código” en el explorador de soluciones como lo muestra la Fig. nº 6:
5
Algo que usaremos muy a menudo para crear “La interfaz gráfica” será el llamado cuadro de herramientas el cuál podemos ver en la Fig. nº 7.
En el cuadro de herramientas se encuentran los controles que podemos arrastrar hacia el formulario para crear nuestra aplicación. Las herramientas se dividen en 2 grupos principalmente: Las que forman parte de la interfaz de usuario ya sean botones, cuadros de texto, etc. Y las que ofrecen funcionalidad pero no son visibles en tiempo de ejecución tales como timer’s, procesos en 2º plano, etc. 6
El explorador de soluciones que vimos más arriba sirve para administrar archivos, proyectos y configuraciones de la aplicación. El cuadro de propiedades que vemos en la Fig. nº 8 sirve para modificar propiedades y eventos de los controles que se encuentran en la interfaz de usuario.
Para compilar o ejecutar el programa nos acostumbraremos a usar la tecla de acceso rápido F5. También podemos dirigirnos hacia depurar – iniciar depuración, con el mismo resultado. Con esto damos por finalizado la introducción al ambiente de trabajo. Ahora comenzaremos con el diseño del programa.
Diseño de la interfaz de usuario: La primera acción que realizaremos será tomar 4 GroupBox del cuadro de herramientas y los añadiremos al formulario. No importa el orden, a medida que vallamos avanzando los iremos configurando. En este momento tiene que quedar como lo muestra la Fig. nº 9:
7
Ahora, a cada uno de los elementos creados les cambiaremos el nombre. Por ejemplo al primer Groupbox, llamado groupBox1, le pondremos “SALIDAS DIGITALES” correspondiente al control que contendrá los botones que activarán o desactivarán las salidas digitales del entrenador. Para poder cambiar el nombre del control pulsamos con el botón derecho sobre el mismo y hacemos clic en propiedades. Dentro del cuadro de propiedades del groupBox1, modificamos los siguientes parámetros:
Parámetro
Valor
Name Text
CONTENEDOR_SALIDAS SALIDAS DIGITALES
Lo mismo con los demás Groupbox. Para el grouBox2.
Parámetro
Valor
Name Text
CONTENEDOR_IN_DIGITALES ENTRADAS DIGITALES
Para el grouBox3.
Parámetro
Valor
Name Text
CONTENEDOR_ANALOGICAS ENTRADAS ANALOGICAS 8
Para el grouBox4.
Parámetro
Valor
Name Text
CONTENEDOR_PWM CONTROL PWM
Una vez que se han modificado los parámetros de todos los controles nos tiene que quedar el formulario como se ve en la Fig. nº 10:
Ahora ya tenemos los contenedores listos, por lo tanto, hay que empezar a añadir los controles asociados a esos contenedores. Primero agregamos los botones correspondientes a las salidas digitales, quedándonos una ventana como la que se ve en la Fig. nº 11:
9
En total tenemos que insertar 4 Buttons de la barra de herramientas y ordenarlos de modo tal que coincidan con la anterior imagen. Ahora, hay que modificar sus parámetros al igual que hicimos con los contenedores. Como tenemos 4 salidas digitales representadas por 4 led’s, nombraremos los botones de la siguiente manera:
-
Salida 1 Salida 2 Salida 3 Salida 4
Hacemos clic derecho sobre los botones y en las propiedades de cada uno cambiamos los siguientes parámetros: Para el button1.
Para Parámetro Text Font (Name)
Valor SALIDA 1 Microsoft Sans Serif, 8,25pt, style=Bold OUT_DIGITAL_1
Para el button2.
Para Parámetro Text Font (Name)
Valor SALIDA 2 Microsoft Sans Serif, 8,25pt, style=Bold OUT_DIGITAL_2
Para el button3.
Para Parámetro Text Font (Name)
Valor SALIDA 1 Microsoft Sans Serif, 8,25pt, style=Bold OUT_DIGITAL_3
10
Para el button4.
Para Parámetro Text Font (Name)
Valor SALIDA 4 Microsoft Sans Serif, 8,25pt, style=Bold OUT_DIGITAL_4
Cada uno de estos botones comandará una salida del entrenador USB. Nuestra aplicación, luego de las modificaciones tendría que quedar como muestra la Fig. nº 12.
Para las entradas digitales, incluiremos 4 PictureBox, los mismos nos indicarán mediante un cambio en su color si un interruptor ha sido presionado. Una vez añadidos los controles, el formulario tendría que quedar como muestra la Fig. nº 13:
11
Ya ordenados los diferentes PictureBox, procedemos a modificar sus parámetros. Para el PictureBox 1.
Parámetros
Valor
(Name) BorderStyle BackColor Para el PictureBox 2.
IN _ DIGITAL_1 FixedSingle DarkSeaGreen
Parámetros
Valor
(Name) BorderStyle BackColor Para el PictureBox 3.
IN _ DIGITAL_2 FixedSingle DarkSeaGreen
Parámetros
Valor
(Name) BorderStyle BackColor Para el PictureBox 4.
IN _ DIGITAL_3 FixedSingle DarkSeaGreen
Parámetros
Valor
(Name) BorderStyle BackColor
IN _ DIGITAL_4 FixedSingle DarkSeaGreen
Con todos los parámetros configurados, el formulario tendría que tener el siguiente aspecto: Fig. nº 14
12
Para las entradas analógicas, utilizaremos 2 barras de progreso llamadas ProgressBar, que me indicarán el valor que presenta la salida del CAD (Convertidor analógico – digital). Fig. nº 15
Este es el aspecto del formulario con los controles añadidos. Ahora, hay que configurar 2 parámetros básicos para poder utilizarlos. Para el ProgressBar 1:
Parámetros
Valor
(Name) Maximum
ADC1_VALUE 1024
Para el ProgressBar 2:
Parámetros
Valor
(Name) Maximum
ADC2_VALUE 1024
El valor 1024, dentro del parámetro “Maximum”, significa el valor máximo que puede tomar el control y coincide con la resolución máxima de 10 bits del CAD (Convertidor analógico digital). Por último, nos queda el control de PWM (Pulse Width Modulation), que consiste en 2 barra de desplazamiento llamadas HSscrollBar. A través de este control, podremos controlar el ciclo de trabajo de los 2 PWM definidos por software. 13
Esto quiere decir que tendremos la capacidad de variar el tiempo Ton (Tiempo en que la señal PWM está en alto) y el tiempo Toff (tiempo en que la señal PWM está en bajo). Por lo tanto controlaremos la potencia aplicada y en consiguiente el brillo de los led’s PWM, según el valor que tome la barra de desplazamiento. Los 2 PWM definidos por software tienen una resolución máxima de 8 bits. Esto nos da 255 valores de brillo diferente para los led’s. Por lo que la barra tiene que tomar un valor que no supere 255; este valor lo configuraremos en los parámetros de dicho control. Fig. nº 16
Para el hsScrollBar 1. Parámetros (Name) Maximum Para el hsScrollBar 2. Parámetros (Name) Maximum
Valor PWM_CONTROL_1 255 Valor PWM_CONTROL_2 255
Además de los controles que ya hemos visto, necesitamos 2 elementos más dentro de la aplicación: Un botón para conectar el dispositivo (hardware USB), con la aplicación de control y un cuadro de texto donde se muestren los diferentes eventos que ocurran dentro y fuera de la aplicación. Por lo comentado anteriormente, agregaremos un ListBox y un Button de la barra de herramientas, con lo que el formulario nos quedaría de la siguiente manera:
14
Fig. Nº 17
Como podemos ver, hemos redimensionado los demás controles para obtener una mejor estética final de la aplicación. Los parámetros de los nuevos controles son los siguientes: Para el button.
Parámetros
Valor
(Name) Text
CONECTAR _ DISPOSITIVO CONECTAR DISPOSITIVO
Para el ListBox.
Parámetros
Valor
(Name) Backcolor
MENSAJES_USB 255, 255, 128 (Amarillo)
Por último para darle un mejor aspecto al formulario, vamos a configurarle los siguientes parámetros: Parámetros (Name) Backcolor FormBorderStyle Text StartPosition MaximizeBox Icon
Valor USB_HID 224, 224, 224 (Gris plateado) FixedSingle USB HID Demo CenterScreen False Elegimos un icono predeterminado 15
Finalmente la Interfaz de usuario nos tendría que quedar como muestra la Fig. nº 18:
Aún faltan controles por agregar pero no afectan a la funcionalidad del programa por lo que podemos empezar a introducir código de programación.
Programación de la Interfaz de usuario: En esta parte del manual, veremos como agregarle funciones a los controles creados previamente. Lo primero que tenemos que hacer es agregar la clase easyHID.cs al proyecto de Visual C# que habíamos creado antes. A través de ella podremos llamar a las diferentes funciones de control que se encuentran en easyHID.dll, una librería proporcionada por la empresa MecaniqueUK para el control de dispositivos USB mediante protocolo HID. Para poder agregar la clase tenemos que agregar al directorio donde se encuentra nuestro proyecto 2 archivos: - mcHID.dll (Librería de control). - easyHID.cs (Clase con las funciones de control definidas).
16
En la Fig. nº 19, vemos como quedan agregados ambos archivos a nuestro proyecto:
Ahora que los archivos están incluidos a la carpeta del proyecto tenemos que agregarlos a nuestro entorno de trabajo. Para esto hacemos clic en Proyecto – Agregar nuevo elemento existente. Fig. nº 20
Una vez que anexamos la clase y la librería al proyecto ya podemos trabajar con ellas. En este momento hacemos clic derecho sobre el formulario y ponemos ver código; nos tendría que quedar algo así:
17
Fig. nº 21
Hemos agregado algunos elementos de código que están comentados en verde. Los mismos son necesarios para poder usar las funciones incluidas en la librería mcHID.dll. En este momento ya estamos listos para poder comenzar a escribir las funciones de control, pero antes vamos a echar un vistazo a la clase donde están definidas las diferentes funciones. Explicaremos el código paso por paso para un mejor entendimiento del mismo.
Acá tenemos 4 constantes fundamentales en la comunicación con el dispositivo USB; las 2 primeras identifican el dispositivo mediante 2 valores VendorID y ProductID. Los mismos son proporcionados por el fabricante (MecaniqueUK) y deben coincidir con el descriptor de dispositivo en el firmware para poder entablar la comunicación mediante USB. Las otras 2 constantes, BUFFER_IN_SIZE y BUFFER_OUT_SIZE, indican el tamaño del buffer del reporte de entrada y del reporte de salida.
18
Acá definimos los mensajes que obtenemos del controlador HID cuando ocurre un evento. Más abajo tenemos las llamadas a las diferentes funciones incluidas en la librería mcHID.dll. Entre ellas podemos destacar las siguientes:
Conecta la aplicación al controlador.
Desconecta la aplicación del controlador.
Leemos el reporte de entrada para ver si hay datos provenientes del dispositivo. El tamaño del reporte dependerá de la constante BUFFER_IN_SIZE. La función retorna 1 si hay datos disponibles para leer y 0 si no los hay.
Escribimos un reporte de salida con los datos almacenados en la variable pData, que es un puntero a un buffer no administrado. El tamaño del reporte dependerá de la variable BUFFER_OUT_SIZE. La función retorna 1 si se ha podido enviar el reporte y 0 en el caso contrario.
A través de estas funciones obtenemos el vendorID y el productID del dispositivo.
Activamos el servicio de notificaciones para recibir mensajes cada vez que se produce un evento de lectura. El servicio se activa una vez que el dispositivo ya se ha conectado al controlador.
A través de esta función obtenemos el estado de conexión del dispositivo mediante el vendorID y el productID.
19
Con esto ya hemos explicado todas las funciones que se usarán en el programa. Ahora veremos el desarrollo de 2 de ellas: Write y Read, correspondientes a las funciones para leer y escribir datos.
Esta función lee el reporte de entrada para ver si hay datos disponibles. En primera instancia asigna memoria con un tamaño igual a BUFFER_IN_SIZE a un puntero:
Se utiliza el método Marshal, para poder trabajar con memoria no administrada. Luego guarda el retorno de la función Read en la variable result, que corresponde a la presencia de datos en el reporte de entrada.
A través del método try, crea un buffer llamado pData. Como es una porción de memoria no administrada, usa Marshal nuevamente y copia los datos usando el puntero creado con anterioridad en el buffer pData, quedando los datos del reporte guardados en este último.
Como el espacio de memoria que al que hacía alusión el puntero no se utiliza más y es memoria no administrada, usamos Marshal para liberarla para otros procesos.
Finalmente la función retorna con el valor que haya tomado result.
20
Esta función escribe un dato en el reporte de salida. En primer instancia es igual que la función anterior, salvo que la variable result se le asigna un valor luego de copiar los datos en el reporte de salida; para poder indicar si los datos se han escrito correctamente. Ahora que ya tenemos la clase easyHID.cs explicada, comenzamos con el núcleo principal del programa. Anteriormente comentamos que para saber si el dispositivo estaba conectado/desconectado o enviando datos, necesitábamos leer los diferentes mensajes que entregaba el controlador. Para este fin incluimos dentro de la clase principal el siguiente código.
Esta función toma los mensajes de Windows, los procesa y según el valor que tomen podemos realizar diferentes acciones. Por ello crearemos 3 funciones:
21
- Dispositivo _ conectado (En caso que el dispositivo esté conectado al host) - Dispositivo _ desconectado (En caso de que desconectemos el dispositivo) - Lee _ dispositivo (Si se recibe el mensaje de que hay datos disponibles) El parámetro de cada una de las 3 funciones se da según el mensaje que se recibe por parte del controlador, con lo cuál la función que mostramos más arriba queda de la siguiente manera.
Ahora tenemos que crear las 3 funciones dentro de la clase principal:
Con esto, cada vez que se produzca una notificación podremos realizar diferentes acciones en consecuencia. Las 3 funciones las desarrollaremos más adelante ahora nos encargaremos de los controles principales. Primero trabajaremos sobre el control Conección_USB. El mismo nos permitirá conectar la aplicación al controlador y a su vez el dispositivo a dicho controlador. Para añadir el código necesario haremos doble clic sobre el botón y nos tiene que aparecer la siguiente función, asociada al evento “clic” del mismo:
22
Ahora es momento de añadirle los elementos de la función:
Vemos el uso del método try – match y la función:
A través de ella conectamos la aplicación al controlador y a su vez el controlador al dispositivo. Para poder ver si realmente estamos conectados con el entrenador USB hacemos uso de la función:
Con esto podemos detectar cualquier dispositivo conectado que coincida con el VID, PID declarado en la aplicación.
Ahora es momento de ejecutar nuestro programa por primera vez, para esto conectamos el entrenador al host, pulsamos F5 y hacemos clic en el botón “conectar dispositivo”. Nos tendría que quedar como muestra la Fig. nº 22: 23
Vemos que al pulsar el botón “conectar dispositivo”, busca el dispositivo y nos muestra el VID, PID del mismo. Si ahora lo desconectamos y volvemos a presionar sobre el botón “conectar dispositivo”, veremos la Fig. nº 23:
Podemos apreciar que la aplicación se ha conectado con el controlador (mcHID.dll), pero no ha logrado encontrar el dispositivo USB. 24
Ya tenemos el primer control funcional dentro del programa. Ahora es el turno del control de las “salidas digitales” el cuál, mediante el uso de 4 botones cambiará el estado de 4 led’s dentro del entrenador USB. Para comenzar, hacemos clic en cada uno de los 4 botones asignados al control de salidas digitales. Con lo cuál nos quedará el siguiente código:
Las 4 funciones corresponden a los eventos que se producen al hacer clic en cada uno de los botones. Ahora agregaremos algunos trozos de código para enviar un comando de control y otro de datos hacia el dispositivo USB. Con el fin de manejar los led’s de salida.
En primera instancia la función crea un buffer llamado “BufferOUT”. El mismo guardará todos los datos que se enviarán en el reporte de salida. Primero enviamos el comando correspondiente al control de salidas: 0x0A. Luego enviamos el dato que corresponde al cambio de estado del led 1 del entrenador USB: 0x10. 25
Para enviar el reporte de salida usamos la función explicada anteriormente: easyHID.Write. Como podemos ver, dentro de la función que envía el reporte de salida hay un parámetro que no hemos visto en detalle:
“Controlador”, se refiere al controlador de salida el cuál se activa cuando el dispositivo está conectado al host. Como no sabemos cuando el dispositivo está o no conectado, hacemos uso de los mensajes que entrega Windows en la función:
Precisamente en el evento “NOTIFY_PLUGGED” es donde se detecta la conección de un dispositivo al host y se procesa el mensaje mediante la función:
En la clase principal creamos la variable global, controlador para poder acceder al handle en cualquier parte del programa.
Ahora agregaremos el código necesario para poder activar el controlador de entrada/salida.
Con esto ya podemos enviar o recibir desde y hacia el dispositivo USB. Anteriormente habíamos agregado código al botón de la salida 1, por lo tanto ahora haremos lo mismo con los demás botones.
26
Ahora pulsaremos F5, conectaremos el dispositivo y cambiaremos el estado de cada uno de los 4 indicadores led que se encuentran en el entrenador. Al hacer clic en cada uno de los botones, la función enviará un mensaje de notificación indicando el cambio de estado de los led’s. Como lo muestra la Fig. nº 24:
27
Para ver mejor como trabaja la aplicación pueden ver el video: Prueba de funcionamiento Nº 1, anexado a la carpeta del manual. Al próximo control al cuál nos enfocaremos serán las entradas digitales. Para esto tenemos que trabajar sobre la función: La misma responde al evento “NOTIFY_READ”, el cuál se activa en cuanto hay datos procedentes del dispositivo para ser leidos. Vamos a agregar código dentro de la función que nos permita indicar de forma gráfica y textual si un pulsador del entrenador USB ha sido presionado.
28
Como se puede apreciar usamos la función easyHID.red para leer el reporte de entrada. Según los datos que se reciben se activan los indicadores correspondientes y se entregan mensajes de confirmación. Luego de agregar el código que se muestra más arriba conectamos el dispositivo USB y presionamos F5. Una vez que el dispositivo está conectado presionamos los 4 botones que tiene el entrenador y veremos como cambian de color los indicadores del programa mientras se reciben los mensajes de confirmación. Para ver mejor como trabaja la aplicación pueden ver el video: Prueba de funcionamiento Nº 2 anexado a la carpeta del manual.
Otro elemento presente en nuestra aplicación, es el control de PWM. El mismo nos permite variar el ciclo de trabajo de 2 PWM implementados por software en el firmware. Para poder insertar código en dichos controles, hacemos doble clic en las barras de desplazamiento con lo cuál nos tendría que quedar las siguientes funciones dentro del código principal:
En estas 2 funciones se toma el valor de las barras de desplazamiento y se envía al dispositivo para controlar el ciclo de trabajo de los PWM y poder variar el brillo de los led’s PWM que se encuentran en el entrenador USB. Ambos PWM tienen una resolución máxima de 8 bits. Esto se debe a que a mayor resolución se necesita mayor velocidad de refresco; al utilizar PWM por software la señal inyectada a los led’s puede ser inestable debido a la cantidad de procesos que se ejecutan dentro del programa principal del PIC. 29
En una posible actualización se podría usar PWM por hardware lo que nos daría más resolución sin perder estabilidad en la señal generada.
Para ver mejor como trabaja la aplicación pueden ver el video: Prueba de funcionamiento Nº 3, anexado a la carpeta del manual. En este momento solo falta un control para programar: Las entradas analógicas. Para mostrar el valor que toma el CAD (convertidor analógico – digital), tenemos 2 barras de progreso ADC1_Valor y ADC2_Valor. Las mismas muestran de forma gráfica el valor de voltaje presente en los pines de las entradas analógicas. Ambas barras de progreso pueden tomar un valor máximo de 1024, correspondiente al valor máximo que puede tomar la lectura del CAD. Que tiene una resolución máxima de 10 bits. En la próxima imagen vemos el código agregado a la función lee _ dispositivo ().
Ahora conectamos el dispositivo, presionamos F5 y hacemos clic en “conectar dispositivo”. En este momento nos tendría que aparecer en la barra de progreso el valor de voltaje presente en los pines analógicos. Para poder ver mejor el efecto, variamos el valor de los potenciómetros y veremos como cambia el valor mostrado en las barras. Para ver mejor como trabaja la aplicación pueden ver el video: Prueba de funcionamiento Nº 4 anexado a la carpeta del manual. En este punto ya hemos visto todos los procesos que se realizan con el dispositivo conectado. Una vez que el dispositivo se desconecta, hay que cerrar la comunicación con el controlador. Vamos a agregar código a la función:
La misma actúa en consecuencia cuando se ha desconectado el dispositivo del host. 30
Añadimos las siguientes sentencias de código a la función:
Con este código, cada vez que el dispositivo USB se desconecta del host, se desconectará del controlador y nos notificará el evento mediante un mensaje. Hay que agregar también la función easyHID.disconect () en el evento form_closed, ya que al cerrarse el programa no necesitaremos estar enlazados con el controlador. En el siguiente trozo de código lo mostramos:
Ahora que ya tenemos todos los controles en funcionamiento, mejoraremos la estética y añadiremos algunas funciones extras a la aplicación.
Lo primero que haremos será definir 2 funciones. Una de ellas habilitará los controles cuando conectemos el dispositivo y la otra desactivará los controles cuando lo desconectemos.
La primera función se activará en cuanto el dispositivo se haya conectado, por lo tanto será llamada desde:
La segunda función se activará en cuanto iniciemos la aplicación o el dispositivo se haya desconectado del host, por lo tanto será llamada desde:
31
Ahora añadimos código para ver su funcionamiento:
32
En este momento ya tenemos nuestra aplicación funcional, por lo que procederemos a añadir los controles faltantes al formulario. Primero a través de la herramienta MenuStrip, agregamos un menú llamado opciones y otro llamado ayuda. El formulario tendría que quedar como muestra la Fig. nº 25:
Dentro del menú opciones creamos la función “salir” y dentro del menú ayuda: - “Acerca de HID Demo” - “Web del proyecto” - “Manual de usuario” El menú de ayuda es un menú informativo para que el usuario se guíe dentro del programa además de presentar información relativa al autor, información de contacto, etc. Con lo anterior la apariencia de la aplicación nos tiene que quedar como muestra la Fig. nº 26 y 27:
33
Ahora comenzaremos a añadir código para hacer funcionales dichos elementos. Primero que nada hacemos doble clic en “Salir” e introducimos el siguiente código:
A través de esta función, nos desconectamos del controlador y cerramos el programa. Podemos agregarle teclas de acceso rápido. Para esto modificamos el siguiente parámetro:
Parámetros
Valor
ShortCutKeys
Control+ S
Con esto el formulario nos queda como muestra la Fig. nº 28:
Yéndonos al menú ayuda tenemos la primera función “Acerca de HID Demo”. Hacemos clic en ella y agregamos las siguientes sentencias.
Este código mostrará una ventana informativa sobre el creador del programa, contacto, licencia, etc. 34
Podemos agregarle teclas de acceso rápido. Para esto modificamos el siguiente parámetro:
Parámetros
Valor
ShortCutKeys
F1
Si ejecutamos la aplicación y presionamos F1, aparecerá la siguiente ventana: Fig. nº 29
Luego hacemos doble clic en “Web del proyecto” y agregamos el siguiente código:
Para agregarle teclas de acceso rápido. Para esto modificamos el siguiente parámetro:
Parámetros
Valor
ShortCutKeys
Ctrl+W
Finalmente hacemos doble clic en “Manual de usuario” y agregamos el siguiente código:
35
En este código, trata de abrir el manual de usuario de la aplicación. En caso de no poder, muestra un mensaje alternativo de advertencia como el que está a continuación. Fig. nº 30
Para agregarle teclas de acceso rápido, modificamos el siguiente parámetro:
Parámetros
Valor
ShortCutKeys
Ctrl+A
Con esto ya tenemos nuestro menú creado y funcional. Ahora añadiremos de la barra de herramientas el elemento “StatusStrip”. Con esto el formulario tendría que quedar como muestra la Fig. nº 31:
Dentro del elemento podemos ver un menú desplegable allí elegimos el control llamado “StatusLabel” y le modificamos el siguiente parámetro:
Parámetros
Valor
Text
hh:mm:ss
A través de este control mostraremos la hora en formato: horas : minutos : segundos Para poder realizar esto añadimos un “timer” de la barra de herramientas y le cambiamos el siguiente parámetro: 36
Parámetros
Valor
Interval
1000
El valor parámetro interval nos indica la frecuencia con la cuál el componente se actualiza, en este caso 1000 ms (mili segundos) o un segundo. Para poder obtener la hora hacemos doble clic sobre el timer y le agregamos el siguiente código:
Y dentro del evento:
El siguiente código:
Con esto la aplicación ya muestra la hora una vez que se inicializa: Fig. nº 32
37
Como podemos ver le hemos añadido algunos indicadores adicionales a los controles para mejorar el aspecto visual del mismo, como así también redimensionamos algunos controles. Un último control funcional que tendremos que agregar a la aplicación será un ToolTip. Este control muestra información cuando se pasa el puntero del Mouse sobre el control asociado. Una vez que lo arrastramos desde la barra de herramientas, le añadimos el siguiente código:
Finalmente lo que nos queda por hacer es añadirle un icono al programa y modificar la información de ensamblado para agregar información personal. Para este fin nos dirigiremos hacia: Fig. nº 33
Dentro de la pestaña aplicación tenemos que modificar algunos parámetros: 38
Fig. nº 34
Podemos ver varias cosas entre las que destaco las siguientes: - Nombre de ensamblado y espacio de nombres: Aquí pondremos el nombre de la aplicación. - Información de ensamblado: Información que se incrusta al programa compilado (.exe), respecto del autor, versión, fecha de ensamblado, revisión, etc. Fig. nº 35
39
- Por ultimo el icono y manifiesto que seleccionaremos del icono agregado a la aplicación previamente. Para ver como ha quedado la aplicación podemos presionar F6 y generar el archivo ejecutable que estará en la carpeta release, como lo muestra la Fig. nº 36:
En este punto hemos terminado con la aplicación para la PC y nos queda únicamente explicar el código del microcontrolador para terminar con la guía.
Introducción al compilador CCS: En este apartado no explicaremos como programar en C, sino como crear una aplicación funcional a partir de conocimientos previos en programación. Explicaremos los puntos clave a tener en cuenta con el firmware del microcontrolador. Como compilador utilizaremos el CCS v4.114, ya que ofrece una gran facilidad en el uso de las librerías USB. El entorno de trabajo del CCS permite compilar y también suministra una gran variedad de herramientas auxiliares. En la Fig. nº 37, se muestran los distintos elementos básicos del entorno de trabajo. Existen 2 formas de iniciar una sesión: abriendo un fichero de código fuente o creando un proyecto. 40
Para abrir un fichero fuente directamente se realiza una pulsación sobre el icono para el manejo de ficheros (Fig. nº 38) y aparece un menú donde podemos crear, abrir, guardar o cerrar ficheros. Con el comando New podemos crear un fichero fuente, un proyecto, un fichero RTF o un fichero de diagrama de flujo.
Con la opción New –> Source file, el programa pide el nombre del nuevo fichero y crea una nueva ventana en blanco donde podemos empezar a escribir, como lo muestra la Fig. nº 39.
41
Una vez explicado esto, procederemos a crear nuestra aplicación de control.
Programación del firmware para el microcontrolador: Lo primero que haremos será cargar el firmware, que ya escribí, en el editor de CCS Fig. nº 40.
42
Una vez que ya tenemos el archivo cargado, vamos bajando y vemos la primer sentencia de código:
A través de la misma introducimos en nuestro programa la definición de registros internos del PIC18F2550, que es el microcontrolador usado en el entrenador USB. Con esto le decimos al compilador que trabajaremos con un PIC18 y que use el modo PCH (compilador para micros de 16 bits). Más abajo tenemos la siguiente línea de código:
A través del uso de esta directiva, le decimos al compilador que trabajaremos con el CAD (Convertidor analógico a digital) con 10 bits de resolución y justificación a la derecha (Los bits más significativos del registro ADRESH, son leídos como “0”).
Los “fuses” (o mejor dicho palabra de configuración) son muy importantes ya que determinan muchos parámetros del microcontrolador. Los que se encuentran ordenados en la figura anterior tienen las siguientes funciones: -
-
NOMCLR: No usaremos el pin MCLR, utilizaremos reset por software. HSPLL: Utilizaremos un cristal de alta velocidad en conjunto con el PLL. NOWDT: No utilizaremos el perro guardián. NOPROTECT: No protegeremos la memoria contra lecturas. NOLVP: No habilitaremos la programación con bajo voltaje. NODEBUG: No utilizamos código para debug. USBDIV: Significa que el reloj del módulo USB se tomará de la salida del PLL\2. En este caso 96Mhz \ 2 = 48Mhz (Frecuencia de trabajo). PLL5: Esto quiere decir que el prescaler dividirá en 5 la frecuencia del oscilador principal para obtener los 4Mhz necesarios en la entrada del PLL. Como estamos usando un cristal de 20Mhz….20Mhz \ 5 = 4Mhz. CPUDIV1: La frecuencia del PLL se dividirá en 2 para obtener la frecuencia de trabajo del CPU: 48Mhz. VREGEN: Habilitamos el regulador interno de 3.3v del módulo USB. NOPBADEN: Todo el puerto B como entradas/salidas digitales.
Ahora ya tenemos la palabra de configuración explicada, por lo que procederemos con la siguiente sentencia: Acá declaramos la frecuencia de trabajo para que el compilador pueda calcular los retardos en las funciones de delay. 43
Usando la directiva #include agregamos todas las librerías necesarias para gestionar la comunicación USB. Por el momento explicaremos 2 de ellas: - APLICACIÓN_HID.h - Descriptor_easyHID.h En la primera guardamos todas las definiciones de hardware, constantes, declaración y documentación de funciones, etc.
A través del uso de etiquetas #define le añadimos nombres a las entradas y salidas para poder facilitar la programación y recordar donde se ubican los diferentes componentes.
Definimos el tamaño que debe tener el edpoint de entrada y de salida, en este caso el valor “32” nos indica que recibirá 32 bytes desde el host y transmitirá 32 bytes hacia el host. Para dejar bien en claro el significado de endpoint, les dejo el siguiente enunciado: "Los dispositivos (o mejor dicho, las funciones) tienen asociados unos canales lógicos unidireccionales (llamados pipes) que conectan al host (PC) controlador con una entidad lógica en el dispositivo (PIC) llamada endpoint. Los datos son enviados en paquetes de largo variable (potencia de 2). Típicamente estos paquetes son de 64, 128 o más bytes. Estos endpoints (y sus respectivos pipes) son numerados del 0 al 15 en cada dirección, por lo cual un dispositivo puede tener hasta 32 endpoints (16 de entrada y 16 de salida). La dirección se considera siempre desde el punto de vista del host controlador. Así un endpoint de salida será un canal que transmite datos desde el host controlador al dispositivo. Un endpoint solo puede tener una única dirección. El endpoint 0 (en ambas direcciones) está reservado para el control del bus."
44
La cita anterior fue extraída del trabajo de grado que se encuentra en el siguiente link: http://pablohoffman.com/oscusb/doc/
Estas definiciones está íntimamente ligadas con las funciones de control que se encuentran en la aplicación de Visual C# estudiada anteriormente. Esto lo veremos más adelante.
Estos macros son usados para el control de las salidas digitales para no tener que usar las funciones predefinidas más costosas de recordar. Ayudan al desarrollo del programa. Luego hay 2 funciones más, pero su explicación es redundante ya que están muy bien documentadas en la librería. Siguiendo con el programa principal tenemos las siguientes funciones:
Estas 2 directivas nos permiten utilizar los puertos sin necesidad de configurarlos cada vez que se usan. Lo que si debemos tener en cuenta es configurar que pines serán entradas y que pines serán salidas usando las siguientes sentencias:
Una vez configurados los puertos pueden usarse libremente los que nos ahorra RAM y ROM dentro una vez que compilamos el programa.
45
Esta función ya se encuentra explicada en la librería, pero dentro de ella tiene una sentencia que no ha sido desarrollada.
Esta función se encuentra dentro de la librería: USB.c, lo que hace es esperar hasta que el host enumere el dispositivo y prender el LED verde. En caso de que no lo hiciera el dispositivo no puede comunicarse con la aplicación de control y el LED rojo permanece encendido.
Esta función pertenece al usuario Palitroquez del foro TODOPIC. La misma configura correctamente el ADCON2 como se explica en la librería: APLICACIÓN_HID.h Adentrándonos en la función principal main (), tenemos las siguientes funciones:
A través de estas sentencias configuramos correctamente el CAD.
Con estas 2 sentencias inicializamos los 2 PWM y apagamos los led’s asociados.
Una función muy importante ya que inicializa el stack USB, conecta el dispositivo al host, habilita las interrupciones, etc. Trabaja en conjunto con USB stack; esta función asume que el USB está conectado siempre al host, por lo que mantiene al dispositivo permanentemente conectado.
46
Esta función inicializa el hardware USB, las interrupciones, etc. Trabaja en conjunto con USB_init (). En caso de usar USB_init_cs (), hay que llamarla periódicamente desde el main (), pero normalmente se llama una sola vez.
Esta función la utilizamos como indicador si el dispositivo está o no conectado al host. En caso de que no esté enumerado el programa no avanza y no nos podemos comunicar con la PC. Ya dentro del bucle infinito que se muestra a continuación, todas las funciones que se encuentren dentro del mismo se ejecutarán indefinidamente.
Aquí miramos el estado de la función usb_enumerated (), la misma nos indica si el dispositivo está o no conectado. En caso de que si lo esté ejecuta las sentencias que se explicarán a continuación:
Estas 2 funciones son idénticas y nos permiten controlar el ciclo de trabajo de ambos PWM. La variable ValorPWMx_H, corresponde al semiciclo positivo de la señal y la variable ValorPWMx_L, al semiciclo negativo. Modificando el valor de ambas variables según el valor que se reciba de la PC, podemos modificar el ciclo de trabajo, por lo tanto la potencia aplicada a los led’s PWM (modificamos el brillo de los mismos).
47
Estas 4 sentencias son idénticas, lo que hacen es ver el estado de los pulsadores y enviar guardar el valor en el buffer “envía”.
Ambos grupos de sentencias son iguales, lo que hacen es lo siguiente, enumerado para una mejor comprensión: -
Elegimos un canal de conversión. Esperamos 10us. Guardamos la parte alta de la conversión en la variable valor_adc_alta. Guardamos la parte baja de la conversión en la variable valor_adc_baja. Asignamos la parte alta al 4º bit del arreglo “envía”. Asignamos la parte baja al 5º bit del arreglo “envía”.
Esta función envía el arreglo de datos “envía” hacia el host para luego poder visualizar los datos en la aplicación. La función tiene 4 parámetros que enumeraremos para un mejor entendimiento: 1º parámetro: endpoint usado, en este caso el endpoint 1. Para su mejor entendimiento remitirnos a la explicación que está en la pág. 44. 2º parámetro: variable que contiene los datos a enviar, en este caso es el buffer “envía”. 3º parámetro: Tamaño del arreglo que contiene los datos a enviar: 32. 4º parámetro: sincronismo de datos.
48
Al principio se ejecuta un bucle condicional, el mismo se fija, mediante la función que tiene asociada si hay datos en el endpoint indicado. En este caso dentro del paréntesis hay indicado un “1”, refiriéndose al endpoint 1. En caso de que haya datos provenientes del host para leer, los tomamos y guardamos usando la función usb_get_packet. La misma tiene 3 parámetros: 1º parámetro: endpoint usado. Usamos el endpoint 1. 2º parámetro: variable donde se guardarán los datos provenientes del host. 3º parámetro: tamaño del paquete a recibir. Una vez tomados los datos del host los procesaremos como muestran las siguientes funciones:
Acá tenemos 2 bucles condicionales, primero si recibimos el comando: ACTIVA _ SALIDAS, vemos el primer byte del arreglo “recibe”. Según sea el dato recibido, activamos el led en consecuencia. Para darnos una idea de como trabaja la aplicación con el hardware vamos a poner la función:
49
Vemos que la función envía el comando para activar los led’s y luego el dato correspondiente al led 1. Cuando el PIC los recibe, cambia el estado del led 1 como muestra la sentencia de código:
Para el caso de los PWM se cumple lo mismo: Se recibe el comando de control, recibe el valor procedente de las barras de desplazamiento y lo guarda en las variables que contienen el ciclo de trabajo.
Con esto ya hemos visto tanto la aplicación para la PC, como el firmware para el microcontrolador y estamos listos para poder crear nuestras propias aplicaciones a partir de la guía. Algo que habíamos omitido hasta el momento es la explicación del hardware utilizado. Aunque su utilización sea sencilla vale la pena detallar como está compuesto, además es necesario nombrar los elementos que lo componen para un mejor entendimiento del mismo.
50
Entrenador USB v0.1: Como elemento hardware para el desarrollo de esta guía usaremos un entrenador de bajo costo diseñado para comprender el funcionamiento del puerto USB y posibles aplicaciones de control. El entrenador también puede ser usado para aprender a programar debido a que posee los periféricos básicos que se usan en los entrenadores estudiantiles. Para tener una vista general del hardware utilizado, miremos la Fig. nº 41.
En la imagen podemos ver la distribución de todos los elementos de la placa. Un punto a tener en cuenta es el conector ICSP, que está específicamente diseñado para usarlo con el PicKit2. En la Fig. nº 42, vemos la distribución de pines de dicho conector y la comparamos con el conector del PicKit2 de la Fig. nº 43.
51
El nombre de cada pin es el siguiente: -
Pin 1: Vpp (Voltaje de programación). Pin 2: Vdd (Voltaje de alimentación: desde el programador). Pin 3: Gnd (Negativo o tierra). Pin 4: PGD (Señal de datos desde/hacia el programador). Pin 5: PGC (Señal de reloj desde/hacia el programador).
Como podemos ver es la misma distribución de pines que el PicKit2:
Por último podemos ver el diseño del circuito impreso y el esquema de nuestro entrenador USB en las Fig. nº 44 y 45 respectivamente:
52
Con esto damos por terminada nuestra guía, espero les sirva. Un saludo !
53
54
55
View more...
Comments