Bluetooth HC-05 comunicaciĆ³n half duplex, Pic C Compiler

En esta secciĆ³n aprenderĆ”s a establecer una comunicaciĆ³n inalĆ”mbrica en modo half duplex utilizando dos mĆ³dulos Bluetooth para enviar y recibir datos. El objetivo es establecer la comunicaciĆ³n inalĆ”mbrica entre un PIC Maestro y un PIC Esclavo para enviar comandos o instrucciones para recibir la lectura del valor de un potenciometro o un botĆ³n.

Bluetooth HC-05Ā 

El Bluetooth HC-05 es un mĆ³dulo de comunicaciĆ³n inalĆ”mbrico que utiliza la tecnologĆ­a Bluetooth para establecer un enlace de comunicaciĆ³n serie entre dos dispositivos. Es un dispositivo muy popular en proyectos de electrĆ³nica y robĆ³tica, ya que permite la comunicaciĆ³n inalĆ”mbrica entre un microcontrolador, como Arduino, y otros dispositivos como un ordenador, smartphone o tablet. El HC-05 puede funcionar como maestro o esclavo y utiliza el perfil serial port profile (SPP) de Bluetooth, lo que lo hace compatible con una amplia variedad de dispositivos que soportan este perfil.

CaracterĆ­sticas:

  • TecnologĆ­a: Bluetooth 2.0 + EDR (Enhanced Data Rate)
  • Alcance de comunicaciĆ³n: hasta 10 metros (en condiciones ideales)
  • Velocidad de transmisiĆ³n: 2.1 Mbps mĆ”x. en modo EDR, 721 kbps mĆ”x. en modo estĆ”ndar
  • Frecuencia: 2.4 GHz a 2.4835 GHz banda ISM
  • Potencia de transmisiĆ³n: Clase 2, hasta 4 dBm (2.5 mW)
  • Sensibilidad de recepciĆ³n: -80 dBm tĆ­pico
  • Protocolos de soporte: Bluetooth serial port profile (SPP)
  • Modo de operaciĆ³n: Maestro o Esclavo
  • Compatibilidad: Compatible con dispositivos que soportan Bluetooth SPP
  • Interfaz: UART (Universal Asynchronous Receiver/Transmitter)
  • Voltaje de alimentaciĆ³n: 3.3V a 5V DC
  • Consumo de energĆ­a: 30 mA en modo de operaciĆ³n, 1 mA en modo de espera
  • Dimensiones: 28 mm x 15 mm x 2.35 mm

Circuito de conexiĆ³n

ConfiguraciĆ³n

Inicialmente se deben configurar los mĆ³dulos Bluetooth en modo maestro y esclavo para poder transmitir los datos mediante una comunicaciĆ³n inalĆ”mbrica.

ProgramaciĆ³n PIC Maestro

Inicialmente se establecen los parĆ”metros de la comunicaciĆ³n RS232.

  • baud = Velocidad de transmisiĆ³n y recepciĆ³n configurada en el mĆ³dulo Bluetooth.
  • stop = Bits de parada.
  • parity = Bit de paridad.Ā 
  • xmit = Pin de transmisiĆ³n.
  • rcv = Pin de recepciĆ³n.Ā 
  • bits = Datos de transmisiĆ³n.
  • stream = identificaciĆ³n de transmisiĆ³n.

#use rs232(baud=38400, stop=1, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

Inicialmente esperamos a que los mĆ³dulos bluetooth se vinculen. El pin STATE del mĆ³dulo genera una seƱal digital de Ā«1Ā» cuando el mĆ³dulo bluetooth esta vinculado y Ā«0Ā» cuando no esta vinculado.


#define  state input(pin_d0)

