sexta-feira, abril 25, 2014

Comunicação Bluetooth entre Arduino e Android - Configuração do módulo BT.

Embora você possa usar o módulo Bluetooth com a configuração de fábrica, você provavelmente vai querer alterar os parâmetros de conexão. Neste post veremos como fazer isto.


Novamente esbarramos na escassez de documentação. O arquivo BT_HC06.pdf (que você encontra nos arquivos do blog) contem algumas informações úteis, apesar de não se referir especificamente ao módulo que estou usando.

A configuração é feita através de "comandos AT" enviados pela interface serial. Os comandos AT foram criados pela Hayes em 1981 e vem sendo sistematicamente abusados desde então. O módulo BT aceita apenas quatro comandos, e de forma totalmente rudimentar. Os comandos devem obrigatoriamente ser enviados em maiúscula e em caso de erro são silenciosamente ignorados. O módulo aceita os comandos AT somente quando não está conectado a um mestre através do rádio.

A determinação do início e do fim do comando é feito por tempo, seguindo as recomendações cifradas do documento adotei uma pausa de 1 segundo antes do primeiro caracter e uma pausa de 1 segundo após o último. O final da resposta (em caso de sucesso) também precisa ser determinado por tempo.

O primeiro comando consiste simplesmente de "AT" (sem as aspas); a resposta para este comando é "OK" (também sem aspas). Este comando é útil para confirmar que o módulo está entendendo os comandos que estamos enviando.

O segundo comando é "AT+BAUDn", onde n é um dígito de 1 a 9 ou uma das letras A, B e C. Este comando determina a velocidade da comunicação serial do módulo (no caso, o Arduino). Já deu para perceber a pegadinha? Para configurar uma nova velocidade você precisa saber qual a velocidade atual. O documento tem a tabela das velocidades (1=1200, 2=2400, 3=4800, 4=9600, etc). Eu tenho usado a velocidade de 9600, que é a padrão de fábrica. A resposta ao comando é "OKnnnnn", ainda na velocidade antiga (nnnn é 1200, 4800, 9600, etc).

O próximo comando é "AT+NAMExxxxx". Este comando altera o "Bluetooth name", que é uma das identificações que o Android vai receber quando procurar dispositivos BT para se conectar (para o caso de você estar curioso, a outra identificação é o endereço MAC do módulo). Este nome pode ter até 20 caracteres. A resposta a este comando é "OKsetname".

Por último temos "AT+PINnnnn", que define a senha (ou PIN) que deve ser fornecida para "parear" o módulo com um mestre (veremos mais sobre isto em um post futuro, quando falarmos no processo de conexão no lado do Android). A senha (nnnn) são sempre quatro dígitos (ou seja, de 0000 a 9999). A resposta ao comando é "OKsetPIN".

