Hola controleros y controleras, en la entrada del día de hoy vamos a realizar una comunicación USB con PIC, el cual puede ser el PIC 18F4550 o PIC18F2550, en forma CDC donde podremos emular un COM desde la puerta USB de nuestro computador.
Antes de comenzar te hago la invitación para que veas nuestro CURSO GRATUITO DE MICROCONTROLADORES PIC.
Y también que te suscribas al canal en YouTUBE para que sigas aprendiendo sobre estos temas de programación de dispositivos embebidos, control de procesos, análisis de sistemas, instrumentación entre otros.
Comunicación USB con PIC
El bus de comunicación USB (Universal Serial Bus, en sus siglas en ingles) es un bus serie con una estructura de árbol que permite la conexión de diversos dispositivos en cadena permitiendo la transferencia síncrona y asíncrona entre estos.
Al momento de conectar un dispositivo USB, nuestro computador pregunta sobre su velocidad de funcionamiento y el controlador (driver) que debe cargarse para realizar una configuración adecuada.
La comunicación USB es un bus punto a punto, que comienza en el HOST y cuyo destino es el HUB. El HOST es el dispositivo maestro que inicia la comunicación y el HUB es el dispositivo que contiene uno o más conectores o conexiones hacia otros dispositivos USB. Cada conector es un puerto USB.
Además, cada dispositivo USB tiene una jerarquía de descriptores que informan al host sobre como se constituye el dispositivo y sus características de funcionamiento, tales como: la clase, el número de serie del producto, la identificación del fabricante, el tipo de dispositivo, etc.
El cable USB posee internamente un par trenzado (D+ y D-) además de la tierra y la alimentación (+5V). Los conectores están sujetos al estándar (Tipo A, Tipo B).
Clases de comunicación USB
Básicamente, hay tres tipos de clases más utilizadas: Human Interface Device (HID), Mass Storage Device (MSC), Communications Device Class(CDC).
En una futura entrada abordaremos el uso del USB HID con PIC18F4550.
Nuestro enfoque de estudio en esta entrada estará en la Clase de Dispositivo de Comunicaciones (CDC). Los dispositivos de este tipo de clase implementan un mecanismo de comunicación de propósito general que se puede utilizar para la comunicación entre la mayoría de los dispositivos. Normalmente, los dispositivos clasificados como USB-CDC son: módems, dispositivos de red, comunicación inalámbrica, interfaces de hardware dedicadas, etc.
Pueden existir diferentes configuraciones en un sistema USB, y son los dispositivos conectados a este sistema los encargados de suministrar esta información a través de los descriptores los cuales poseen campos que permiten al sistema clasificar al dispositivo y asignarle un driver.
La primera información relevante corresponden al fabricante del dispositivo USB y el producto. Estas dos informaciones se dan a través de dos numeros conocidos como VIP (USB vendor ID) y PID (Product ID).
El VID es un número de 16 bits asignado por el fabricante del hardware a conectar. En nuestro caso podemos utilizar el número 04D8h que identifica a Microchip. O para este ejemplo, usar el número propio del CCS C 2405h que viene por defecto en el compilador.
El PID es un número de 16 bits que identifica al dispositivo en concreto a conectar. En nuestro caso utilizamos el número 000Bh que identifica a la familia de los PIC18 de microchip.
PIC USB en CCS C
La comunicación USB con PIC es bastante compleja y su programación requiere entender adecuadamente este protocolo, debido a esto tanto Microchip como otros compiladores tales como el CCS proporcionan librerías (llamadas «Stacks» o pila de software) para facilitar la programación de los microcontroladores.
Para la comunicación USB-CDC (Communications Device Class), se utiliza la libreria usb_cdc.h y algunas de las funciones disponibles de esta librería son:
- usb_cdc_kbhit(): retorna TRUE si hay uno o mas caracteres esperando en el buffer de recepción.
- usb_cdc_getc(): Obtiene el carácter recibido en el Buffer de recepción.
- usb_cdc_putc(char c): Coloca el carácter que recibe como parámetro en el buffer de transmisión para ser enviado.
- usb_cdc_putc_fast (char c) – Similar a usb_cdc_putc (), excepto si el búfer de transmisión está lleno, se saltará el char.
- USB_CDC_ISR () se puede definir si desea que una rutina específica cuando haya datos entrantes por el USB CDC (puerto virtual virtual). Esta es una rutina de «interrupción serial» la cual posee algunas limitaciones.
- usb_init(): Inicializa el hardware USB, esperando hasta que el periférico USB esté conectado al bus (Lo que NO significa que haya sido enumerado por el PC). Habilita y utiliza la interrupción USB.
- usb_enummerated(): Devuelve TRUE si el dispositivo ha sido enumerado por el PC. En este caso el dispositivo entra en modo de operación normal y puede enviar y recibir paquetes de datos.
- usb_init_cs(): Inicializa el protocolo USB y debe usarse cuando se utiliza una fuente externa para alimentar el microcontrolador. Esta función requiere el uso de el pin USB_CON_SENSE, el cual puede definirse al comienzo del programa y ser asignado a cualquier entrada digital del PIC, en este caso a modo de ejemplo, aunque no es necesario lo vamos a colocar en el PIN RB2.
- usb_task(): se usa para verificar el estado lógico del pin USB_CON_SENSE y debe llamarse como máximo cada 1 ms cuando se usa una fuente externa. Si se alimenta el PIC a través del propio USB NO es necesario llamar esta función cada 1 ms.
La librería posee más funciones, y se recomienda ver la cabecera del archivo usb_cdc.h para conocer el restante de funciones.
Es importante también ver los ejemplos disponibles por el compilador CCS C, los cuales puedes encontrar en la carpeta de instalación del software dentro de la carpeta «examples». Se recomienda darle un vistazo al ejemplo ex_usb_serial2.c y también al ejemplo ex_usb_serial3.c
Para iniciar la comunicación USB se usa la función: usb_cdc_init() y usb_init() en el main()
Es importante también estar llamando periodicamente la función usb_task() para que la comunicación USB se mantenga por lo que nuestro programa tendrá que tener un bucle infinito principal donde deberemos incluir la llamada a esta función.
LIMITACIONES DE INTERRUPCIÓN
Esta sección solo es relevante si está utilizando interrupciones PIC USB.
El manejo del USB es complejo, y a menudo requiere varias transmisiones de paquetes para lograr la transferencia de un bloque de datos. La mayor parte de este procesamiento se realiza en el USB ISR. Debido a esto, no se puede llamar la función usb_cdc_putc() dentro de otro ISR, el USB ISR o cuando los ISR están deshabilitados. Para solucionar este problema, se recomienda usar usb_cdc_putc_fast() y la opción USB_CDC_DELAYED_FLUSH.
Esto no garantiza una comunicación perfecta, porque si usas usb_cdc_putc_fast() para desbordar el búfer TX, los datos se perderán.
Tampoco se puede llamar a usb_cdc_getc() dentro de otro ISR, el USB ISR, USB_CDC_ISR() o cuando las interrupciones están desactivadas A MENOS QUE la función usb_cdc_kbhit() devuelva un VERDADERO.
Frecuencia de Oscilación del PIC – USB 2.0
La comunicación USB con PIC 18f4550, o cualquier otro de la familia 18, la frecuencia de oscilación necesaria para el USB 2.0 es de 48 Mhz. A continuación se muestra el diagrama de bloques del reloj del PIC 18F4550 USB:
Para conseguir los 48Mhz de oscilación, vamos a colocarle en este caso a nuestro microcontrolador un cristal de cuarzo de 20MHz y utilizaremos el PLL (Phase Locked Loop).
El PLL del circuito de reloj es un complejo circuito que nos permite modificar la frecuencia de entrada del oscilador externo primario. Dentro del circuito de reloj se tiene un divisor de frecuencia. Para ello utilizamos el fuse HSPLL. Como el módulo PLL requiere una oscilación de entrada de 4 Mhz debemos utilizar el divisor 1:5 indicado con el fuse PLL5 para obtener los 20:5 = 4 Mhz requeridos. Habilitamos el switche USBDIV para utilizar la frecuencia del PLL. En este caso también utilizaremos la velocidad de la CPU del PIC a 48Mhz, por lo tanto en la división del postcaler la vamos a dejar intacta, o sea colocando CPUDIV1.
Ejemplo USB-CDC PIC18 usando CCS C Compiler
Para este ejemplo vamos a implementar la comunicación USB con el PIC 18F4550 en ccs c, sin embargo este ejemplo lo puedes extrapolar al uso del PIC18F2550 USB.
PIC18f4550 USB tutorial
Vamos a implementar el siguiente circuito, donde enviaremos a través de la comunicación PIC USB CDC el valor leido en el pin análogo RA0 hacia el computador. Adicionalmente el PIC recibirá ordenes para prender o apagar los LEDs conectados en RB4 (Led1) y RB5 (Led2), para eso se enviará una trama de datos dada por: S101$ para realizar el toggle del primer LED y la trama S102$ para realizar el toggle del segundo LED. Utilizaremos la misma interfaz gráfica en MATLAB, utilizada en la entrada del CONTROL PID de un HORNO usando la Estructura de Predictor de Smith.
En este caso la alimentación del PIC se hará directamente desde el USB. El circuito para la Comunicación USB PIC18f4550 CCS se muestra a continuación:
El driver USB CDC para el pic18f4550 o cualquier otro pic o dispositivo ya viene instalado por defecto en Windows 10, ya que es un driver genérico.
Interfaz:
Hercules: Es un software que permite mostrar en el computador los datos que están siendo enviados por el puerto serial. Es una interfaz grafica de usuario que permite visualizar los datos que nuestro PIC está enviando para nosotros (esta es una alternativa si no deseas hacer la interfaz gráfica). Puedes descargarlo dando CLICK AQUI.
Para obtener los códigos del 18F4550 USB basta simplemente compartir el contenido de este post con cualquiera de los siguientes botones, de esa forma ayudas que más personas aprendan sobre estos temas.
>> DESCARGAR TODOS LOS ARCHIVOS <<
#include <18F4550.h> #device ADC=10 #fuses HSPLL, NOWDT, NOPROTECT, NODEBUG, USBDIV, PLL5, CPUDIV1, VREGEN #use delay(clock=48000000) #byte porta = 0xf80 // Identificador para el puerto A. #byte portb = 0xf81 // Identificador para el puerto B. #byte portc = 0xf82 // Identificador para el puerto C. #byte portd = 0xf83 // Identificador para el puerto D. #byte porte = 0xf84 // Identificador para el puerto E. //#define USB_CONFIG_PID 0x000A //#define USB_CONFIG_VID 0x04D8 // if USB_CDC_ISR is defined, then this function will be called // by the USB ISR when there incoming CDC (virtual com port) data. // this is useful if you want to port old RS232 code that was use // #int_rda to CDC. #define USB_CDC_ISR() RDA_isr() // in order for handle_incoming_usb() to be able to transmit the entire // USB message in one pass, we need to increase the CDC buffer size from // the normal size and use the USB_CDC_DELAYED_FLUSH option. // failure to do this would cause some loss of data. #define USB_CDC_DELAYED_FLUSH #define USB_CDC_DATA_LOCAL_SIZE 128 static void RDA_isr(void); // Includes all USB code and interrupts, as well as the CDC API #include <usb_cdc.h> #include <stdlib.h> #include <string.h> #define USB_CON_SENSE_PIN PIN_B2 //No usado cuando alimentado desde el USB #define LED1 PIN_B4 #define LED2 PIN_B5 int deg=0; //Define la interrupción por recepción Serial static void RDA_isr(void) { while(usb_cdc_kbhit()) { int i=0,ini=0,fin=0; char dat[5]; char degC[5]; // Almacena 5 datos leidos del USB CDC for(i=0;i<5;i++){ dat[i]=usb_cdc_getc(); } //Busco el valor de los datos recibidos for(i=0;i<5;i++){ if(dat[i]=='S'){ ini=i+1; i=10; } } for(i=ini;i<5;i++){ if(dat[i]=='$'){ fin=i-1; i=10; } } if(ini!=0 && fin!=0){ // salvo en degC el caracter con el escalon for(i=ini;i<=fin;i++){ degC[i-ini]=dat[i]; } deg = atol(degC); //Convierte el String en un valor numerico if(deg==101) output_toggle(LED1); if(deg==102) output_toggle(LED2); } } } void main(){ int16 v=0; float p; char msg[32]; setup_adc_ports(AN0); setup_adc(ADC_CLOCK_INTERNAL); set_adc_channel(0); set_tris_b(0b00000100); bit_clear(portb,4); bit_clear(portb,5); usb_cdc_init(); usb_init(); //enable_interrupts(INT_RDA); //Habilita Interrupción por serial (Recepcion USB_CDC) //enable_interrupts(GLOBAL); //Habilita todas las interrupciones while(true){ usb_task(); //Verifica la comunicación USB if(usb_enumerated()) { v = read_adc(); p=5.0 * v / 1023.0; sprintf(msg,"I%1.2fFI%1.2fFI%1.2fF",p,p,p); printf(usb_cdc_putc,"%s",msg); delay_ms(1000); } } }
Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:
👉 Invitar a Sergio a un Café ☕️
Que esten muy bien, nos vemos en la siguiente entrada.
Mi nombre es Sergio Andres Castaño Giraldo, y en este sitio web voy a compartir una de las cosas que mas me gusta en la vida y es sobre la Ingeniería de Control y Automatización. El sitio web estará en constante crecimiento, voy a ir publicando material sobre el asunto desde temas básicos hasta temas un poco más complejos. Suscríbete al sitio web, dale me gusta a la página en Facebook y únete al canal de youtube. Espero de corazón que la información que comparto en este sitio, te pueda ser de utilidad. Y nuevamente te doy las gracias y la bienvenida a control automático educación.