void main()
{  
 
   while (!state)//espera la conexion con el esclavo;
   {}
   .
   .
   .

Una vez que se vinculen los mĆ³dulos Bluetooth, se envĆ­an los comandos por el puerto RS232 para solicitar un valor al PIC esclavo.


      printf("PAN0\r");
      recibe();
      PAN0 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits

La funciĆ³n Ā«printfĀ» envĆ­a un comando por el puerto RS232 para ser enviado por el mĆ³dulo Bluetooth al PIC esclavo.


      printf("PAN0\r");

Para recibir el valor correspondiente al comando se utiliza la sub-rutina Ā«recibe()Ā» donde el valor recibido se guarda en la variable Ā«recibido[]Ā».

En la sub-rutina tambiĆ©n se verifica la conexiĆ³n de los mĆ³dulos Bluetooth, si se llega a perder la conexiĆ³n, el programa retorna a la funciĆ³n Ā«main()Ā».


void recibe()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   int8 i=0;
   while(true)
   {
      if (kbhit())//espera el primer caracter
      {        
         while(true)
         {
            recibido[i]=getc();//RECIBE EL CARACTER

            if(recibido[i]=='\r')//busca el salto de linea \r
            {
               recibido[i]='\0';//fin de la cadena = caracter nulo \0
               return;
            }
            
            i++;
            
            if (!state)//verifica la conexion;
            {
               return;
            }
            
         }
      }
      
      if(!state)//verifica la conexion;
      {
         return;
      }
      
   }
}

Se convierte la cadena caracteres que contiene el valor recibido de la variable Ā«recibido[]Ā» en un valor Ā«int16Ā» y se guarda el valor en una variable Ā«int16Ā» asignada.


 PAN0 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits

Finalmente se muestra el valor correspondiente en el diplay OLED.


void mostrar()
{
   char texto[20];

   sprintf(texto,"PAN0=%04lu",PAN0);
   OLED_DrawText(1,1,texto,1);

   sprintf(texto,"PRD0=%u",PRD0);
   OLED_DrawText(1,10,texto,1);

   OLED_Display();//Muestra la informaciĆ³n en pantalla;
}

CĆ³digo completo PIC Maestro


#include "stdlib.h"

#FUSES NOMCLR

#use i2c(Master,Fast, sda=PIN_B0, scl=PIN_B1, force_sw, stream=OLED_stream)//parametros I2C
#use rs232(baud=38400, stop=1, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

#define SH1106_128_64 //DEFINE EL MODELO DE LA PANTALLA OLED
//#define SSD1306_128_64

#include "OLED_I2C.c" //libreria oled I2C

#define  state input(pin_d0)

char recibido[20];

int16 PAN0=0;
int1 PRD0=0;

void recibe()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   int8 i=0;
   while(true)
   {
      if (kbhit())//espera el primer caracter
      {        
         while(true)
         {
            recibido[i]=getc();//RECIBE EL CARACTER

            if(recibido[i]=='\r')//busca el salto de linea \r
            {
               recibido[i]='\0';//fin de la cadena = caracter nulo \0
               return;
            }
            
            i++;
            
            if (!state)//verifica la conexion;
            {
               return;
            }
            
         }
      }
      
      if(!state)//verifica la conexion;
      {
         return;
      }
      
   }
}


void mostrar()
{
   char texto[20];

   sprintf(texto,"PAN0=%04lu",PAN0);
   OLED_DrawText(1,1,texto,1);

   sprintf(texto,"PRD0=%u",PRD0);
   OLED_DrawText(1,10,texto,1);

   OLED_Display();//Muestra la informaciĆ³n en pantalla;
}


void main()
{

   OLED_Begin();
   OLED_ClearDisplay();

   mostrar();
   
   while (!state)//espera la conexion con el esclavo;
   {}
   
   while(TRUE)
   {

      printf("PAN0\r");
      recibe();
      PAN0 = (int16)atol(recibido);  //convierte la cadena en un numero de 16bits

      printf("PRD0\r");
      recibe();
      PRD0 = (int1)atoi(recibido);  //convierte la cadena en un numero de 8bits

      mostrar();
            
   }
   
}

ProgramaciĆ³n PIC Esclavo

Inicialmente se establecen los parĆ”metros de la comunicaciĆ³n RS232.

  • baud = Velocidad de transmisiĆ³n y recepciĆ³n configurada en el mĆ³dulo Bluetooth.
  • stop = Bits de parada.
  • parity = Bit de paridad.Ā 
  • xmit = Pin de transmisiĆ³n.
  • rcv = Pin de recepciĆ³n.Ā 
  • bits = Datos de transmisiĆ³n.
  • stream = identificaciĆ³n de transmisiĆ³n.

#use rs232(baud=38400, stop=1, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

Se habilita la conversiĆ³n analĆ³gica a digital para los pines analĆ³gicos.


   setup_adc(ADC_CLOCK_INTERNAL);

