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