Está en la página 1de 16

USB_HID

MODO HID Este modo es el que utilizan los Mouse USB y los teclados USB, incluso hay ejemplos en la red para simular estos dispositivos, para este modo no es necesario instalar drivers en windows. Haremos un sencillo ejemplo, haremos encender y apagar un LED conectado al pin B0 del PIC, y en el PIC tendremos un botn conectado a B1, el cual al ser pulsado encender un Shape en el formulario de Visual Basic.

FORMULARIO VISUAL BASIC

CIRCUITO BASICO USB

PROGRAMACION: Comenzamos por explicar el cdigo en el PIC, para esto necesitamos el archivo hid 8byte el cual incluyo en el archivo que descargaron, este archivo es necesario para compilar el proyecto, en este archivo se encuentran definiciones para que el dispositivo sea reconocido por Windows, as como el nombre que queremos que se muestre al conectar el dispositivo en este caso USB_HID tambin tenemos el VID y el PID los cuales son los identificadores que reconoce Windows, en este caso el VID es 00461 y el PID es 00020 en el cdigo los marque en rojo para reconocerlos, noten que esta invertidos los bytes es decir en el VID en lugar de decir: 004, 061, dice: 061,004.

////////////////////////////////////////////////////////////////// /// /// start device descriptors

/// ////////////////////////////////////////////////////////////////// constchar USB_DEVICE_DESC[USB_DESC_DEVICE_LEN] ={ //starts of with device configuration. only one possible USB_DESC_DEVICE_LEN, //the length of this report ==1 001, //the constant DEVICE (DEVICE 001) ==2 010,001, //usbversionin bcd(pic167xx is 1.1) ==3,4 000, //class code ==5 000, //subclass code ==6 000, //protocol code ==7 USB_MAX_EP0_PACKET_LENGTH, //max packet size for endpoint 0. (SLOW SPEED SPECIFIES 8 ) ==8 061,004, //vendor id (0x04D8 is Microchip, or is it 00461 ??) 020,000,//product id ==11,12 //dont use ffffsays usb-by-example guy. oops 000,001, //device release number ==13,14 001, //index of string description of manufacturer. therefore we point to string_1 array (see below) ==15 002, //index of stringdescriptor of the product ==16 000, //index of stringdescriptor of serial number ==17 USB_NUM_CONFIGURATIONS //number of possible configurations ==18 };

