Projeto 02 — LEDs RGB pelo celular via Bluetooth

Robótica com C — Bloco 3: Projetos Práticos

O que vamos construir

Um painel de iluminação RGB controlado pelo celular via Bluetooth. Você digita um comando no app e as cores dos LEDs mudam instantaneamente — sem fio, sem botão físico, sem cabo USB. Este projeto introduce o módulo Bluetooth HC-05, que a partir daqui será o canal de comunicação de todos os projetos do Bloco 3 que envolvem o celular.

🔴
cmd "R"
LED vermelho
🟢
cmd "G"
LED verde
🔵
cmd "B"
LED azul
🟡
cmd "W"
Todos ligados
⚫
cmd "X"
Todos apagados

Por que começar com LEDs RGB? LEDs são inofensivos, dão feedback visual imediato e permitem verificar se o Bluetooth está funcionando sem precisar de relay ou motor. É o "Hello, World!" do controle remoto por celular — e o protocolo de comandos aprendido aqui é idêntico ao dos próximos projetos.

📶 Componente novo: módulo Bluetooth HC-05

O HC-05 é um módulo de comunicação serial sem fio que opera na faixa de 2,4 GHz. Para o Arduino, ele é completamente transparente: recebe bytes do celular via rádio Bluetooth e os entrega ao Arduino pela UART, exatamente como se fossem bytes do cabo USB.

Pinos de comunicação
  • VCC → 5V
  • GND → GND
  • TX → RX do Arduino (pino 10)
  • RX → TX do Arduino (pino 11) via divisor!
Características
  • Bluetooth 2.0 — alcance ~10m
  • Taxa padrão: 9600 bps
  • Nome padrão: HC-05
  • Senha padrão: 1234 ou 0000

⚠️ Divisor de tensão obrigatório no RX do HC-05: o Arduino envia 5V no pino TX, mas o HC-05 suporta no máximo 3,3V no pino RX. Conectar diretamente pode danificar o módulo ao longo do tempo. O divisor é simples:

Arduino TX (pino 11) ──── R1 (1kΩ) ──┬──── HC-05 RX
                                      │
                                     R2 (2kΩ)
                                      │
                                     GND

Tensão no HC-05 RX = 5V × R2/(R1+R2) = 5V × 2/3 ≈ 3,3V ✓
Aspecto HC-05 HC-06
Modos Mestre e escravo — pode iniciar conexão Apenas escravo — aguarda conexão
Configuração AT Sim — nome, senha, baud rate configuráveis Limitada
Preço (BR) R$ 20–35 R$ 12–20 (mais barato)
Para este projeto ✅ Funciona perfeitamente ✅ Também funciona

HC-05 ou HC-06? Para todos os projetos deste curso, onde o celular inicia a conexão com o Arduino, tanto o HC-05 quanto o HC-06 funcionam. O HC-06 é mais barato e mais simples de usar. O HC-05 é mais versátil. Use o que você tiver disponível — o código é idêntico.

📱 App no celular: Serial Bluetooth Terminal

Para enviar comandos do celular ao Arduino, use o app Serial Bluetooth Terminal (Android), disponível gratuitamente na Play Store. Ele permite:

Configuração dos botões de macro (recomendado):

BotãoMacro (texto enviado)Cor/Função
M1R🔴 Vermelho
M2G🟢 Verde
M3B🔵 Azul
M4W⚪ Branco (todos)
M5X⚫ Apagar tudo
M6?📋 Ver comandos

Para usuários iOS: o HC-05/HC-06 usa Bluetooth Classic (não BLE), que não é suportado nativamente pelo iOS desde o iPhone 4. Use um módulo HM-10 (Bluetooth LE) com o app LightBlue ou BLE Terminal HM-10 para iOS. O código do Arduino é praticamente o mesmo — só muda o nome do objeto Serial.

Circuito completo

Componente Conexão Observação
HC-05 VCC → 5V O módulo aceita 5V na alimentação
HC-05 GND → GND —
HC-05 TX → pino 10 (RX software) Conexão direta — HC-05 envia 3,3V, Arduino aceita
HC-05 RX → divisor R1/R2 → pino 11 (TX software) Divisor obrigatório: R1=1kΩ, R2=2kΩ
LED vermelho + 220Ω pino 9 → R → LED → GND Pino PWM para controle de brilho futuro
LED verde + 220Ω pino 6 → R → LED → GND Pino PWM
LED azul + 220Ω pino 5 → R → LED → GND Pino PWM

Por que pinos PWM para LEDs? Esta aula usa digitalWrite() (liga/desliga). Na extensão da Seção 6, você vai usar analogWrite() para controlar o brilho de cada canal com valores 0–255. Reservar pinos PWM agora evita remontagem depois.

