Electrónica y programación para Microcontroladores.

Libros técnicos para electrónica programable.

Email
Contactanos en:

consultas@firtec.com.ar

Arduino

Bluetooth HC05/HC06

 

Los módulos de bluetooth  HC-05 y HC-06 son módulos muy populares para aplicaciones con microcontroladores.
Se trata de dispositivos relativamente económicos y que habitualmente se venden en un formato que permite insertarlos en un protoboard y cablearlo directamente a cualquier microcontrolador, incluso sin realizar soldaduras.

El HC-05.

El módulo de bluetooth HC-05 es Maestro-Esclavo, quiere decir que además de recibir conexiones desde una PC o tablet, también es capaz de generar conexiones hacia otros dispositivos bluetooth. Esto nos permite por ejemplo, conectar dos módulos de bluetooth y formar una conexión punto a punto para transmitir datos entre dos microcontroladores o dispositivos.

El HC-05 tiene un modo de comandos AT que debe activarse mediante un estado alto en el marcado “Key” mientras se enciende o se resetea el módulo. Una vez que estamos en el modo de comandos AT, podemos configurar el módulo bluetooth y cambiar parámetros como el nombre del dispositivo, password, modo maestro/esclavo, etc.

Para comunicarnos con el módulo y configurarlo, es necesario tener acceso al módulo mediante una interfaz serial.
Muchas personas,
incluso comercios en internet venden el HC-06 y HC-05 como un mismo módulo, debido a que esencialmente el hardware es el mismo para ambos, la diferencia real es el firmware que viene cargado de fábrica en cada uno de ellos.
El puerto serie en modo de configuración para el HC-05 debe configurarse de la siguiente manera: 34800 bps, 8 bits de datos, sin paridad, sin control de flujo.
Si buscamos cambian algo de su configuración por defecto podemos seguir los siguientes pasos:

  1. Poner a estado alto en el pin "KEY".
  2. Conectar la alimentación del módulo (o resetearlo de preferencia).
  3. Enviar un comando AT\r\n para comprobar que estemos en modo de comando AT.

La siguiente lista es una compilación de algunos comandos importantes, el resto de comando se pueden consultar el la hoja de datos del módulo.

AT\r\n      Comando de prueba, debe responder con OK\r\n
AT+ROLE=1\r\n      Comando para colocar el módulo en modo Maestro (Master)
AT+ROLE=0\r\n       Comando para colocar el módulo en modo Esclavo (Slave)
AT+VERSION?\r\n      Obtener la versión del firmware
AT+UART=115200,1,2\r\n      Configurar el modo de funcionamiento del puerto serie en “modo puente”
AT+PIO=10,1\r\n      Colocar el pin de IO de propósito general a nivel alto

Al módulo HC-05 siempre debemos enviarle \r\n para finalizar cada comando, por lo que debemos configurar nuestro programa de terminal serial para que siempre envíe \r\n al final de cada linea.

El HC-06

El HC-06 tiene un firmware distinto, un módulo es esclavo y otro es maestro, también un funcionamiento distinto en cuanto a su modo de configuración. Para poder configurar el HC-06 es necesario que este NO este emparejado ni siendo usado por ningún dispositivo.
De igual forma que el HC-05 es necesario conectarlo a la PC mediante una interfaz serial para darle instrucciones de configuración (Comandos AT).

El módulo HC-06 acepta un set muy básico de comandos, que permite pocas configuraciones, pero sin duda muy útil para personalizar este económico módulo y configurarlo para satisfacer las necesidades de la aplicación.
Es de remarcar que para usar estos módulos no es necesario cambiar nada en su configuración, esto es solo válido si la necesidad de uso lo exige, pero el módulo en si mismo ya es operativo.

Para configurar el Baudrate los pasos de configuración son los siguientes:

Envíar: AT+BAUD<Numero>

El parámetro número es un caracter hexadecimal de ‘1’ a ‘c’ que corresponden a los siguientes Baud Rates: 1=1200, 2=2400, 3=4800, 4=9600, 5=19200, 6=38400, 7=57600, 8=115200, 9=230400, A=460800, B=921600, C=1382400

Recibe: OK<baudrate>

Configurar el Nombre de dispositivo Bluetooth:

Envíar: AT+NAME<Nombre>

Recibe: OKsetname

Configurar el código PIN de emparejamiento:

Envíar: AT+PIN<pin de 4 digitos>

Recibe: OK<pin de 4 digitos>

Obtener la version del firmware:

