Robótica com C — Bloco 1
O HC-SR04 mede distância por ultrassom: emite um pulso de 40 kHz pelo pino TRIG e mede o tempo até o eco chegar ao pino ECHO. Como o som viaja a ~343 m/s (0,0343 cm/µs), o tempo de ida e volta dividido por 2 fornece a distância. É o sensor de desvio de obstáculos mais usado em robótica por custar menos de R$10 e ser preciso entre 2 cm e 4 metros.
| Pino | Função | Configurar como |
|---|---|---|
| VCC | Alimentação 5V | — |
| GND | Terra | — |
| TRIG | Dispara o pulso ultrassônico (entrada do sensor) | OUTPUT |
| ECHO | Fica HIGH enquanto aguarda o eco (saída do sensor) | INPUT |
// HC-SR04: TRIG → pino 9, ECHO → pino 10 const int PINO_TRIG = 9; const int PINO_ECHO = 10; void setup() { pinMode(PINO_TRIG, OUTPUT); pinMode(PINO_ECHO, INPUT); Serial.begin(9600); } // Função encapsulada — retorna distância em cm long medirDistanciaCm() { // Garante TRIG em LOW antes de disparar digitalWrite(PINO_TRIG, LOW); delayMicroseconds(2); // Pulso de 10µs — dispara o ultrassom digitalWrite(PINO_TRIG, HIGH); delayMicroseconds(10); digitalWrite(PINO_TRIG, LOW); // pulseIn() mede quanto tempo ECHO fica HIGH (µs) long duracao = pulseIn(PINO_ECHO, HIGH); // Distância = tempo × 0,0343 cm/µs ÷ 2 (ida e volta) return (duracao * 0.0343) / 2; } void loop() { long dist = medirDistanciaCm(); Serial.print("Distancia: "); Serial.print(dist); Serial.println(" cm"); if (dist < 20) Serial.println(" >> Obstaculo proximo!"); delay(500); }
Distancia: 85 cm
Distancia: 34 cm
Distancia: 12 cm
>> Obstaculo proximo!
Por que encapsular em função? A função medirDistanciaCm() aplica diretamente o que você aprendeu nas aulas de funções em C: lógica reutilizável com retorno claro. No robô, você vai chamar essa função periodicamente sem repetir as 7 linhas de protocolo. Nas aulas 51–52, ela será chamada dentro de uma struct para dois sensores simultâneos.
Quando o robô tiver sensores na frente e na lateral, a struct encapsula os pinos e reutiliza a mesma função de medição:
// Dois HC-SR04 com struct — padrão que será usado no robô
typedef struct {
int pinTrig;
int pinEcho;
const char* nome;
} Ultrassonico;
void inicializarUS(Ultrassonico* s) {
pinMode(s->pinTrig, OUTPUT);
pinMode(s->pinEcho, INPUT);
}
long medirCm(Ultrassonico* s) {
digitalWrite(s->pinTrig, LOW); delayMicroseconds(2);
digitalWrite(s->pinTrig, HIGH); delayMicroseconds(10);
digitalWrite(s->pinTrig, LOW);
return (pulseIn(s->pinEcho, HIGH) * 0.0343) / 2;
}
Ultrassonico frente = {9, 10, "FRENTE"};
Ultrassonico lateral = {6, 7, "LATERAL"};
void setup() {
inicializarUS(&frente);
inicializarUS(&lateral);
Serial.begin(9600);
}
void loop() {
Serial.print(frente.nome); Serial.print(": "); Serial.print(medirCm(&frente));
Serial.print(" cm | ");
Serial.print(lateral.nome); Serial.print(": "); Serial.print(medirCm(&lateral));
Serial.println(" cm");
delay(300);
}
Reconheceu o padrão? Ultrassonico*, s->pinTrig, inicializarUS(&frente) — é exatamente a mesma lógica das funções de lista encadeada das aulas 37–38, agora aplicada ao hardware.
LiquidCrystal.hO display LCD 16×2 (16 colunas, 2 linhas) exibe texto sem precisar de Serial ou computador conectado — fundamental para o robô mostrar status, distância e modo de operação de forma autônoma.
Pode ser controlado de duas formas: modo paralelo (6 fios de dados + controle) ou I2C (apenas 2 fios via adaptador). Aqui cobrimos o modo paralelo — o mais fácil de entender internamente:
// Display LCD 16×2 em modo paralelo // Pinos: RS=12, EN=11, D4=5, D5=4, D6=3, D7=2 // Alimentação: VSS→GND, VDD→5V, V0→potenciômetro (contraste), A→5V, K→GND #include <LiquidCrystal.h> const int rs=12, en=11, d4=5, d5=4, d6=3, d7=2; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); // objeto da classe void setup() { lcd.begin(16, 2); // inicializa: 16 colunas, 2 linhas lcd.print("Ola, Arduino!"); // linha 0, coluna 0 lcd.setCursor(0, 1); // move para linha 1 lcd.print("Curso AFF :)"); } void loop() { }
Para dados dinâmicos, atualize dentro do loop() — mas evite lcd.clear() pois causa pisca. A técnica correta é escrever por cima com espaços:
// LCD dinâmico: temperatura em tempo real (LM35 no A0) #include <LiquidCrystal.h> LiquidCrystal lcd(12, 11, 5, 4, 3, 2); const int PINO_LM35 = A0; void setup() { lcd.begin(16, 2); lcd.print("Temperatura:"); // rótulo fixo — só no setup() } void loop() { float temp = analogRead(PINO_LM35) * (5.0 / 1023.0) * 100.0; lcd.setCursor(0, 1); // posiciona na linha 1 lcd.print(temp, 1); // ex: "24.3" lcd.print(" C "); // espaços cobrem dígitos anteriores delay(500); }
Métodos mais usados do LCD:
lcd.begin(cols, linhas) — inicializa o display (sempre no setup())lcd.print(valor) — escreve texto, int ou float na posição atuallcd.setCursor(coluna, linha) — move o cursor (coluna 0–15, linha 0–1)lcd.clear() — apaga tudo e volta ao (0,0) — causa pisca, use com parcimônialcd.createChar(id, bitmap) — cria ícone customizado de 5×8 pixelsVersão I2C para projetos maiores: o LCD via I2C usa apenas 2 fios (SDA=A4, SCL=A5) em vez de 6, liberando pinos digitais para motores e sensores. Requer a biblioteca LiquidCrystal_I2C.h e um módulo adaptador soldado atrás do LCD. Na Aula 46 usaremos LCD I2C — aqui você aprendeu o funcionamento interno para entender o que o adaptador esconde.
O módulo RTC (Real Time Clock) DS3231 é um relógio de alta precisão que continua funcionando mesmo quando o Arduino é desligado — ele tem uma bateria CR2032 própria. Comunica via I2C: SDA → pino A4, SCL → pino A5 no Uno.
Requer a biblioteca RTClib: Sketch → Incluir Biblioteca → Gerenciar Bibliotecas → "RTClib" → Instalar.
// Módulo RTC DS3231 // Ligação I2C: SDA → A4, SCL → A5, VCC → 3.3V ou 5V, GND → GND #include <Wire.h> #include <RTClib.h> RTC_DS3231 rtc; // objeto da classe — instância, como você aprendeu na 41a void setup() { Serial.begin(9600); if (!rtc.begin()) { Serial.println("RTC nao encontrado! Verifique a ligacao."); while (1); // trava — sem RTC o programa não faz sentido } // Se a bateria morreu, ajusta com a hora da compilação do sketch if (rtc.lostPower()) { Serial.println("RTC sem hora — ajustando..."); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } } void loop() { DateTime agora = rtc.now(); // objeto com data e hora atual // Formato DD/MM/AAAA HH:MM:SS Serial.print(agora.day(), DEC); Serial.print("/"); Serial.print(agora.month(), DEC); Serial.print("/"); Serial.print(agora.year(), DEC); Serial.print(" "); Serial.print(agora.hour(), DEC); Serial.print(":"); Serial.print(agora.minute(), DEC); Serial.print(":"); Serial.print(agora.second(), DEC); Serial.println(); delay(1000); }
28/3/2026 14:35:02
28/3/2026 14:35:03
28/3/2026 14:35:04
F("texto") e F(__DATE__): a macro F() armazena a string na memória flash (32 KB) em vez de copiar para a RAM (2 KB) durante a execução. Com apenas 2 KB de RAM no Uno, usar F() em mensagens longas ou constantes de texto é uma boa prática. __DATE__ e __TIME__ são macros do compilador que inserem a data e hora da compilação diretamente no binário.
O padrão final das aulas de robótica é exatamente este: um sensor lê o mundo, o LCD exibe o resultado, o código decide o que fazer. Aqui está uma miniatura desse padrão:
/* * HC-SR04 + LCD 16×2 * Exibe distância em tempo real no display * Se dist < 20cm: linha 2 mostra "OBSTACULO!" */ #include <LiquidCrystal.h> LiquidCrystal lcd(12, 11, 5, 4, 3, 2); const int PINO_TRIG = 9; const int PINO_ECHO = 10; long medirDistanciaCm() { digitalWrite(PINO_TRIG, LOW); delayMicroseconds(2); digitalWrite(PINO_TRIG, HIGH); delayMicroseconds(10); digitalWrite(PINO_TRIG, LOW); return (pulseIn(PINO_ECHO, HIGH) * 0.0343) / 2; } void setup() { pinMode(PINO_TRIG, OUTPUT); pinMode(PINO_ECHO, INPUT); lcd.begin(16, 2); lcd.print("Distancia:"); } void loop() { long dist = medirDistanciaCm(); lcd.setCursor(0, 1); lcd.print(dist); lcd.print(" cm "); // espaços cobrem dígitos antigos lcd.setCursor(9, 1); if (dist < 20) lcd.print("OBST!"); else lcd.print(" "); delay(300); }
Esse é o núcleo do robô da Aula 52: medirDistanciaCm() retorna a distância, o LCD exibe, e um if decide a ação. Nas próximas aulas você vai acrescentar motores, mais sensores e uma máquina de estados — mas a estrutura central permanece essa.
Teste o que você aprendeu sobre HC-SR04, LCD e RTC: