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