Enviar: AT+VERSION

Recibe: Linvor1.8

No es necesario finalizar el comando con \r\n, pero si es necesario ingresar los comandos con todos los caracteres seguidos sin pausas. NO hay necesidad de dar “Enter” para finalizar un comando. El modulo tiene un Temporizador que hace necesario introducir el comando de una sola vez, sin pausas entre los caracteres.

Por lo anterior, si utilizamos un emulador de terminal hay que pegarlos como si fuera un string o una cadena de caracteres  y no escribirlos uno a uno con el teclado. Todas las letras de los comandos van en mayúsculas ya que de lo contrario, no funcionarán.

Uso practico con microcontroladores.

El uso de estos módulos con microcontroladores es relativamente sencillo.

Se puede ver aquí un microcontrolador PIC conectado a un HC-06 al que no se ha modificado nada en su configuración interna, simplemente se lo conectó al microcontrolador y ya funciona perfecto.

La recepción de los datos, en este caso la hace una computadora con su Bluetooth interno corriendo Linux Debian. Los datos recibidos son el voltaje medido en el punto medio del potenciómetro conectado a un canal analógico del PIC y la parte gráfica en Liunux está en Python.

Desde luego que los datos pueden ser recibidos con cualquier dispositivo que tenga Bluetooth, también podemos guardar los datos en una base de datos.
En este ejemplo se ha usado MySQL que podemos correrlo en Windows, Linux, etc. y la base de datos almacena la temperatura de un sensor DS18B20 enviado por Bluetooth desde un PIC.

Luego podríamos, por ejemplo consultar estos datos via web, en la imagen se aprecian los datos en una tabla MySQL, y se consulta la base de datos desde una pagina en PHP. El servidor usado en el ejemplo es Apache que también corre en Windows, Linux, Unix, etc.

 

Con un esquema así se podría, por ejemplo, tener una electrónica simple que colecte datos, los envía por medio de Bluetooth, RS-232, 485, socket, etc, etc, a un concentrador, este los almacena en una base de datos y desde cualquier lugar del mundo, consultar estos datos por Internet.

El adquisidor de datos podría ser un simple PIC puesto en terreno, el concentrador una placa Raspberry, o cualquier microcontrolador con capacidad para contener una base de datos MySQL y el STACK TCP-IP y el acceso remoto, cualquier dispositivo con capacidad de navegar por Internet.
Armar algo de este tipo tiene un costo muy bajo si lo comparamos con un PLC, o incluso algún dispositivos para el control domótico, sobre todo si pensamos que los datos guardados en la base de datos podrían ser fotos de un sistema de seguridad o incluso vídeos de una cámara de vigilancia.

 


 

El chip PCF8591 realiza conversiones digitales con una resolución de 8 bits y un A/D de aproximaciones sucesivas, incorpora también un conversor D/A, todo controlado mediante el bus I2C. El chip incorpora pines de direccionamiento por hardware (Igual que las memorias I2C), un pin de salida analógica para el DAC y entrada de Vref. Esto funcional al DAC como al ADC.

Funcionamiento.

En este ejemplo lo vemos trabajar en los dos modos en un programa que se divide en dos partes que son accedidas mediante la acción de un botón conectado en el pin RA0 de un PIC18F4620.
En el modo por defecto el PIC recibe los datos de dos canales (A0 y A1) enviados por I2C desde el PCF8591, luego actuando sobre el botón en RA0 enviamos al módulo DAC el número 128 lo que pondrá en la salida analógica el 50% de la tensión de alimentación aproximadamente. Puede ver a continuación el programa completo para el manejo de este dispositivo con XC8 y MPLAB X.
(Para mas detalles consulte la hoja de datos del chip).

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* *********************************************************************************
**  Nombre       : PCF8591.c
**  Descripcion  : Midiendo en dos canales del ADC y funcionamiento del DAC
**  Target       : PIC18F4620
**  Compilador   : Microchip XC8
**  XTAL         : 20MHZ  
** *********************************************************************************
 El pulsador colocado en RA0 controla el flujo del programa.
***********************************************************************************/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <plib/i2c.h>
//#include "PCF8591.h"
 
#pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF
 
#include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\PCF8591.X\lcd_xc8.c"
#include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\PCF8591.X\lcd_xc8.h"
 
#ifndef _XTAL_FREQ
 #define _XTAL_FREQ 20000000
#endif
 