Para cambiar el nombre del dispositivo debemos tener en cuenta varias cosas, la primera es la parte que puse en azul en ella se indica en donde estn los ndices de cada palabra que ponemos, pero lo que nos importa esta despus del ndice 4 que es la palabra Ezkybel y USB_HID por ejemplo la palabra Ezkybel tiene 7 letras pero como a toda letra le agregamos un 0( E,0,) entonces la longitud de esa palabra ser de 14 bytes y le sumamos 2 bytes mas por lo que nuestra palabra ser de 16 bytes, es por eso que {0,4,20} significa que la primer palabra de configuracin comienza en el ndice 0 y es: 009,004, luego la segunda palabra (Ezkybel) comienza en el ndice 4, y la tercera palabra USB_HID comienza en el ndice 20. char USB_STRING_DESC_OFFSET[ ={0,4,20}; char const USB_STRING_DESC[]={ //string 0 4, //length of string index USB_DESC_STRING_TYPE, //descriptor type 003 (STRING) 009,004, //Microsoft Defined for US-English //string 1 16, //length of string index USB_DESC_STRING_TYPE, //descriptor type 003 (STRING)

E,0, z,0, k,0, y,0, b,0, e,0, l,0, //string 2 16, //length of string index USB_DESC_STRING_TYPE, //descriptor type 003 (STRING) U,0, S,0, B,0, _,0, H,0, I,0, D,0,

la modificacion de este archivo solo es nesesaria para cuando queremos cambiar de VID y/o de PID pero pueden dejarla asi sin problema alguno. La programacion de su aplicacion esta en el archivo llamado USB_HID.c en el cual escribiran su programa especifico, ahi comente lo mas importante, pero aqui menciono las funciones mas importantes

//******************************************************************** // Ejemplo en USB HID // // www.wix.com/ezkybel/electronica //******************************************************************** #include <18F2550.h> #fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VRE GEN #use delay(clock=48000000) // siempre ponemos (48000000) // CCS Library dynamic defines #DEFINE USB_HID_DEVICE TRUE //Tells the CCS PIC USB firmware to include HID handling code. #define USB_EP1_TX_ENABLE USB_ENABLE_INTERRUPT //turn on EP1 for

IN bulk/interrupt transfers #define USB_EP1_TX_SIZE 8 //Numero de byte de envio (maximo 64 bytes) #define USB_EP1_RX_ENABLE USB_ENABLE_INTERRUPT //turn on EP1 for OUT bulk/interrupt transfers #define USB_EP1_RX_SIZE 8 //Numero de byte de Recepcion (maximo 64 bytes) // CCS USB Libraries #include <pic18_usb.h> //Microchip 18Fxx5x hardware layer for usb.c #include <hid 8-byte.h> //USB Configuration and Device descriptors for this UBS device #include <usb.c> //handles usb setup tokens and get descriptor reports void main() { int8 in_data[8]; //Declaramos la variable de entrada y su tamaano de 8 bytes int8 out_data[8]; //Declaramos la variable de salida y su tamaano de 8 bytes usb_init(); // inicializa el modulo USB. while(1){ usb_task(); if (usb_enumerated()){ // si windows reconocio el dispositivo. if (usb_kbhit(1)) { // Si el pic recibio algun dato de la PC usb_get_packet(1, in_data, ;// Guarda en in_data los datos de la PC if (in_data[0]==0xAA){ // si el dato recibido fue 0xAA output_high(pin_B0); // Enciende el LED en B0 } if (in_data[0]==066){ // si el dato recibido fue 066 output_low(pin_B0); // Apaga el LED en B0 } } if (input(pin_B1)){ // Si se presiono el boton out_data[0]=055; // out_data[0]= 055 usb_put_packet(1, out_data, 8, USB_DTS_TOGGLE); // lo enviamos por USB a la PC } } } }

Lo mas importante lo puse en rojo y lo que esta en verde siempre debe ir al igual que la configuracion del PIC como es el reloj a 48Mhz, aunque usemos un cristal de 20 Mhz, al momento de grabar nuestro pic debemos decirle en las configuraciones del programa que lo graba que divida el reloj para obtener 4Mhz, lo que hace es que configura en el PIC un divisor de frecuencia para obtener 4Mhz del cristal que usemos, posteriormente un PLL aumenta esa frecuencia a 48 Mhz, por eso es que trabajaremos siempre 48Mhz, pero eso ya lo hace el programa del grabador sin embargo es importante que se configure bien.

Ejemplo de configuracion del divisor en mi grabador en este caso tengo un cristal de 20Mhz

En la parte: #define USB_EP1_TX_SIZE 8 #define USB_EP1_RX_SIZE 8 int8 out_data[8]; int8 in_data[8]; se define el tamao buffer de recepcion y del de transmision en este caso son 8 bytes cada uno. si se cambian aqui habria que cambiarlo tambien en visual basic. Estas dos funciones siempre deben ir y son para inicializar el puerto y ponerlo a funcionar. usb_init(); usb_task(); En nuestro ejemplo manejamos dos arrays in_data[x] y out_data[x], cada uno de ellos de 8 bytes, la x representa el indice de cada array,en nuestro ejemplo solo utilizaremos un byte de cada array para enviar datos y leer los recibidos, pero podemos trabajar asi, en este caso sern in_data[0] y out_data[0], si ustedes quieren trabajar con mas datos no hay problema pero recuerden que ente caso solo tenemos de limite 8 bytes. if(usb_enumerated()) Es para saber si se ha reconocido el dispositivo por la PC if (usb_kbhit(1)) Es para saber si se ha recibido un dato desde el PC

Y estas son las dos principales funciones de envio y recepcion

Para recibir datos: el formato es este: ejemplo: usb_get_packet(1, in_data, 8); note que unque solo utilizamos un byte para nuestro ejemplo debemos pedir los 8 para evitar errores. usb_get_packet(1, array para guardar datos, numero de datos a recibir);

Para transmitir datos: el formato es este: usb_put_packet(1, array para enviar datos, numero de datos a enviar,USB_DTS_TOGGLE); ejemplo: usb_put_packet(1, out_data, 8, USB_DTS_TOGGLE); para ambos casos solo modificaremos la parte en rojo, el 1 significa el endpoint del arreglo, por lo tanto siempre sera el mismo (un 1), tampoco modificarems USB_DTS_TOGGLE En nuestro ejemplo si presionamos el boton por B1, enviaremos a la PC el dato 055 por medio de out_data[0], y estara esperando que le envien datos el cual guardara en in_data[0], si el dato que envia la PC es 0xAA encendera el LED, pero si envia 066 entonces lo apagara, estos datos pueden ser cualquier valor de 0a 255.

VISUAL BASIC Se puede hacer el programa en diferentes lenguajes (Visual Basic.net, Visual C++, Visual C#, etc) sin ambago aqui solo veremos en visual basic, yo no tengo ejemplos en otros lenguajes y elegi este por que hay muchos ejemplos para manejar este entorno. nesecitaremos un modulo .bas llamado mcHIDInterface.bas el cual viene incluido en los

archivos que descargaste, la plantilla que utilizo para hacer aplicaciones HID en Visual Basic esta comentada totalmente (en ingles), por lo que solo explicare lo mas importante.

ENVIO Aqui vemos como se envian datos al PIC por USB, tenemos el codigo de los dos botones usado en este ejemplo uno de ellos apaga el led y el otro lo enciende. Private Sub Command1_Click() BufferOut(1) = &HAA hidWriteEx VendorID, ProductID, BufferOut(0) End Sub Private Sub Command2_Click() BufferOut(1) = &H66 hidWriteEx VendorID, ProductID, BufferOut(0) End Sub

Explicacion ponemos en BufferOut(1) el dato 0xAA BufferOut(1) = &HAA y con la siguiente funcion sacamos el dato por USB a esta funcion no le cambiamos nada, hidWriteEx VendorID, ProductID, BufferOut(0)

RECEPCION Esta funcion es la que se encarga de recibir datos y guardarlos en el array BufferIn ***************************************************************** on read event ***************************************************************** Public Sub OnRead(ByVal pHandle As Long) read the data (dont forget, pass the whole array) If hidRead(pHandle, BufferIn(0)) Then ** YOUR CODE HERE ** first byte is the report ID, e.g. BufferIn(0) the other bytes are the data from the microcontrolller End If End Sub

pero ya esta definida en la plantilla por lo que no tenemos que preocuparnos por hacerla, solo leemos el byte que nos interesa en este caso BufferIn(1), podemos leer el arreglo en cualquier momento y lugar de el codigo, pues esta funcion es como una interrupcion. en el ejemplo lo leemos desde un timer Timer1 el cual esta configurado en intevalos de 100 ms. Private Sub Timer1_Timer() If BufferIn(1) = &H55 Then Shape1.BackColor = &HFF00& Else Shape1.BackColor = &H4000& End If BufferIn(1) = 0 End Sub Nota. Algo en lo que debemos tener cuidado es que en visual basic, la variable de el array de recepcion como de transmision siempre sera mayor en1 alos indices de los array en el PIC por ejemplo si enviamos desde el pic el dato 0xFF por la variable out_data[0],seria asi: out_data[0]=0xFF; usb_put_packet(1, out_data, 8, USB_DTS_TOGGLE); y en visual basic lo recibimos en el indice 1 , quedaria asi: If BufferIn(1) = &HFF Then End If De igual manera al enviar un dato de V. Basic a la variable in_data[0] del PIC se haria de esta manera: si le enviamos el dato 0xFF al arreglo seria asi: BufferOut(1) = &HFF hidWriteEx VendorID, ProductID, BufferOut(0) y el PIC lo recibiria asi: if (in_data[0]==0xFF) Por ultimo compilan el codigo del PIC y el archivo .hex generado, lo graban cuidando la configuracion de su cristal como lo mencione anteriormente para que le pueda funcionar, tambien lo pueden simular en Proteus con el USB Virtual y la PC lo detectara como si estuvieran realmente conectando un dispositivo fisicamente. Si lo que envio el PIC es 055 cambia el color de Shape1 cambia el color de Shape1

Al conectar su pic a la PC debera salir la siguiete notificacion como cuando conectan un dispositivo nuevo.

Descarga del proyecto: ->USB_HID_Ezkybel.zip< Saludos

14 Responses to USB_HID

Janet Benites: October 25, 2010 at 6:55 pm Felicidades por un paso mas en tu escalalera, y que tu lucha nunca cese para que logres tus objetivos; estamos contigo siempre y en cada momento, gracias por nunca dejar de sorprendernos y por que eres un orgullo para nosotras. TE AMO. Reply

Arturo: October 30, 2010 at 7:17 pm Este aporte est muy bien explicado. Gracias por tan buen proyecto para aprendisaje. Lo voy a armar y ya dire como me fue. Gracias Reply

Luis:

December 22, 2010 at 3:45 pm Hola ezkybel, gracias por tus aportes, me impresiona lo que se puede hacer con los microcontroladores, yo tengo conocimientos basicos (ya que voy empezando) de la programacion, estoy utilizando el lenguaje PBP, pero ando buscando informacion de como utilizar la programacion en C ya que me llama la atencion de como se utiliza no se si sea dificil de entender (aunque no lo e utlizado) aunque los temas que publicaste lo hacen ver sencillo de emplear y bueno los aportes que das me ayudan mucho en esto que comento, vi lo publicado con un termostato y me quede impresionado ahora estoy leyendo este del USB, no pensaba que se pudiera hacer esto con este lenguaje. Gracias por tus aportes. Saludos desde Mxico! Reply

Ezkybel: December 22, 2010 at 3:56 pm Hola Luis, claro que se puede hacer, de hecho y comence a trabajar con PBP y HID, con un programa llamado Easy HID si te fijas el codigo en visual basic que posteo esta generado con este programa, es decir combin la parte de visual basic con la programacion en CCS, y no es dificil entender este lenguaje, yo me mude de PBP a CCS por que se me hizo mejor lenguaje, pero sin embargo estuve trabajando mucho con PBP, lo bueno de CCS es que hay infinidad de ejemplos y tutoriales en la red hacerca de este lenguaje y lo que yo presento en esta pagina son aplicaciones, te invito a leer el nuevo proyecto Ceradura con tarjetas telefonicas es un ejemplo mas real creativo y sencillo que los otros dos que ya publique. Saludos tambien desde Mexico (S.L.P) Luis. Reply

Nextar: August 6, 2011 at 1:03 pm Ketal Ezkybel, primero que nada felicitarte por tus aportes. bien.. te escribo por que en la parte de oscilador no entiendo muy bien. Por que? el reloj siempre lo debemos poner a 48Mhz cuando en realidad es de 20Mhz; si entiendo la funcin que hace el PLL y si por ejemplo pongo un xtal de 20Mhz y el PLL lo divide entre 5, tendr los 4Mhz los cuales son los que necesito para usar el (USB clock selection) para que el pic divida los 96Mhz entre 2 y asi obtendra los

48Mhz que necesita el pic para que pueda funcionar el usb.. y pues es aqu mi duda por que se debe configurar el reloj a 48Mhz y no a 20Mhz? aun as no me queda claro. otra cosa quisiera saber si me puedes ayudar.. lo que quiero hacer es: recibir una cadena de caracteres por el puerto serial ya sea con el 18F2550 o con el 18F4550 y posteriormente enviar esos mismos datos a una aplicacin en la pc va usb. La aplicacin de visual basic ya la hice, y en un principio utilice el codigo de ejemplo de CCS (ex_usb_hid.c) en el cual lee un puerto analgico y el estado de un push button, la modificacin que hice fue quitar la rutina del ADC y el testeo del push button y en lugar de ellos poner una rutina que tome los datos por el puerto serial con [gets(buffer); ] y posteriormente enviarlo via usb con [ out_data[0] =buffer[0]; ] donde buffer va desde 0 hasta la longitud de mi cadena de caracteres (son 10 en total). la velocidad que utilizo es de 2400 baudios con un cristal de 20Mhz y aqu el problema, todo esto ya lo simule en proteus y todo funciona perfecto pero implementado fsicamente no funciona. lo nico que puedo recibir es la primer cadena de caracteres que llega al pic y claro la muestra en la pc correctamente pero despues de eso ya no regresa a tomar la siguiente cadena de caracteres la cual nunca es la misma. Tambin ya lo hice con tu cdigo e igual en la simulacin todo funciona perfectamente pero fsicamente no lo hace, pareciera que el programa se queda colgado y pues yo no creo que sea eso por que no se pierde la conexin usb con la pc. es por eso que te pido ayuda haber si me puedes ayudar.. por lo menos tomar un dato por el puerto serie del pic y enviar ese mismo dato a la pc. no se como subir mi cdigo o la simulacin en proteus para que sea mas fcil de entender lo que quiero hacer bueno espero que me puedas ayudar la verdad ya tengo meses con esto y no encuentro solucin por ningn lado. Reply

Ezkybel: August 6, 2011 at 11:19 pm Hola Nextar, mira en cuanto a lo de la frecuencia de los 48 Mhz debo confesarte que no lo he hestudiado bien pero estuve estudiando sobre el tema en esta pagina la cual te recomiendo: http://picmania.garciacuervo.net/conceptos.php#USB4Mhz , debo decirte que yo jamas cambio los valores en el codigo de CCS es decir siempre lo pongo a 48Mhz segun entendi hay un postscaler el cual vuelve a configurar la frecuencia para el

programa, pero no tuve mucho tiempo de leerlo, espero que si logras entenderlo mejo no lo expliques por favor te lo agradeceria. En cuanto a el problema de tu programa con la comunicacion serial se me hace algo raro, si quieres enviame a mi correo tu programa para analizarlo y ayudarte mejor mi correo es: ezkybel@hotmail.com saludos Reply

Nextar: August 9, 2011 at 9:50 pm Hola ketal Ezkybel, primero que nada pues agradecerte por tu pronta respuesta.. En cuanto a lo del cristal a utilizar y a la seleccin de la frecuencia de reloj ya me quedo claro y aqu la explicacin espero poder darme a entender. Primero que nada podra decirse que el microcontrolador va a trabajar con dos frecuencias en caso de que utilicemos el modulo USB ya sea, que sean iguales o no. Por lo tanto el valor que pongamos en esta directiva #use delay(clock=48000000) no corresponde al valor del cristal, sino a la frecuencia a la que trabajara el microcontrolador; la cual estar determinada por la directiva CPUDIV, la funcin de este postcaler es tomar la frecuencia del PLL de 96Mhz y dividirla ya sea en 2,3,4 o 6 y esta ser finalmente la frecuencia a la que estarn ejecutando las instrucciones el microcontrolador. En el caso de que se configure como CPUDIV1 se le estar indicando al microcontrolador que la frecuencia de reloj ser de 48Mhz 96Mhz/2; paralelo a ello, la misma frecuencia proveniente del PLL de 96Mhz es dividida automticamente por 2, y utilizando la directiva USBDIV tomara esta frecuencia que ser de 48Mhz para la operacin del modulo USB. Como conclusin se puede decir que si se tiene como ejemplo un cristal de 8Mhz la configuracin de bits ser la siguiente: #fuses HSPLL,PLL2,USBDIV,CPUDIV2, Con HSPLL estaremos indicando que utilizaremos el un cristal de alta frecuencia y el PLL Prescaler Con PLL2 dividimos la frecuencia del cristal de 8Mhz en 2 para obtener 4Mhz que son necesarios para el PLL de 96Mhz, para obtener 96Mhz el cual tomara dos caminos:

1.- Con USBDIV se estarn tomando 48Mhz (96Mhz/2) para el uso del modulo USB 2.- Con CPUDIV2 se estar indicando que la frecuencia de reloj ser de 32Mhz (en la hoja de datos CPUDIV2 . corresponde a dividir la frecuencia del PLL de 96Mhz entre 3 lo que nos da como resultado 32Mhz). Lo que . finalmente ser este dato lo que pondremos en la siguiente instruccin: #use delay(clock=32000000) Y es aqu donde les comentaba que el microcontrolador puede estar trabajando a frecuencias diferentes 48Mhz para el funcionamiento del USB y 32Mhz para la ejecucin de sus instrucciones. Espero haberme dado a entender adems de que esto me resolvi varios problemas que tenia en la conexin USB. Por otro lado.. voy a ordenar mis programas e informacin de lo que pretendo hacer y te lo mando a tu correo, espero que con tu ayuda pueda sacar este pequeo proyecto. De antemano muchas gracias Saludos desde Puebla Reply

Ezkybel: August 10, 2011 at 6:18 am Al contrario gracias por la respuesta y la aclaracion de la duda en cuanto al cristal, tu respuesta es muy clara y entendible, y enviame tu codigo para checarlo, he trabajado mucho con el puerto serial y me ha funcionado bien, espero poder ayudare, antes de eso recorde que tuve un problema similar que me dio muchos dolores de cabeza ya que en la simulacion funcionaba perfectamente pero en mi caso no era un proyecto de comunicacion sino mas bien era un programa que variaba la tension altena por medio de unos triacs ademas de eso tenia un ventilador de 12 V y cuando este encencia hacia que se reiniciara el microcontrolador, el problema era que los pics tienen una funcion muy util para casos de inestabilidad de la alimentacion, asi que cuando el motor arrancaba consumia mucha corriente y como el eliminador que tenia era de poca corriente le afectaba al micro, para deshabilitar esta funcion el PIC tiene un fusible llamado BROWN OUT DETECT, quisa sea tu problema, puedes probar deshabilitandolo. Saludos

Reply

Nextar: August 20, 2011 at 6:05 pm ketal ezkybel, ya dashabilite el fusible que me dijiste ya tambin estuve analizando la configuracin de bits y nada.. ya te envi a tu correo el cdigo que tengo espero que me puedas ayudar.. gracias.. buen da Reply

Ezkybel: August 23, 2011 at 6:53 am Hoy lo voy a checar Reply

Crs: September 26, 2011 at 4:17 pm Muy buen ejemplo, tengo una duda si tengo una entrada analgica AN0 como puedo desplegar el valor an tu programa de vb? Gracias y saludos. Reply

Ezkybel: September 26, 2011 at 4:23 pm Claro que si se puede, basicamente es esto: lees al ADC, lo pones en una variable de 8 bits o en dos bytes, y lo(s) envias por el puerto USB, lo recojes con visual basic, y haces las operaciones corespondientes segun lo que quieras leer, y lo muestras, y asi haces un ciclo infinito.

cualquier duda comentamela y si hay tiempo te ayudare saludos Reply

JUAN: March 13, 2012 at 5:42 pm Amigo me marca error en el compilador, la compilacion la estoy haciendo en PIC C. Me podrias decir cual es mi error o si tengo que pegar algun archivo en algun directorio de mi ordenador? Reply

Ezkybel: March 13, 2012 at 8:55 pm Hola quiza tu error sea, por que la compilacion la hice con PCWHD y tu lo estas haciendo con otro compilador, saludos Reply