Com estas informações, podemos fazer um pequeno programa que programa o módulo para velocidade de 9600, nome DQSOFT e senha 4321..
  1. // Configura o módulo Bluetooth  
  2.   
  3. #include <SoftwareSerial.h>  
  4.   
  5. // Módulo ligado aos pinos 10 (TXD) e 11 (RXD)  
  6. SoftwareSerial BTSerial(10, 11);  
  7.   
  8. // Iniciação  
  9. void setup ()  
  10. {  
  11.   char resp[40];  
  12.     
  13.   // Serial ligada ao PC  
  14.   Serial.begin(19200);  
  15.     
  16.   // Espera digitar algo no PC  
  17.   while (Serial.available() == 0)  
  18.     ;  
  19.   Serial.read();  
  20.     
  21.   // Procura a velocidade atual  
  22.   unsigned int baud[] = { 2400, 4800, 9600, 19200, 38400, 57600 };  
  23.   for (int i = 0; i < 6; i++)  
  24.   {  
  25.     Serial.print ("Tentando ");  
  26.     Serial.print (baud[i]);  
  27.     Serial.print ("bps\r\n");  
  28.     BTSerial.begin(baud[i]);  
  29.     enviaCmd ("AT");  
  30.     leResp (resp, sizeof(resp));  
  31.     if (strcmp ((const char *)resp, "OK") == 0)  
  32.     {  
  33.       Serial.print ("Achou\r\n");  
  34.       // Programa 9600  
  35.       enviaCmd ("AT+BAUD4");  
  36.       leResp (resp, sizeof(resp));  
  37.       Serial.print (resp);  
  38.       Serial.print ("\r\n");  
  39.       BTSerial.end();  
  40.       break;  
  41.     }  
  42.     BTSerial.end();      
  43.     delay(500);  
  44.   }  
  45.   
  46.   // Configurar os demais parametros    
  47.   BTSerial.begin(9600);  
  48.   enviaCmd ("AT");  
  49.   leResp (resp, sizeof(resp));  
  50.   if (strcmp ((const char *)resp, "OK") == 0)  
  51.   {  
  52.     enviaCmd ("AT+NAMEDQSOFT");  
  53.     leResp (resp, sizeof(resp));  
  54.     Serial.print (resp);  
  55.     Serial.print ("\r\n");  
  56.     enviaCmd ("AT+PIN4321");  
  57.     leResp (resp, sizeof(resp));  
  58.     Serial.print (resp);  
  59.     Serial.print ("\r\n");  
  60.   }  
  61. }  
  62.   
  63. // Programa principal, não faz nada  
  64. void loop ()  
  65. {  
  66. }  
  67.   
  68. // Rotina para enviar um comando AT  
  69. void enviaCmd (char *cmd)  
  70. {  
  71.   unsigned long to;  
  72.   char c;  
  73.     
  74.   delay(1000);  
  75.   while (*cmd != 0)  
  76.   {  
  77.     BTSerial.write (*cmd++);  
  78.   }  
  79.   delay(1000);  
  80. }  
  81.   
  82. // Rotina para ler a resposta do módulo  
  83. int leResp (char *buf, int tam)  
  84. {  
  85.   int n = 0;  
  86.   int cont = 0;  
  87.   int c;  
  88.   unsigned long to = millis() + 500;  // timeout inicial  
  89.   while (n < (tam-1))  
  90.   {  
  91.     if (BTSerial.available() > 0)  
  92.     {  
  93.       c = BTSerial.read();  
  94.       cont++;  
  95.       if (cont > 100)  
  96.         break;  // provavelmente recebendo continuamente lixo  
  97.       if ((c > 0x1F) && (c < 0x7F))  
  98.         buf[n++] = (c > 0x5F) ? c - 0x20 : c;  
  99.       to = millis() + 200;  // rearma o timeout  
  100.     }  
  101.     if (millis() >= to)  
  102.     {  
  103.       break;  // timeout  
  104.     }  
  105.   }  
  106.   buf [n] = 0;  
  107.   return n;  
  108. }  
No próximo post vamos começar a ver o lado do Android.

5 comentários:

Unknown disse...

Amigo esse código funcionou para você? Não esta dando certo para mim

Daniel Quadros disse...

Funcionou sim. Confira se você ligou corretamente o módulo ao Arduino, conforme descrito no post anterior.

Unknown disse...

Daniel, poderia comentar o que significa cada linha dessa parte do código:

void enviaCmd (char *cmd)
{
unsigned long to;
char c;

delay(1000);
while (*cmd != 0)
{
BTSerial.write (*cmd++);
}
delay(1000);
}

Desde já, agradeço

Daniel Quadros disse...

Bruno, não tem nada de especial nesta parte (fora a declaração desnecessária de to, que deve ter sobrado de alguma edição). A rotina recebe o ponteiro para um comando (cmd), que é uma sequência de caracteres encerrada por 0 (como é costume em C). Dá uma pausa de 1 segundo, que é a forma de indicar para o módulo o início do comando. Em seguida são enviados ao módulo os caracteres do comando. Por último, uma nova pausa de 1 segundo para indicar o fim do comando.

Unknown disse...

Certo. Obrigado.