static  bit bandera1 = 0;    // Bandera para cambiar el canal.
unsigned char bandera2 = 0;
char Str_float[5];       // Cadena para convertir el float en ASCII.
float voltaje = 0.00;    // Contenedor para guardar la medición.
 
unsigned char  Lee_Byte( unsigned char ByteControl, unsigned char Direccion)
{
	unsigned char Valor;
	IdleI2C();                 // El modulo esta activo?
	StartI2C();                // Condicion de START
	while ( SSPCON2bits.SEN ); // Espera a que la condición de inicio termine
	WriteI2C( ByteControl );
	WriteI2C( Direccion );
 
	RestartI2C();                // Envia ReStart
	while ( SSPCON2bits.RSEN );  // Si se ha recibido el byte sigue
	WriteI2C( ByteControl | 0x01 ); // Cambia bit0 de ByteControl a 1 para realizar lectura.
	Valor=ReadI2C();		// Realiza lectura.
	NotAckI2C();                   // Envia NACK
	while ( SSPCON2bits.ACKEN );   // Espera a que de ASK termine
	StopI2C();                     // Condicion de STOP
	while ( SSPCON2bits.PEN );     // Espera a que la condición de stop termine
	return ( Valor );              // Retorna Lectura
}
//-------------------- FUNCIÓN PARA EL CONTROL DEL ADC -------------------------
void ADC(void){
      switch(bandera1){   // Se discrimina en cual canal se medirá.
   case 0:{             // Si es "0" se lee en el canal cero.
     voltaje =Lee_Byte(0x90,0); // En voltaje se guarda el dato desde el A/D.
     __delay_ms(10);
     bandera1 =1;        // Se cambia bandera para el siguiente canal.
    break;
   }
case 1:{
     voltaje =Lee_Byte(0x90,1);
     __delay_ms(10);
     bandera1 =0;
    break;
   }
 }
   voltaje = (voltaje*5.0)/256; // Se escala el valor para medir entre 0 y 5V
   sprintf(Str_float,"%1.2f ",voltaje); // El float es convertido a ASCII
   if(bandera1 ==0)      // Si bandera es cero se coloca el cursor en el lugar
   lcd_gotoxy(4,2);     // indicado junto al cartel que le corresponde.
   else
    lcd_gotoxy(13,2);   // Si bandera es uno se coloca el cursor en el lugar
   lcd_puts(Str_float); // indicado junto al cartel que le corresponde.
}
//--------------- FUNCIÓN VERIFICA LA PRESENCIA DEL PCF8591 --------------------
void check_PCF8591(unsigned short dir){
 StartI2C();            // Condición de inicio en el bus.
 if (WriteI2C(dir)){    // Escribe la direción del chip en el bus.
  lcd_gotoxy(2,2);      // Si retorna "1" no hay sensor en el bus.
lcd_putrs("PCF8591 ERROR!!");  // Aviso de que no hay sensor en el BUS.
while(1);               // Programa termina.
 }
 else {
     lcd_gotoxy(3,1);
     lcd_putrs("Chip PCF8591");  // Cartel incial para indicar la presencia
 }                               // del chip en el bus I2C.
     StopI2C();
}
//--------------------- FUNCION PRINCIPAL DEL PROGRAMA -------------------------
void main() {
 
TRISA=0X01;	// Configura el pin 2 como entrada digital 
ADCON1 = 0X0F; 	// Configura los pines del PORT A como I/O Digitales
 
  OpenI2C(MASTER,SLEW_OFF);  	// Modo Master.
  SSPADD = 49;			// 100KHz para 20MHz.
  
 lcd_init();            // Configura el LCD a valores por defecto.
 check_PCF8591(0x90);   // Verifica la presencia del chip en el BUS.
 
 while(1) {
 // El boton en RA0 es el encargado de cambiar al DAC o al ADC
   if(PORTAbits.RA0!=1 && bandera2== 1){
    while(!PORTAbits.RA0);   // Espera a que el boton se suelte
    lcd_gotoxy(1,2);
 lcd_putrs("                "); // Limpia la línea inferior para el ADC
 bandera2=0;   // Coloca la bandera para que el ADC sea el modo por defecto
   }
   if(PORTAbits.RA0!=1 && bandera2== 0){ // Pasa al modo DAC
   while(!PORTAbits.RA0);  // Espera a que el boton se suelte
   bandera2++;
   lcd_gotoxy(1,2);
   lcd_putrs("  Conversor DAC ");
  StartI2C(); 
  WriteI2C(0x90);
   __delay_ms(2);
   WriteI2C(0x40);   // Coloca el chip en modo DAC
   __delay_ms(2);
   WriteI2C(128);   // Saca por el pin analógico 2.5V aprox. (256/2=128)
   StopI2C();       // Condición de STOP
   while ( SSPCON2bits.PEN ); // Espera que termine la condición de STOP
   }
  if(bandera2==0){  // Si bandera es 0 se activa el modo por defecto (ADC)
 lcd_gotoxy(1,2);       // Coloca los carteles para los canales analógicos
  lcd_putrs("A0:");
    lcd_gotoxy(10,2);
     lcd_putrs("A1:");
      ADC();         // LLama a la función del conversor analógico
  }
 }
}
 

 

 

 El ejemplo funcionando.

