El problema de los ejemplos que vienen con las librerías de Microchip es que están pensados para funcionar en los demostradores de Microchip y esto supone que el código está tan plagado de excepciones que resulta difícil de leer.
Llevo unos días peleándome con la de USB para usar comunicación CDC y he decidido crear un ejemplo que sea la mínima expresión; es decir, sólo lo necesario para ver cómo funciona y luego poder ampliarlo a gusto.
El resultado se lo dejo a continuación, y me ha permitido establecer una comunicación CDC muy básica tanto con un 19f27j53 usando el oscilador interno como en un 18f2455 usando un cristal de 20MHz.
La siguiente en caer será la librería TCP/IP
MPLAB C Compiler for PIC18 USB CDC barebones
Este desarrollo está basado en el ejemplo "USB Device - CDC - Basic Demo" de las librerías de aplicación de Microchip.
En el archivo adjunto encontrará todo el proyecto, además de los HEX para un 18f2455 y un 18f27j53.
REQUISITOS PREVIOS1. Instalar MPLAB IDE:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en0194692. Instalar la versión dgratuita educativa de MPLAB C Compiler for PIC18:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en5366563. Instalar las Microchip Application Library:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en547784Por defecto, el compilador se instala en la carpeta MCC18 y, en su interior, se encuentra la subcarpeta h que contiene includes fundamentales.
Por defecto, la Application Library se instala en la carpeta Microchip Solutions v2010-10-19 y, en su interior, se encuentra la subcarpeta Microchip/Include que contiene includes fundamentales.
PASO A PASO1. En primer lugar crearemos una carpeta para nuestro proyecto y colocaremos en ella los archivos del Stack USB que nos interesan. Cree una carpeta llamada, por ejemplo: USB-CDC.
2. El stack USB requiere que existan en la carpeta del proyecto los 3 siguientes archivos:
* HardwareProfile.h: El stack está pensado para utilizarlo con los demostradores de Microchip, pero si vamos a usar un prototipo diferente tendremos que crear este archivo dentro de la carpeta con el contenido mínimo que se muestra a continuación:
#ifndef HARDWARE_PROFILE_H
#define HARDWARE_PROFILE_H
#define DEMO_BOARD USER_DEFINED_BOARD
#define self_power 1
#define USB_BUS_SENSE 1
#endif //HARDWARE_PROFILE_H
* usb_decriptors.c: Este archivo contiene el nombre con el que identificará nuestro dispositivo en el sistema y lo más cómodo es copiarlo directamente del ejemplo C:\Microchip Solutions v2010-10-19\USB Device - CDC - Basic Demo\CDC - Basic Demo - Firmware.
* usb_config.h: Este archivo establece algunas constantes que condicionan el funcionamiento del stack y lo más cómodo es copiarlo directamente del ejemplo C:\Microchip Solutions v2010-10-19\USB Device - CDC - Basic Demo\CDC - Basic Demo - Firmware. Por defecto, viene configurado para usar el stack en modo interrupción, pero en este ejemplo se ha utilizado en modo polling porque es más sencillo. Por este motivo tenemos que realizar en este archivo la modificación que se indica a continuación (líneas 83 y 84):
#define USB_POLLING
//#define USB_INTERRUPT
3. Ejecutar MPLAB IDE.
4. Seleccionar Project>Project Wizard.
5. Seleccionar el microcontrolador. Este ejemplo ha sido probado conel PIC18f2455 y con el PIC18F27J53, pero en principio debería funcionar con todos. Pulsar Siguiente.
6. Seleccionar como Active Toolsuite "Microchip C18 Toolsuite". Pulsar Siguiente.
7. Pulsar el botón Browse para selecccionar la carpeta USB-CDC que creamos en el paso 1 y en la que hemos colocado ya los 3 archivos necesarios, y escribir un nombre para el proyecto, por ejemplo USB-CDC en el cuadro de texto Nombre. Pulsar Guardar y, a continuación, Siguiente.
7. Seleccionar los 3 archivos que ya hemos colocado en la carpeta USB-CDC y pulsar el botón Add para añadirlos al proyecto.
8. Además de estos 3 archivos, necesitamos 2 del stack: C:\Microchip Solutions v2010-10-19\Microchip\USB\usb_device.c y C:\Microchip Solutions v2010-10-19\Microchip\USB\CDC Device Driver\usb_function_cdc.c. Añádalos también pulsando el botón Add. Pulse el botón Siguiente y, a continuación, Finalizar.
9. Confirme el nombre que se propone para el Workspace pulsando Guardar.
10. Además de los 5 archivos que hemos incluido en el proyecto, el stack hace uso de un puñado de includes; pero en lugar de añadirlos vamos a indicarle a MPLAB dónde buscarlos. Seleccione Project>Build options>Project y, en el cuadro de diálogo que aparece, asegúrese de que está activa la ficha Directories.
11. Despliegue el cuadro de lista Show directories for y seleccione Include Search Path. Utilice el botón New para añadir las rutas C:\Microchip Solutions v2010-10-19\Microchip\Include y C:\MCC18\h.
12. Despliegue nuevamente el cuadro de lista Show directories for y seleccione Library Search Path. Si no está incluida la dirección C:\MCC18\lib, añádala pulsando el botón New.
13. Pulse el botón Aceptar.
14. Ya tenomos todo lo necesario para usar el stack USB en modo CDC, sólo nos queda crear el archivo main de nuestra aplicación. Seleccione File>New y, a continuación, File>Save As para guardar el archivo con el nombre main.c en la carpeta USB-CDC del proyecto. Seleccione Project>Add Files to Project y elija el archivo main.c para incluirlo también en el árbol del proyecto.
15. Escriba en el archivo main.c el código que se muestra a continuación. Las únicas precauciones son comentar/descomentar los pragmas que se deseen utilizar de la zona superior. El primer conjunto está pensado para utilizar el oscilador interno en un 18f27j53 (a pesar de que en principio no debería ser muy fiable, el caso es que funciona), y el segundo grupo está pensado para usar un cristal externo en un 18f2455. El código empieza con un USBDeviceInit que inicializa el dispositivo USB apoyándose en las tres funciones Callback que hay al final del código. A continuación simplemente se entra en un bucle infinito que llama en cada iteración a las funciones USBDeviceTasks() y ProcessIO. La primera debe llamarse periódicamente para poner a punto el estado de la comunicación USB y en ProcessIO en primer lugar se comprueba si el dispositivo está aún conectado ((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)), a continuación se comprueba si está listo para recibir/transmitir (USBUSARTIsTxTrfReady()) y, en caso afirmativo, se leen los nuevos caracteres que hayan podido llegar desde el ordenador por el USB getsUSBUSART(USB_Out_Buffer,64) y se los devolvemos al buffer de salida anteponiendo "Ha pulsado: " con putsUSBUSART. Por último, llamamos a CDCTxService() que es la responsable de enviar el buffer por el puerto USB de vuelta al ordenador. Para probar el programa, compílelo con Project>Build all, grábelo en su dispositivo, conéctelo al ordenador, abra una sesión de HyperTerminal y conecte al puerto USB (generalmente aparecerá como COM4 o uno superior); todo lo que escriba le será devuelto anteponiento "Ha pulsado".
/** CONFIGURATION **************************************************/
//Descomente estos pragmas para usar el oscilador interno. Probado en un pic18f27j53
#pragma config WDTEN = OFF
#pragma config CPUDIV = OSC1
#pragma config CFGPLLEN = ON
#pragma config OSC = INTOSCPLL
#pragma config PLLDIV = 2
#pragma config XINST = OFF
//Descomente estos pragmas para usar un cristal externo de 20MHz. Probado en un pic18f2455
//#pragma config WDT = OFF
//#pragma config CPUDIV = OSC1_PLL2
//#pragma config FOSC = HSPLL_HS
//#pragma config PLLDIV = 5
//#pragma config XINST = OFF
//#pragma config USBDIV = 2
//#pragma config VREGEN = ON
/** I N C L U D E S **********************************************************/
#include "USB/usb.h"
#include "USB/usb_function_cdc.h"
/** V A R I A B L E S ********************************************************/
char USB_Out_Buffer[64];
char buffer[64];
/** P R I V A T E P R O T O T Y P E S ***************************************/
void ProcessIO(void);
/** DECLARATIONS ***************************************************/
void main(void)
{
USBDeviceInit(); //usb_device.c. Initializes USB module SFRs and firmware
//variables to known states.
while(1)
{
USBDeviceTasks();
ProcessIO();
}//end while
}//end main
/********************************************************************
* Function: void ProcessIO(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is a place holder for other user
* routines. It is a mixture of both USB and
* non-USB tasks.
*
* Note: None
*******************************************************************/
void ProcessIO(void)
{
BYTE numBytesRead;
// User Application USB tasks
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;
if(USBUSARTIsTxTrfReady())
{
numBytesRead = getsUSBUSART(USB_Out_Buffer,64);
if(numBytesRead != 0)
{
strcpypgm2ram(buffer,(const rom far char *)"Ha pulsado: ");
strncat(buffer,USB_Out_Buffer,numBytesRead);
strcatpgm2ram(buffer,(const rom far char *)"\r\n");
putsUSBUSART(buffer);
}
}
CDCTxService();
} //end ProcessIO
// ******************************************************************************************************
// ************** USB Callback Functions ****************************************************************
// ******************************************************************************************************
// The USB firmware stack will call the callback functions USBCBxxx() in response to certain USB related
// events. For example, if the host PC is powering down, it will stop sending out Start of Frame (SOF)
// packets to your device. In response to this, all USB devices are supposed to decrease their power
// consumption from the USB Vbus to <2.5mA each. The USB module detects this condition (which according
// to the USB specifications is 3+ms of no bus activity/SOF packets) and then calls the USBCBSuspend()
// function. You should modify these callback functions to take appropriate actions for each of these
// conditions. For example, in the USBCBSuspend(), you may wish to add code that will decrease power
// consumption from Vbus to <2.5mA (such as by clock switching, turning off LEDs, putting the
// microcontroller to sleep, etc.). Then, in the USBCBWakeFromSuspend() function, you may then wish to
// add code that undoes the power saving things done in the USBCBSuspend() function.
// The USBCBSendResume() function is special, in that the USB stack will not automatically call this
// function. This function is meant to be called from the application firmware instead. See the
// additional comments near the function.
/*******************************************************************
* Function: void USBCBCheckOtherReq(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: When SETUP packets arrive from the host, some
* firmware must process the request and respond
* appropriately to fulfill the request. Some of
* the SETUP packets will be for standard
* USB "chapter 9" (as in, fulfilling chapter 9 of
* the official USB specifications) requests, while
* others may be specific to the USB device class
* that is being implemented. For example, a HID
* class device needs to be able to respond to
* "GET REPORT" type of requests. This
* is not a standard USB chapter 9 request, and
* therefore not handled by usb_device.c. Instead
* this request should be handled by class specific
* firmware, such as that contained in usb_function_hid.c.
*
* Note: None
*******************************************************************/
void USBCBCheckOtherReq(void)
{
USBCheckCDCRequest();
}//end
/*******************************************************************
* Function: void USBCBInitEP(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is called when the device becomes
* initialized, which occurs after the host sends a
* SET_CONFIGURATION (wValue not = 0) request. This
* callback function should initialize the endpoints
* for the device's usage according to the current
* configuration.
*
* Note: None
*******************************************************************/
void USBCBInitEP(void)
{
CDCInitEP();
}
/*******************************************************************
* Function: BOOL USER_USB_CALLBACK_EVENT_HANDLER(
* USB_EVENT event, void *pdata, WORD size)
*
* PreCondition: None
*
* Input: USB_EVENT event - the type of event
* void *pdata - pointer to the event data
* WORD size - size of the event data
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is called from the USB stack to
* notify a user application that a USB event
* occured. This callback is in interrupt context
* when the USB_INTERRUPT option is selected.
*
* Note: None
*******************************************************************/
BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size)
{
switch(event)
{
case EVENT_CONFIGURED:
USBCBInitEP();
break;
case EVENT_EP0_REQUEST:
USBCBCheckOtherReq();
break;
default:
break;
}
return TRUE;
}
/** EOF main.c *************************************************/
Metadatos para buscadores:
USB CDC Internal Oscillator
Microchip USB barebones
Basic example of Microchip USB CDC