En otras entradas en las que hablé del USB como esta, utilicé un dispositivo externo como puente entre una comunicación UART y una USB, que en ese caso fué el MCP2200. No es el único que existe, FTDI es la empresa líder en hacer este tipo de pasarelas, pero en esta entrada vamos a realizar una comunicación USB sin utilizar ninguna pasarela, es decir, vamos a programar una comunicación con el USB nativo del microcontrolador PIC18F14K50.
Para no empezar desde cero, vamos a modificar uno de los proyectos que nos da microchip para realizar comunicaciones mediante USB con el protocolo CDC, el cual emula en nuestro PC un puerto COM por el que nos comunicamos como si de una conexión COM se tratara. El ejemplo que amos a utilizar es el USB Device-CDC-BasicDemo, disponible en las MLA, que podéis descargar en http://www.microchip.com/mla. Este ejemplo como todos los de microchip está preparado para muchos microcontroladores, por lo que si utilizamos MPLAB 8 nos encontraremos con muchos proyectos diferentes, por el contrario, si ya hemos cambiado a MPLAB X existe solo un proyecto, esta vez con muchas configuraciones diferentes. En mi caso he utilizado MPLAB X, utilizando la configuración correspondiente para la placa Low Pin Count USB, con el 18F14K50.
En el ejemplo hay muchísimo código de las demás configuraciones que podemos eliminar, aunque esto solo nos va a servir para hacer más entendible el código, ya que todo este código no es compilado por el compilador, ya que se encuentra dentro de instrucciones #ifdef, y el precompilador las elimina. No os recomiendo quitar código que el precompilador no elimine, ya que el protocolo USB requiere de muchas funciones que si las eliminamos puede que luego no funcione bien.
Una vez dicho todo esto, vamos a desgranar un poco el código. Lo primero que tenemos, después de los includes y las configuraciones, es un remapeo de los punteros de reset, interrupciones de alta prioridad e interrupciones de baja prioridad. Esto es necesario en el caso que utilicemos un bootloader que ocupe dichas posiciones, en caso de no utilizarlo esta parte del código se puede borrar sin ningún inconveniente, aunque yo he preferido dejarla. Si queréis dejarla, debéis decirle al microcontrolador que no vais a utilizar bootloader, para ello debéis comentar la siguiente línea en el archivo HardwareProfile.h
//Uncomment the following line to make the output HEX of this // project work with the HID Bootloader //#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER
//#define USE_SELF_POWER_SENSE_IO #define tris_self_power TRISAbits.TRISA2 // Input #if defined(USE_SELF_POWER_SENSE_IO) #define self_power PORTAbits.RA2 #else #define self_power 1 #endif //#define USE_USB_BUS_SENSE_IO #define tris_usb_bus_sense TRISAbits.TRISA1 // Input #if defined(USE_USB_BUS_SENSE_IO) #define USB_BUS_SENSE PORTAbits.RA1 #else #define USB_BUS_SENSE 1 #endif
Lo siguiente es la inicialización del usuario, es decir, puertos que vayamos a utilizar, inicialización de las salidas… y por ultimo la inicialización de los servicios del USB.
Volviendo al programa principal, lo siguiente que vemos es el bucle sin fin, y dentro otras sentencias para el precompilador. Estas sentencias lo que nos dan a elegir es si queremos nosotros que cuando haya algún cambio en el bus USB salte un interrupción que trate es en cambio, o por el contrario queremos desde el programa principal ir comprobando si se ha realizado algún cámbio en cada ciclo. Esto se configura desde el archivo USBConfig.h con las siguientes líneas:#define USB_POLLING //#define USB_INTERRUPT
En este caso lo vamos a hacer mediante polling. OJO! la interrupción SOLO salta cuando hay cambios en el bus USB, es decir, reconocimento correcto por parte del PC, desconexión del cable USB, esperando reconocimiento por parte del PC, pero la interrupción no salta cuando llega un dato, ni cuando este se ha enviado, esto debemos hacerlo testeando continuamente el numero de bytes a leer, que lo haremos dentro de la función ProcessIO. En esta función lo que hacemos es meter nuestro código de usuario, lo primero que se hace en este ejemlo, es, según el estado en el que estemos, los leds d ela placa parpadean de una forma o de otra, con la función BlinkUSBStatus(), y si el USB ya ha sido configurado, entonces empezamos a escribir según el estado del pulsador:
if(buttonPressed) { if(stringPrinted == FALSE) // si no hemos enviado todavía la cadena... { if(mUSBUSARTIsTxTrfReady()) //está el usb listo para enviar?? { putrsUSBUSART("Button Pressed -- \r\n"); stringPrinted = TRUE; } } } else { stringPrinted = FALSE; }
Y también empezamos a comprobar el buffer a ver si ha llegado algún dato, y según que dato sea hacer algo en consecuencia.
if(USBUSARTIsTxTrfReady()) { numBytesRead = getsUSBUSART(USB_Out_Buffer,64); if(numBytesRead != 0) { BYTE i; for(i=0;i<numBytesRead;i++) { switch(USB_Out_Buffer[i]) { case 0x0A: PORTBbits.RB7 = 1; break; case 0x0D: PORTBbits.RB7 = 0; break; default: USB_In_Buffer[i] = USB_Out_Buffer[i] + 1; break; } } putUSBUSART(USB_In_Buffer,numBytesRead); } }
En esta caso se ha cambiado un poco el código del ejemplo original, y si recibimos un 0xA se pone a 1 el bit RB7, si recibimos un 0xD, se pone a 0 ese bit, y si recibimos cualquier otro valor, se devuelve sumando 1.
El protoclo CDC no es el único que existe, aunque sí que es el más sencillo de utilizar, sobre todo por parte del PC, así que es el que más utilizaré en el blog. Os dejo el enlace del programa reducido para que podais hacer pruebas.
Firmware
El protoclo CDC no es el único que existe, aunque sí que es el más sencillo de utilizar, sobre todo por parte del PC, así que es el que más utilizaré en el blog. Os dejo el enlace del programa reducido para que podais hacer pruebas.
Firmware
No hay comentarios:
Publicar un comentario