🖥️ Simulando no Wokwi — o que funciona e o que não funciona

O Wokwi não tem o HC-05 como componente nativo. Não é possível simular o rádio Bluetooth nem parear o celular com o simulador. Porém, como a Aula 46 demonstrou, a lógica de processarComando() é completamente independente do canal — o que permite uma estratégia de simulação muito prática.

Estratégia: Serial Monitor como substituto do celular. No Wokwi, você digita os comandos (R, G, B, W, X) diretamente no Monitor Serial — exatamente como faria pelo app no celular. A lógica de processamento é 100% idêntica. Só o rádio não é simulado, e rádio não tem como testar em software de qualquer forma.

Para simular no Wokwi, use esta versão adaptada do código — troca SoftwareSerial bluetooth por Serial:

// ── Versão WOKWI (simulação) ───────────────────────
// Remove SoftwareSerial — usa Serial direto
// Envie comandos pelo Monitor Serial: R G B W X ?
// Comportamento idêntico ao projeto com HC-05 real

const int PINO_R = 9;
const int PINO_G = 6;
const int PINO_B = 5;

bool estadoR = false, estadoG = false, estadoB = false;

void atualizarLEDs() {
    digitalWrite(PINO_R, estadoR ? HIGH : LOW);
    digitalWrite(PINO_G, estadoG ? HIGH : LOW);
    digitalWrite(PINO_B, estadoB ? HIGH : LOW);
}

void enviarStatus() {
    Serial.print("RGB: ");
    Serial.print(estadoR ? "R" : "-");
    Serial.print(estadoG ? "G" : "-");
    Serial.println(estadoB ? "B" : "-");
}

void processarComando(char cmd) {
    switch (cmd) {
        case 'R': estadoR = true;  break;
        case 'r': estadoR = false; break;
        case 'G': estadoG = true;  break;
        case 'g': estadoG = false; break;
        case 'B': estadoB = true;  break;
        case 'b': estadoB = false; break;
        case 'W': estadoR = estadoG = estadoB = true;  break;
        case 'X': estadoR = estadoG = estadoB = false; break;
        case '?': Serial.println("Cmds: R/r G/g B/b W X"); return;
        case '\n': case '\r': return;
        default: Serial.print("Desconhecido: "); Serial.println(cmd); return;
    }
    atualizarLEDs();
    enviarStatus();
}

void setup() {
    pinMode(PINO_R, OUTPUT);
    pinMode(PINO_G, OUTPUT);
    pinMode(PINO_B, OUTPUT);
    atualizarLEDs();
    Serial.begin(9600);
    Serial.println("=== RGB Wokwi — envie: R G B W X ?");
}

void loop() {
    if (Serial.available() > 0) {
        processarComando(Serial.read());
    }
}
Aspecto Versão Wokwi (simulação) Versão física (HC-05)
Canal de comunicação Monitor Serial (teclado) Bluetooth HC-05 (celular)
Objeto usado Serial bluetooth (SoftwareSerial)
Função processarComando() Idêntica — nenhuma mudança Idêntica — nenhuma mudança
Comportamento dos LEDs Idêntico Idêntico
O que NÃO é simulado O rádio Bluetooth e o pareamento —

Fluxo de trabalho recomendado para todos os projetos Bluetooth do Bloco 3:

  1. Simule no Wokwi com a versão Serial — valide toda a lógica de comandos, estados e LEDs/relay/servo
  2. Monte no hardware físico com o HC-05 e troque Serial por bluetooth — o código já está validado, só o canal muda
  3. Conecte o celular e teste o pareamento e os comandos via app

Essa separação economiza muito tempo: problemas de lógica são encontrados e resolvidos no simulador, sem precisar desmontar o circuito físico. Problemas de hardware (divisor de tensão, baud rate, pareamento) são isolados para a etapa 2.

Código completo (versão com HC-05 físico)

/*
 * =====================================================
 * Projeto 02 — LEDs RGB via Bluetooth HC-05
 * =====================================================
 * Comandos (maiúsculo = liga, minúsculo = desliga):
 *   R/r = vermelho | G/g = verde | B/b = azul
 *   W   = todos ligados (branco)
 *   X   = todos apagados
 *   ?   = lista de comandos
 * =====================================================
 */

#include <SoftwareSerial.h>

// ── Bluetooth ──────────────────────────────────────
// SoftwareSerial(RX, TX) — pinos do ARDUINO
// HC-05 TX → pino 10 | HC-05 RX → pino 11 (via divisor)
SoftwareSerial bluetooth(10, 11);

// ── Pinos dos LEDs (todos PWM) ─────────────────────
const int PINO_R = 9;
const int PINO_G = 6;
const int PINO_B = 5;