Material extraído de nuestro libro Introducción al C para PIC. 


 

El chip TC74 es un sensor de temperatura serie accesible a través del bus I2C fabricado por Microchip Technology que mide con una resolución de 1°C.
La temperatura está disponible en un byte que es almacenado en un registro interno.
El dato de temperatura es almacenado en formato binario con complemento a 2 y el bit más significativo es el bit de signo, que se establece en 1 para temperaturas negativas por lo tanto, la temperatura máxima positiva es de + 127 ° C (0111 1111). También existe otro registro de configuración (RWCR) que se utiliza para poner el dispositivo en bajo consumo (5μA), en este modo se detiene el convertidor A / D.

El programa para medir temperaturas con XC8 y un PIC18F460 es realtivamente simple.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* ******************************************************************************************
**  Nombre       : TC74A3.c
**  Descripcion  : Sensor de Microchip I2C de 8 bits. (-40 a +125 grados)
**  Target       : PIC18F4620
**  Compilador   : Microchip XC8
**  XTAL         : 20MHZ 
**  www.firtec.com.ar 
** *******************************************************************************************/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <plib/i2c.h>
#pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF
 
#include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\TC74.X\lcd_xc8.c"
#include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\TC74.X\lcd_xc8.h"
 
#ifndef _XTAL_FREQ
 #define _XTAL_FREQ 20000000
#endif
 
void delay(unsigned int t){ // Mínimo argumento 2!!!! tarda 1mS.
while(--t)
    __delay_ms(1);
}
unsigned short num=0;
const int TC74A3 = 0x96; // Dirección I2C del sensor
 
//------------------------ FUNCIÓN PARA VERIFICAR EL SENSOR --------------------
void check_sensor(unsigned short dir){
 StartI2C();
 if (WriteI2C(dir)){
  lcd_gotoxy(1,2);
lcd_putrs("Sensor ERROR!!");     // Aviso NO hay sensor en el BUS!!!
while(1);
 }
 else {
     lcd_gotoxy(2,1);
     lcd_putrs("Sensor TC74A3");  // Cartel incial si detecta sensor.
 }
     StopI2C();
}
//---------------------- FUNCIÓN PARA LEER LA TEMPERTAURA ----------------------
unsigned short Leer_Temp(){
unsigned short dato;
 IdleI2C();                     // Pregunta si el bus está libre.
  StartI2C();                   // Pone la condición de inicio.
    IdleI2C();                  // Espera que termine.
     WriteI2C(TC74A3);          // Direcciona el sensor
 while(SSPCON2bits.ACKSTAT);    // Espera el ACK
         IdleI2C();             // Espera por el bus libre.
         WriteI2C(0x00);        // Escribe la dir 0 (registro de la temp)
while(SSPCON2bits.ACKSTAT);     // Espera el ACK
   IdleI2C();                   // Espera a que el bus esté libre
     RestartI2C();              // Re-inicio del bus
       IdleI2C();               // Espera que termine
         WriteI2C(TC74A3+1);    // Envía órden de lectura en la dir. 0
           while(SSPCON2bits.ACKSTAT);  // Espera por ACK
            dato = ReadI2C();           // Lee el registro y lo guarda en dato
             IdleI2C();                 // Espera que termine
               NotAckI2C();             // No hay ACK
                IdleI2C();              // Espera que termine
                 StopI2C();             // Condición de fin de transacción.
 return dato;                           // Retorna la temperatura
}
//--------------------- FUNCION PRINCIPAL DEL PROGRAMA -------------------------
void main() {
  char temperatura[] = "000";
 
  OpenI2C(MASTER,SLEW_OFF);  	// Modo Master
  SSPADD = 49;			// 100KHz para 20MHz
  
 lcd_init();	                // Configura el LCD a valores por defecto.
 lcd_gotoxy(1,2);
 lcd_putrs("Grados:");          // Cartel inicial II.
 check_sensor(TC74A3);          // Verifica la presencia del sensor en el BUS.
  while(1) {
    num = Leer_Temp();          // Lee la temperatura desde el sensor.
   if (num > 127) {             // Verifica si la temperatura es negativa.
       num = ~num +1;           // Complementa y ajusta la temperatura si es negativa
       sprintf(temperatura,"-%d ",num); // Completa el string para el LCD
   }
   else{
   sprintf(temperatura,"+%d ",num); // Temperatura positiva.
       }
   lcd_gotoxy(8,2);
   lcd_puts(temperatura);          // Muestra la teperatura.
   delay(500);
  } 
}
 

 

 

 

