⬤ Avançado

📶 Bluetooth HM-10 BLE

⏱️ 45 min 🧩 HM-10 BLE — D0 (RX) · D1 (TX)

Exercícios

📌 Pinagem na placa de interface

MóduloConector InterfacePino ArduinoNotas
RX — Recebe dadosBLE_RXD0 (RX)Recebe do telemóvel via UART
TX — Envia dadosBLE_TXD1 (TX)Envia para o telemóvel via UART
VCC3.3V3.3V⚠️ 3.3V — nunca ligar directamente a 5V
GNDGNDGND—
⚠️
IMPORTANTE — Upload de código: O HM-10 partilha os pinos D0/D1 com a porta USB do Arduino. Desliga sempre o fio do pino D0 (RX) do HM-10 antes de fazer upload de um novo sketch. Depois do upload, volta a ligar. Se esqueceres, o upload falha com erro de comunicação.
⚠️
Tensão de alimentação: O HM-10 opera a 3.3V — nunca a 5V (danifica o módulo). A placa de interface do Kit C já tem o divisor de tensão necessário para os pinos de dados.

ℹ️ Como funciona o BLE?

🤖 Arduino UNO

Serial.print() envia dados
Serial.read() recebe dados
via UART a 9600 baud

📶
BLE 4.0
até ~10m

📱 Telemóvel Android

App BLE Terminal
envia caracteres
recebe dados dos sensores

ℹ️
BLE vs Bluetooth Clássico: O HM-10 usa Bluetooth Low Energy (BLE) 4.0 — não é compatível com módulos HC-05/HC-06 (Bluetooth clássico). Usa exclusivamente apps que suportem BLE UART (GATT). Funciona na maioria dos telemóveis Android ≥ 4.4 e iOS ≥ 6.

📱 Aplicação para o Telemóvel

Escolhe uma das seguintes apps gratuitas para comunicar com o HM-10:

📟
Serial Bluetooth Terminal
App simples com terminal de texto. Suporta BLE. Ideal para testar comandos.
Android
🔵
nRF Connect
App oficial da Nordic. Muito completa para desenvolvimento BLE.
Android iOS
📱
BLE Terminal HM-10
Aplicação específica para módulos HM-10. Interface simples e directa.
Android
🤖
MIT App Inventor
Criar uma app personalizada com blocos. Perfeito para projetos escolares.
Android
💡
Recomendado para iniciantes: Usa Serial Bluetooth Terminal para testar os exercícios 1, 2 e 3. Para o exercício 4 (app completa), considera criar a tua própria app com MIT App Inventor — gratuito e em português.

Exercício 1 — Receber e interpretar comandos

Receber caracteres enviados pelo telemóvel e imprimir no Serial Monitor. Define a tabela de comandos que irás usar em todos os exercícios seguintes.

TABELA DE COMANDOS BLE:

Comando
Descrição
Resposta do Arduino
'1'
Liga LED branco (sala)
LED_BRANCO ON
'0'
Desliga LED branco
LED_BRANCO OFF
'2'
Liga LED amarelo (quarto)
LED_AMARELO ON
'3'
Desliga LED amarelo
LED_AMARELO OFF
'A'
Abre porta (servo 90°)
PORTA ABERTA
'F'
Fecha porta (servo 0°)
PORTA FECHADA
'J'
Abre janela (servo2 90°)
JANELA ABERTA
'S'
Solicitar dados sensores
LUZ:xxx GAS:xxx PIR:x
'R'
Liga relé (ventoinha)
RELE ON
'r'
Desliga relé
RELE OFF
ex1_ble_receber.ino
void setup() {
  Serial.begin(9600);   // HM-10 usa 9600 baud por defeito
  Serial.println("BLE pronto. A aguardar comandos...");
}

void loop() {
  if (Serial.available() > 0) {
    char cmd = (char) Serial.read();

    // Imprime o que recebeu
    Serial.print("Recebido: ");
    Serial.println(cmd);

    // Interpreta o comando
    switch (cmd) {
      case '1': Serial.println("CMD: Liga sala");   break;
      case '0': Serial.println("CMD: Apaga sala");  break;
      case 'A': Serial.println("CMD: Abre porta"); break;
      case 'S': Serial.println("CMD: Ler sensores");break;
      default:  Serial.println("CMD desconhecido");
    }
  }
}

Exercício 2 — Controlar LEDs e servo via Bluetooth

Controla a iluminação e a porta da casa a partir do telemóvel. Envia '1' para ligar a sala, '0' para apagar, 'A' para abrir a porta, 'F' para fechar.

ex2_ble_controlo.ino
#include <Servo.h>

#define LED_BRANCO  5
#define LED_AMARELO 6
#define SERVO_PORTA 10

Servo portaServo;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BRANCO,  OUTPUT);
  pinMode(LED_AMARELO, OUTPUT);
  portaServo.attach(SERVO_PORTA);
  portaServo.write(0);   // Porta fechada
  Serial.println("BLE Domotica ON");
}