// ── Estado atual de cada canal ─────────────────────
bool estadoR = false;
bool estadoG = false;
bool estadoB = false;


// ════════════════════════════════════════════════════
// Aplica o estado atual nos pinos físicos
// ════════════════════════════════════════════════════
void atualizarLEDs() {
    digitalWrite(PINO_R, estadoR ? HIGH : LOW);
    digitalWrite(PINO_G, estadoG ? HIGH : LOW);
    digitalWrite(PINO_B, estadoB ? HIGH : LOW);
}

// ════════════════════════════════════════════════════
// Envia o estado atual de volta ao celular
// ════════════════════════════════════════════════════
void enviarStatus() {
    bluetooth.print("RGB: ");
    bluetooth.print(estadoR ? "R" : "-");
    bluetooth.print(estadoG ? "G" : "-");
    bluetooth.println(estadoB ? "B" : "-");
}

// ════════════════════════════════════════════════════
// Processa um comando recebido pelo Bluetooth
// ════════════════════════════════════════════════════
void processarComando(char cmd) {
    switch (cmd) {
        case 'R': estadoR = true;  break;
        case 'r': estadoR = false; break;
        case 'G': estadoG = true;  break;
        case 'g': estadoG = false; break;
        case 'B': estadoB = true;  break;
        case 'b': estadoB = false; break;

        case 'W':  // branco — todos ligados
            estadoR = estadoG = estadoB = true;
            break;

        case 'X':  // apagar tudo
            estadoR = estadoG = estadoB = false;
            break;

        case '?':
            bluetooth.println("Cmds: R/r G/g B/b W=branco X=apagar");
            return;   // não atualiza LEDs nem envia status

        case '\n': case '\r': return;

        default:
            bluetooth.print("Desconhecido: ");
            bluetooth.println(cmd);
            return;
    }

    atualizarLEDs();
    enviarStatus();

    // Espelha no Serial USB para debug
    Serial.print("[BT cmd='"); Serial.print(cmd);
    Serial.print("'] RGB: ");
    Serial.print(estadoR ? "R" : "-");
    Serial.print(estadoG ? "G" : "-");
    Serial.println(estadoB ? "B" : "-");
}


// ════════════════════════════════════════════════════
// SETUP e LOOP
// ════════════════════════════════════════════════════

void setup() {
    pinMode(PINO_R, OUTPUT);
    pinMode(PINO_G, OUTPUT);
    pinMode(PINO_B, OUTPUT);
    atualizarLEDs();  // garante que todos começam apagados

    Serial.begin(9600);
    bluetooth.begin(9600);

    Serial.println("=== RGB Bluetooth ===");
    Serial.println("Aguardando conexao do celular...");

    // Sinaliza que está pronto: pisca todos uma vez
    estadoR = estadoG = estadoB = true;  atualizarLEDs(); delay(300);
    estadoR = estadoG = estadoB = false; atualizarLEDs();
}

void loop() {
    if (bluetooth.available() > 0) {
        char cmd = bluetooth.read();
        processarComando(cmd);
    }

    // Espelha tráfego do Serial USB para o Bluetooth (debug)
    if (Serial.available() > 0) {
        bluetooth.write(Serial.read());
    }
}

=== RGB Bluetooth ===

Aguardando conexao do celular...

[celular envia "R"] [BT cmd='R'] RGB: R--

[celular envia "G"] [BT cmd='G'] RGB: RG-

[celular envia "b"] [BT cmd='b'] RGB: RG-

[celular envia "W"] [BT cmd='W'] RGB: RGB

[celular envia "X"] [BT cmd='X'] RGB: ---

Espelhar Serial ↔ Bluetooth no loop(): as duas linhas if (bluetooth.available()) e if (Serial.available()) criam uma "ponte" bidirecional. Enquanto testa, você pode enviar comandos tanto pelo celular quanto pelo Monitor Serial do computador. Remova essa ponte quando o projeto for para produção.

Extensão: controle de brilho por canal (0–255)

Agora que os pinos são PWM, expanda o protocolo para aceitar valores de brilho. Formato: prefixo + valor (padrão da Aula 46), ex: "R128" → vermelho em 50% de brilho:

// Substitui os bool por int (0–255) e usa analogWrite

int brilhoR = 0, brilhoG = 0, brilhoB = 0;

void atualizarLEDs() {
    analogWrite(PINO_R, brilhoR);
    analogWrite(PINO_G, brilhoG);
    analogWrite(PINO_B, brilhoB);
}

