Arduino - Hardware
Usei um Arduino Nano para facilitar a montagem na protoboard. Além do módulo Bluetooth, coloquei dois LEDs, um sensor de temperatura LM35 e um servomotor. Os LEDs estão ligados a saídas digitais comuns, o servomotor a uma saída digital com PWM e o sensor de temperatura a uma entrada analógica.
O módulo Bluetooth está ligado à serial normal do Arduino. Isto permite testar o software retirando o módulo, ligando o Arduino ao PC via USB e enviando os comandos através de um programa de comunicação normal (como o monitor serial da IDE do Arduino). Por outro lado, é preciso desconectar o módulo para fazer a carga do software e desconectar do micro para a operação com o módulo.
Arduino - Software
Nada de muito especial por aqui. Os comandos consistem em um único dígito, de 0 a 6. A resposta é a leitura do sensor de temperatura, em décimos de grau, sempre com três dígitos (seguidos de CR e LF). A leitura do sensor está descrita no meu post sobre o LM35. Os LEDs são controlados por digitalWrite e o servo pela biblioteca que vem com a IDE do Arduino.
// Exemplo de comunicação por Bluetooth #include <Servo.h> // Alguns dispositivos static const int pin_ledr = 2; static const int pin_ledg = 3; static const int pin_servo = 5; static const int pin_lm35 = A0; static Servo servo; // Iniciação void setup () { // Módulo BT está ligado à serial Serial.begin (9600); // Portas digitais pinMode (pin_ledr, OUTPUT); pinMode (pin_ledg, OUTPUT); servo.attach(pin_servo); servo.write(0); // Sensor de temperatura LM35 analogReference (INTERNAL); } // Loop Principal void loop() { int cmd; if (Serial.available()) { // recebeu um comando cmd = Serial.read(); if ((cmd < '0') | (cmd > '6')) return; // ignora comando inválido // Trata o comando switch (cmd) { case '0': // nop break; case '1': // acende led vermelho digitalWrite (pin_ledr, HIGH); break; case '2': // apaga led vermelho digitalWrite (pin_ledr, LOW); break; case '3': // acende led verde digitalWrite (pin_ledg, HIGH); break; case '4': // apaga led verde digitalWrite (pin_ledg, LOW); break; case '5': // Coloca o servo na posição 0 servo.write(0); break; case '6': // Coloca o servo na posição 180 servo.write(180); break; } // Le o sensor de temperatura int vSensor = analogRead(pin_lm35); long temp = (vSensor*1100L)/1024L; // Monta e envia a resposta char resp[6]; resp[0] = (char) (((temp / 100) % 10) + '0'); resp[1] = (char) (((temp / 10) % 10) + '0'); resp[2] = (char) ((temp % 10) + '0'); resp[3] = '\r'; resp[4] = '\n'; resp[5] = '\0'; Serial.print (resp); } }
Android - UI
Para simplificar, a interface se resume a uma única tela. Nada de muito elaborado (ou bonito), apenas o essencial para testarmos o funcionamento.
Android - Software
O ponto de partida foi o meu exemplo de procura de dispositivos. O principal acréscimo é a thread que cuida da conexão e comunicação. Para fazer a interface entre esta thread e os eventos da UI, usei uma BlockingQueue. O código possui uma detecção de erros bem básica.
private BlockingQueue<byte[]> filaCmd; // Trata botão Acende Led Vermelho private final OnClickListener acendeLedR = new OnClickListener() { @Override public void onClick(View v) { try { filaCmd.put (new byte[] { '1' }); } catch (InterruptedException e) { } } }; // Trata a conexão e comunicação com o Arduino private class ConexaoThread extends Thread { private final BluetoothSocket mmSocket; private InputStream mmInStream; private OutputStream mmOutStream; public ConexaoThread(BluetoothDevice device) { BluetoothSocket tmp = null; // Obtem o socket try { tmp = device.createRfcommSocketToServiceRecord(serialUUID); } catch (IOException e) { // tmp ficará com null } mmSocket = tmp; } public void run() { // Confirma que obteve o socket if (mmSocket == null) { return; } // Garante que não tem um discovery sendo executado mBtAdapter.cancelDiscovery(); // Tenta conectar try { mmSocket.connect(); } catch (IOException connectException) { return; // não conseguiu } // Obtem os streams de entrada e saída try { mmInStream = mmSocket.getInputStream(); mmOutStream = mmSocket.getOutputStream(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException closeException) { } return; } bBtConectado = true; acertaTela(); // Trata a comunicação while (true) { byte[] cmd; try { cmd = filaCmd.take(); // Aguarda um comando if ((cmd == null) || (cmd[0] == '*')) { break; } // Envia o comando mmOutStream.write(cmd); // Le a resposta (timeout de 3 segundos) int available = 0; long limite = System.currentTimeMillis() + 3000; while(((available = mmInStream.available()) < 5) && (System.currentTimeMillis() < limite)) { Thread.sleep(250); } if (available >= 5) { byte[] resp = new byte[available]; mmInStream.read(resp); mostraTemp (resp); } } catch (InterruptedException e) { break; } catch (IOException e) { break; } } // Encerra a comunicação try { mmInStream.close(); mmOutStream.close(); mmSocket.close(); } catch (IOException closeException) { } bBtConectado = false; acertaTela(); } }
Funcionamento
O vídeo abaixo mostra o sistema em funcionamento.
Fontes
Os fontes dos softwares estão nos Arquivos do Blog (veja o link lá no alto à direita), no arquivo DemoBT.zip.
5 comentários:
Amigo obrigado pelo esquema, parabéns.
Quero saber o porque dos resistores no rx e tx. É pra garantir nivel logico 0?
E no pwm tambem é necessario?
Leonardo, como descrito em um post anterior o módulo opera a 3.3V, daí o divisor resistivo no pino Rx. O resistor no pino Tx é um pull-up que garante o nível 1. O PWM está ligado direto a um servo e não precisa de nenhum resistor.
Muito legal, obrigado.
Foi voce quem fez o programa?
Eduardo: sim.
Postar um comentário