void loop() {
  if (Serial.available()) {
    char cmd = (char) Serial.read();

    switch (cmd) {
      case '1':
        digitalWrite(LED_BRANCO, HIGH);
        Serial.println("LED_BRANCO ON");
        break;
      case '0':
        digitalWrite(LED_BRANCO, LOW);
        Serial.println("LED_BRANCO OFF");
        break;
      case '2':
        digitalWrite(LED_AMARELO, HIGH);
        Serial.println("LED_AMARELO ON");
        break;
      case '3':
        digitalWrite(LED_AMARELO, LOW);
        Serial.println("LED_AMARELO OFF");
        break;
      case 'A':
        portaServo.write(90);
        Serial.println("PORTA ABERTA");
        break;
      case 'F':
        portaServo.write(0);
        Serial.println("PORTA FECHADA");
        break;
    }
  }
}

Exercício 3 — Enviar dados dos sensores para o telemóvel

Ao receber o comando 'S' do telemóvel, o Arduino envia uma string com todos os valores dos sensores. O telemóvel recebe e mostra no terminal BLE.

ex3_ble_sensores.ino
#define LDR     A0
#define MQ2_ANA A1
#define PIR      2

void setup() {
  Serial.begin(9600);
  pinMode(PIR, INPUT);
}

void enviarSensores() {
  int luz = analogRead(LDR);
  int gas = analogRead(MQ2_ANA);
  int mov = digitalRead(PIR);

  // Formato compacto para o telemóvel
  Serial.print("LUZ:");   Serial.print(luz);
  Serial.print(" GAS:");  Serial.print(gas);
  Serial.print(" PIR:");  Serial.print(mov == HIGH ? "1" : "0");
  Serial.println();   // \n para delimitar a mensagem
}

void loop() {
  if (Serial.available()) {
    char cmd = (char) Serial.read();

    if (cmd == 'S') {
      enviarSensores();    // Resposta ao pedido
    }
  }

  // Envia automaticamente a cada 5 segundos
  static unsigned long ultimo = 0;
  if (millis() - ultimo > 5000) {
    enviarSensores();
    ultimo = millis();
  }
}

Exercício 4 — App completa de controlo da casa

Integração completa: o Arduino responde a todos os comandos da tabela definida no Ex. 1 e envia dados dos sensores automaticamente a cada 3 segundos. Ideal para usar com uma app personalizada feita no MIT App Inventor.

ex4_ble_casa_completa.ino
#include <Servo.h>

#define LED_BRANCO  5
#define LED_AMARELO 6
#define SERVO_PORTA 10
#define SERVO_JAN   12
#define RELE        13
#define LDR         A0
#define MQ2_ANA     A1
#define PIR          2

Servo portaServo;
Servo janelaServo;

unsigned long ultimoEnvio = 0;
const unsigned long INTERVALO_ENVIO = 3000;

void setup() {
  Serial.begin(9600);

  pinMode(LED_BRANCO,  OUTPUT);
  pinMode(LED_AMARELO, OUTPUT);
  pinMode(RELE,        OUTPUT);
  pinMode(PIR,         INPUT);
  digitalWrite(RELE, HIGH);   // Relé OFF (lógica inversa)

  portaServo.attach(SERVO_PORTA);
  janelaServo.attach(SERVO_JAN);
  portaServo.write(0);
  janelaServo.write(0);

  Serial.println("CASA:PRONTA");
}

void enviarEstado() {
  Serial.print("LUZ:");   Serial.print(analogRead(LDR));
  Serial.print(" GAS:");  Serial.print(analogRead(MQ2_ANA));
  Serial.print(" PIR:");  Serial.print(digitalRead(PIR));
  Serial.println();
}

void processarComando(char cmd) {
  switch (cmd) {
    // ── LEDs ──
    case '1': digitalWrite(LED_BRANCO, HIGH);  Serial.println("LED_BRANCO ON");   break;
    case '0': digitalWrite(LED_BRANCO, LOW);   Serial.println("LED_BRANCO OFF");  break;
    case '2': digitalWrite(LED_AMARELO, HIGH); Serial.println("LED_AMARELO ON");  break;
    case '3': digitalWrite(LED_AMARELO, LOW);  Serial.println("LED_AMARELO OFF"); break;

    // ── Porta ──
    case 'A': portaServo.write(90); Serial.println("PORTA ABERTA");  break;
    case 'F': portaServo.write(0);  Serial.println("PORTA FECHADA"); break;

    // ── Janela ──
    case 'J': janelaServo.write(90); Serial.println("JANELA ABERTA");  break;
    case 'j': janelaServo.write(0);  Serial.println("JANELA FECHADA"); break;

    // ── Relé (ventoinha) ──
    case 'R': digitalWrite(RELE, LOW);  Serial.println("RELE ON");  break;
    case 'r': digitalWrite(RELE, HIGH); Serial.println("RELE OFF"); break;

    // ── Solicitar sensores ──
    case 'S': enviarEstado(); break;
  }
}

void loop() {
  // Processar comandos recebidos
  while (Serial.available()) {
    char cmd = (char) Serial.read();
    processarComando(cmd);
  }

  // Enviar estado automático a cada 3s
  if (millis() - ultimoEnvio > INTERVALO_ENVIO) {
    enviarEstado();
    ultimoEnvio = millis();
  }
}
💡
MIT App Inventor: Para criar a tua app Android personalizada, vai a appinventor.mit.edu. Usa o componente BluetoothLE (extensão BLEAI ou BluetoothLE nativo). Cria botões para cada comando da tabela e um campo de texto para mostrar os dados dos sensores recebidos.

🏆 Desafios