// No processarComando(), substitua o switch por:
void processarMensagem(String msg) {
    if (msg.length() < 1) return;

    char canal = msg[0];
    int  valor = constrain(msg.substring(1).toInt(), 0, 255);

    switch (canal) {
        case 'R': brilhoR = valor; break;
        case 'G': brilhoG = valor; break;
        case 'B': brilhoB = valor; break;
        case 'W': brilhoR = brilhoG = brilhoB = valor ? valor : 255; break;
        case 'X': brilhoR = brilhoG = brilhoB = 0; break;
        default: bluetooth.println("Formato: R0-255 G0-255 B0-255 W X"); return;
    }

    atualizarLEDs();

    bluetooth.print("RGB: ");
    bluetooth.print(brilhoR); bluetooth.print(" ");
    bluetooth.print(brilhoG); bluetooth.print(" ");
    bluetooth.println(brilhoB);
}

// No loop(), substitua bluetooth.read() por readStringUntil:
void loop() {
    if (bluetooth.available()) {
        String msg = bluetooth.readStringUntil('\n');
        msg.trim();
        if (msg.length() > 0) processarMensagem(msg);
    }
}

[celular envia "R255"] RGB: 255 0 0

[celular envia "G128"] RGB: 255 128 0

[celular envia "B64"] RGB: 255 128 64

[celular envia "W"] RGB: 255 255 255

[celular envia "X"] RGB: 0 0 0

Pareamento e solução de problemas

Como parear o HC-05 com o celular

  1. Ligue o Arduino com o sketch carregado — o LED do HC-05 deve piscar rapidamente (modo de espera)
  2. No celular: Configurações → Bluetooth → Procurar dispositivos
  3. Selecione HC-05 (ou HC-06)
  4. Digite a senha: 1234 (ou 0000)
  5. Abra o app Serial Bluetooth Terminal → toque no ícone de conexão → selecione HC-05
  6. O LED do módulo muda para piscar lentamente (2x por segundo) quando conectado
  7. Envie "?" — o Arduino deve responder com a lista de comandos

Problemas comuns e soluções

Problema Causa provável Solução
HC-05 não aparece no Bluetooth do celular Módulo não está em modo de descoberta ou não está ligado Verifique VCC e GND — o LED deve estar piscando rápido
Pareia mas não recebe dados TX/RX invertidos ou divisor de tensão incorreto Confira: HC-05 TX → Arduino pino 10 (RX); HC-05 RX → divisor → Arduino pino 11 (TX)
Dados corrompidos / caracteres errados Baud rate diferente entre HC-05 e bluetooth.begin() O baud padrão do HC-05 é 9600. Tente também 38400 se 9600 não funcionar
Arduino reinicia ao conectar o Bluetooth SoftwareSerial interferindo com Serial durante o boot Desconecte TX/RX do HC-05 ao carregar o sketch, reconecte após
LED do HC-05 não para de piscar rápido Nenhum celular conectado Normal — vai parar ao conectar pelo app

C vs Arduino — Serial vs Bluetooth

Conceito Aula 46 (Serial USB) Este projeto (Bluetooth)
Objeto de comunicação Serial bluetooth (SoftwareSerial)
Verificar dados disponíveis Serial.available() bluetooth.available()
Ler um byte Serial.read() bluetooth.read()
Enviar texto Serial.print() bluetooth.print()
Lógica de processamento processarComando(cmd) processarComando(cmd) — idêntica
Inicialização Serial.begin(9600) bluetooth.begin(9600)
Limitação de hardware Comprimento do cabo USB ~10 metros de alcance

Confirmação do que a Aula 46 prometeu: a lógica de processarComando() é copiada literalmente da Aula 46. A única mudança é o nome do objeto — Serial vira bluetooth. O padrão available() → read() → switch(cmd) é 100% reutilizável.

Quiz — Projeto 02

Teste sua compreensão do módulo Bluetooth e do projeto RGB:

1. Por que é necessário um divisor de tensão entre o pino TX do Arduino e o pino RX do HC-05?

2. Na declaração SoftwareSerial bluetooth(10, 11), o que representam os números 10 e 11?

3. Por que atualizarLEDs() é uma função separada que modifica os pinos, em vez de digitalWrite() diretamente no switch?

4. O LED do HC-05 está piscando rapidamente. O que isso indica?

5. Por que os três LEDs foram conectados a pinos PWM (5, 6, 9) mesmo que o código inicial use apenas digitalWrite()?

6. Na extensão de controle de brilho, o que faz constrain(msg.substring(1).toInt(), 0, 255)?

7. O código tem duas linhas no loop() que espelham Serial ↔ Bluetooth. Qual é o propósito desse espelhamento durante o desenvolvimento?

8. Um colega conectou diretamente o HC-05 TX ao Arduino RX e HC-05 RX ao Arduino TX, sem divisor de tensão. O projeto funciona aparentemente bem. Qual é o risco?