Descargar el proyecto completo para MPLAB X.

 

 

 

 

 

 

Emulando un puerto RS-232 con USB.

Como sabemos el puerto USB puede funcionar de distintas formas dependiendo del tipo de dispositivo que conectemos en el. (Cámaras de fotos, teclados, Memorias, etc) .
Cada uno de estos dispositivos están “clasificados” dentro de la arquitectura del USB.
Universal Serial Bus Communication Device Class (USB CDC) es una de esas clases que emula un puerto serial clásico (RS-232) y para poder implementarlo en nuestro Cortex M4 de STM vamos a necesitar los correspondientes drivers provistos por STM.

Como todo programa en C el punto de entrada a nuestra aplicación es main.c y configura los LED´s de la placa entrenadora para que se comporten de forma tal que nos pueda dar indicios de su estado operativo por ejemplo si todo ha sido correcto en la ejecución del código tendremos un LED destellando en la placa, también configura el USB de nuestro micro en modo CDC y cuando la computadora enumere nuestro dispositivo otro LED indicará que está listo para trabajar.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*************************************************************
*  Nombre       : VCP.c
*  Descripción  : Demo para el Com Virtual (USB_CDC)         
*  Target       : STM32F407VG
*  ToolChain    : MDK-ARM
*	 www.firtec.com.ar
***************************************************************/
#include "stm32f4xx.h"
#include "usbd_cdc_core.h"
#include "usbd_cdc_vcp.h"
#include "usbd_usr.h"
#include "usbd_desc.h"
 
__ALIGN_BEGIN USB_OTG_CORE_HANDLE    USB_OTG_dev __ALIGN_END ;
 
void Delay(__IO uint32_t nTick);
 
int main(void)
{
   uint32_t i = 0;  
// Configura los perifericos de la placa entrenadora
  STM32F4_Discovery_LEDInit(LED3);
  STM32F4_Discovery_LEDInit(LED4);
  STM32F4_Discovery_LEDInit(LED5);
  STM32F4_Discovery_LEDInit(LED6);
  STM32F4_Discovery_PBInit(BUTTON_USER, BUTTON_MODE_EXTI);
  
  STM32F4_Discovery_LEDOn(LED3); // LED naranja encendido  
 
// Configura el puerto USB en modo CDC	
  USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,
	          &USR_desc,&USBD_CDC_cb,&USR_cb);	
 
  while (1)
  {
    if (i++ == 0x100000)
    {  // Enciende/Apaga LED verde
    	STM32F4_Discovery_LEDToggle(LED4); 
    	i = 0;
    }
  }
}
 

 

El objetivo de este trabajo es que nuestro micro nos conteste como un eco lo que se escribe en la terminal también si oprimimos el botón de usuario se dispara una interrupción que envía un mensaje con la palabara Firtec.

La aplicación será controlada por el archivo usbd_cdc_vcp.c  que contiene todas las funciones operativas para el envío de datos por el puerto virtual.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*************************************************************
*  Nombre       : usbd_cdc_vcp.c
*  Descripción  : Capa de para acceder al medio USB_CDC        
*  Target       : STM32F407VG
*  ToolChain    : MDK-ARM
*	 www.firtec.com.ar
***************************************************************/
 
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED 
#pragma     data_alignment = 4 
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
 
#include "usbd_cdc_vcp.h"
#include "stm32f4_discovery.h"
 
LINE_CODING linecoding =
  {
    115200, /* baud rate*/
    0x01,   /* stop bits-1*/
    0x00,   /* sin paridad*/
    0x08    /* cantidad de bits 8*/
  };
 
 
USART_InitTypeDef USART_InitStructure;
 
