
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
}
}