Se hace la lectura del pin analĆ³gico Ā«AN0Ā» conectado el potenciometro y se guarda el valor en la variable correspondiente.


 set_adc_channel (0); //Habilita el canal AN0
 delay_us(10);
 val_PAN0 = read_adc(); //lectura del potenciometro

Se hace la lectura digital del pin conectado al botĆ³n y se guarda el valor en la variable correspondiente.


 val_PRD0 = input(pin_d0); // lectura del boton

Se habilitan las interrupciones para la recepciĆ³n de datos por el puerto RS232.


   enable_interrupts(int_rda);
   enable_interrupts(global);

Cuando se habilita la interrupciĆ³n, el programa se aloja en la sub-rutina Ā«rda_isr()Ā» para recibir el comando y guardarlo en la variable Ā«recibido[]Ā»


#int_rda
void rda_isr()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   int8 i=0;
   while(true)
   {
      recibido[i]=getc();//RECIBE EL CARACTER

      if(recibido[i]=='\r')//busca el salto de linea \r
      {
         recibido[i]='\0';//fin de la cadena = caracter nulo \0
         enviar();
         return;
      }
      i++;
   }
}

En la sub-rutina Ā«enviar()Ā», se identifica el comando y se envĆ­a el valor correspondiente al comando.


void enviar()
{
   signed int8 result;
   
   int8 PAN0[10] = "PAN0";
   int8 PRD0[10] = "PRD0";

      result = strcmp(recibido, PAN0);
   
      if (result==0)
      {
         printf("%04lu\r",val_PAN0);//envia el valor del pin AN0
         return;
      }     
   
      result = strcmp(recibido, PRD0);
   
      if (result==0)
      {
         printf("%u\r",val_PRD0);//envia el valor del pin RD0
         return;
      }
      
}

La instrucciĆ³n Ā«strcmp()Ā» compara dos cadenas de caracteres, se compara la variable Ā«recibidoĀ» que contiene el comando recibido y la variable Ā«PAN0Ā» que contiene el comando Ā«PAN0Ā», si las dos cadenas de caracteres resultan iguales se envĆ­a el valor correspondiente en la sentencia Ā«if Ā» por el puerto RS232 al PIC maestro, si son diferentes, el programa pasara a la siguiente comparaciĆ³n para encontrar el comando correspondiente al valor que se enviara al PIC maestro.


   int8 PAN0[10] = "PAN0";

 result = strcmp(recibido, PAN0);
   
      if (result==0)
      {
         printf("%04lu\r",val_PAN0);//envia el valor del pin AN0
         return;
      }     

DespuĆ©s de enviar el valor correspondiente al comando recibido, se retorna a la funciĆ³n Ā«main()Ā» para hacer las lecturas de los pines y esperar una nueva interrupciĆ³n para recibir un nuevo comando del PIC maestro.

CĆ³digo completo PIC Esclavo


#include "stdlib.h"

#FUSES NOMCLR

#use rs232(baud=38400, stop=1, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

char recibido[20];

int16 val_PAN0=0;
int1 val_PRD0=0;

void enviar();

#int_rda
void rda_isr()
{
   memset(recibido, 0, sizeof(recibido)); //limpia los registros de la varible
   int8 i=0;
   while(true)
   {
      recibido[i]=getc();//RECIBE EL CARACTER

      if(recibido[i]=='\r')//busca el salto de linea \r
      {
         recibido[i]='\0';//fin de la cadena = caracter nulo \0
         enviar();
         return;
      }
      i++;
   }
}


void enviar()
{
   signed int8 result;
   
   int8 PAN0[10] = "PAN0";
   int8 PRD0[10] = "PRD0";

      result = strcmp(recibido, PAN0);//compara, si son iguales (0), no (+-1)
   
      if (result==0)
      {
         printf("%04lu\r",val_PAN0);//envia el valor del pin AN0
         return;
      }     
   
      result = strcmp(recibido, PRD0);
   
      if (result==0)
      {
         printf("%u\r",val_PRD0);//envia el valor del pin RD0
         return;
      }
      
}

void main()
{

   enable_interrupts(int_rda);
   enable_interrupts(global);

   setup_adc(ADC_CLOCK_INTERNAL);
   
   while(TRUE)
   {   
       set_adc_channel (0); //Habilita el canal AN0
       delay_us(10);
       val_PAN0 = read_adc(); //lectura del potenciometro

       val_PRD0 = input(pin_d0); // lectura del boton
   }
}
Scroll al inicio