/* Variables importadas del nucleo CDC */
extern uint8_t  APP_Rx_Buffer []; /* En este Buffer recibe los datos desde el EndPoint. */
extern uint32_t APP_Rx_ptr_in;    /* Este puntero se utiliza para recorrer APP_Rx_Buffer */
 
/* Prototipos de Funciones */
void DISCOVERY_COM_IRQHandler(void);
static uint16_t VCP_Init     (void);
static uint16_t VCP_DeInit   (void);
static uint16_t VCP_Ctrl     (uint32_t Cmd, uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataTx   (uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataRx   (uint8_t* Buf, uint32_t Len);
 
CDC_IF_Prop_TypeDef VCP_fops =  
{
 VCP_Init,VCP_DeInit,VCP_Ctrl,VCP_DataTx,VCP_DataRx
};
//----------------------------------------------------
 // Estas dos funciones inicializan los medios de
 // comunicaciónes de STM32 (Deben estar en el código)
  static uint16_t VCP_Init(void)
  {
     return USBD_OK;
  }
//----------------------------------------------------
static uint16_t VCP_DeInit(void)
{
      return USBD_OK;
}
//*****************************************************************
// Esta función administra las solicitudes de clase CDC del USB
// Procesa los comandos y retorna OK si todo a salido bien.
//*****************************************************************
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len)
{ 
  switch (Cmd)
  {
  case SEND_ENCAPSULATED_COMMAND:
    /* No es necesario para este driver */
    break;
 
  case GET_ENCAPSULATED_RESPONSE:
    /* No es necesario para este driver */
    break;
 
  case SET_COMM_FEATURE:
    /* No es necesario para este driver */
    break;
 
  case GET_COMM_FEATURE:
    /* No es necesario para este driver */
    break;
 
  case CLEAR_COMM_FEATURE:
    /* No es necesario para este driver */
    break;
	
	case GET_LINE_CODING:
		Buf[0] = (uint8_t) (linecoding.bitrate);
		Buf[1] = (uint8_t) (linecoding.bitrate >> 8);
		Buf[2] = (uint8_t) (linecoding.bitrate >> 16);
		Buf[3] = (uint8_t) (linecoding.bitrate >> 24);
		Buf[4] = linecoding.format;
		Buf[5] = linecoding.paritytype;
		Buf[6] = linecoding.datatype;
		break;
 
	case SET_CONTROL_LINE_STATE:
		/* No es necesario para este driver */
		break;
 
	case SEND_BREAK:
		/* No es necesario para este driver */
		 break;
	 default:
	break;
  }
 return USBD_OK;
}
/***************************************************************************
  *  Función VCP_DataTx
  *   Esta funcion transmite los datos por el USB_CDC 
  *   Buf: Buffer de datos que seran enviados
  *   Len: Numero de datos a envianr (en bytes)
  *   Resultado de la operacion, SBD_OK si falla la operacion VCP_FAIL
  ***************************************************************************/
static uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{	
  	if (linecoding.datatype == 7)
  	{
  	    APP_Rx_Buffer[APP_Rx_ptr_in] = (uint8_t) Len & 0x7F;
  	}
  	else if (linecoding.datatype == 8)
	{
		APP_Rx_Buffer[APP_Rx_ptr_in] = (uint8_t) Len ;
	}
 
	APP_Rx_ptr_in++;
  
	if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
	{
		APP_Rx_ptr_in = 0;
	}
	return USBD_OK;
}
//*********************************************************************************
//  Función:  VCP_DataRx recibe los datos por el USB_CDC.                     
//  Parametro Buf: Búfer de datos recibidos
//  Parametro Len: Número de datos (en bytes)
//  Retorna:  Resultado de la operación, USBD_OK si todo OK,  VCP_FAIL si error
//**********************************************************************************
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{	
	VCP_DataTx (0,* Buf);
	return USBD_OK;
}
 
void DISCOVERY_EXTI_IRQHandler(void) // ISR de la interrupción del botón de usuario.
{
	/* Transmite Firtec cuando se oprime el boton de usurario */
	VCP_DataTx (0, (uint32_t) 'F');
	VCP_DataTx (0, (uint32_t) 'i');
	VCP_DataTx (0, (uint32_t) 'r');
	VCP_DataTx (0, (uint32_t) 't');
	VCP_DataTx (0, (uint32_t) 'e');
	VCP_DataTx (0, (uint32_t) 'c');
	
}
 

 

El proyecto completo para descargar.