Partilhar: WhatsApp
aulify · Sebenta
UC · Unidade de Competência · UC02842

Sebenta · Arduino e artefactos tangíveis (UC02842)

Electrónica programada para makers
25h · 2.25 pontos crédito Curso: T. Desenv. Software, T. Sist. Comp. Redes ↗ Referencial oficial SNQ
Índice

Introdução

Arduino é a plataforma que democratizou a electrónica programada. Lançada em 2005 em Ivrea (Itália) por um grupo de designers e engenheiros, partia de um princípio simples: dar a artistas e estudantes uma forma acessível de combinar código e hardware. Vinte anos depois, é o standard educativo, de prototipagem e de DIY em todo o mundo.

Esta sebenta cobre Arduino na perspectiva de artefactos tangíveis — projectos que vivem no mundo físico: instalações interactivas, automações domésticas, robôs, estações sensoriais. Vais aprender a controlar LEDs, ler sensores, mover motores, fazer comunicar dispositivos, e juntar tudo em projectos completos.

Não precisas de background em electrónica. Cada conceito é apresentado com analogia, código mínimo e exemplos.

1. Arduino — plataforma e ecossistema

O que é

"Arduino" é três coisas ao mesmo tempo:

Open source — qualquer pessoa pode fabricar clones (e há muitos).

Boards principais

Board Microcontrolador Pinos Memória Preço
Uno R3 ATmega328P 14 dig + 6 ana 32KB Flash €25
Uno R4 WiFi RA4M1 idem 256KB €30
Nano ATmega328P idem 32KB €15
Mega 2560 ATmega2560 54 dig + 16 ana 256KB €40
Leonardo ATmega32U4 20 dig + 12 ana 32KB €25
ESP32 ESP32-WROOM 30+ 4MB + WiFi €10
Pico RP2040 26 2MB €5

Para esta UC: Uno R3 ou compatible. Mais robusto para iniciantes (alimentação 5V, mais tolerante a erros).

Onde se usa

Limites

Não é para: - Aplicações industriais críticas (usa PLCs). - Processamento de imagem ou ML pesado (usa Raspberry Pi / Jetson). - Produção em massa de produtos (usa microcontrolador directo, sem placa Arduino).

Mas como plataforma de aprendizagem e prototipagem — imbatível.

2. Setup

Hardware necessário

Kit básico Arduino (€30-50): - Arduino Uno. - Cabo USB-B. - Breadboard. - Jumper wires (M-M, M-F). - LEDs vários (5mm vermelho, verde, azul). - Resistências (220Ω, 1kΩ, 10kΩ). - Botões de pressão. - Potenciómetros. - Sensor (LDR, TMP36, HC-SR04). - Servo motor SG90.

Software

Arduino IDE 2.x (gratuita): arduino.cc/en/software.

Após instalar: 1. Liga Uno via USB. 2. Tools → Board → Arduino Uno. 3. Tools → Port → escolher (/dev/ttyACM0, /dev/cu.usbserial-..., COM3). 4. File → Examples → Basics → Blink → verificar/upload.

Se LED da board (TX/RX, L) pisca brevemente no upload, está tudo bem.

Alternativa: PlatformIO em VSCode

Para projectos maiores: - Auto-completion melhor. - Library management. - Git-friendly (vs sketches single file).

# VSCode → install extension "PlatformIO IDE"
# Cria projecto → escolher board → editar src/main.cpp

Online IDE

Wokwi (wokwi.com): simulador Arduino online — útil sem hardware.

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

LED_BUILTIN é o pino 13 (Uno tem LED ligado a esse pino).

Click Upload (seta). Após uns segundos, LED pisca a 1Hz.

3. Estrutura de um sketch Arduino

// Variáveis globais e constantes
const int LED_PIN = 13;
int counter = 0;

void setup() {
  // Corre UMA VEZ no arranque (reset ou power-on)
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);   // comunicação USB
  Serial.println("Iniciado!");
}

void loop() {
  // Corre INFINITAMENTE em loop após setup()
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);

  counter++;
  Serial.print("Loops: ");
  Serial.println(counter);
}

A linguagem é C++ com algumas conveniências: - setup() e loop() obrigatórios. - Tipos: int, byte, boolean, float, String, etc. - Funções built-in: pinMode(), digitalRead/Write(), analogRead/Write(), delay(), millis().

Sketch em múltiplos ficheiros

Para projectos maiores, abre Sketch → Add File ou cria tabs. Cada tab é um ficheiro .ino, .h ou .cpp na pasta do sketch.

4. Pinos digitais — output e input

Output: piscar LED

Hardware:

Pino 8 ────[Resistor 220Ω]────[ânodo LED ▶ cátodo]──── GND

Importante: sempre resistência em série com LED. Sem ela, LED queima (puxa corrente excessiva).

LED tem polaridade: - Ânodo (+, perna longa). - Cátodo (-, perna curta, lado com flat na lente).

Código:

const int LED = 8;

void setup() {
  pinMode(LED, OUTPUT);
}

void loop() {
  digitalWrite(LED, HIGH);  // 5V
  delay(500);
  digitalWrite(LED, LOW);   // 0V
  delay(500);
}

Input: botão

Hardware (com resistência pull-up externa):

5V ──[10kΩ]──┬── Pino 2
             
            [Botão]
             
            GND

Quando botão solto: pino lê HIGH (5V via pull-up). Quando premido: pino lê LOW (curto-circuito com GND).

Código com pull-up externa:

const int BUTTON = 2;
const int LED = 8;

void setup() {
  pinMode(BUTTON, INPUT);
  pinMode(LED, OUTPUT);
}

void loop() {
  int s = digitalRead(BUTTON);
  digitalWrite(LED, s == LOW ? HIGH : LOW);
}

Pull-up interna (mais fácil)

Arduino tem resistências pull-up internas — usá-las e poupar a externa:

void setup() {
  pinMode(BUTTON, INPUT_PULLUP);  // ← liga pull-up interna
  pinMode(LED, OUTPUT);
}

Botão liga directo entre pino e GND. Sem necessidade da resistência 10kΩ.

Debounce — botões "tremem"

Quando carregas num botão mecânico, os contactos ressaltam alguns ms — produzindo várias transições falsas. Para detectar "click" correctamente:

const int BUTTON = 2;
int lastState = HIGH;
unsigned long lastChange = 0;
const unsigned long DEBOUNCE = 50;  // ms

void loop() {
  int s = digitalRead(BUTTON);

  if (s != lastState && millis() - lastChange > DEBOUNCE) {
    lastChange = millis();
    lastState = s;

    if (s == LOW) {
      Serial.println("CLICK");
    }
  }
}

Library Bounce2 automatiza isto.

5. Pinos analógicos — sensores

Analog input (A0-A5)

Pinos com prefixo A lêem tensão entre 0V e 5V com resolução de 10 bits → valor 0-1023.

const int POT = A0;

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

void loop() {
  int raw = analogRead(POT);
  float volts = raw * (5.0 / 1023.0);

  Serial.print("Raw: ");
  Serial.print(raw);
  Serial.print(" | ");
  Serial.print(volts, 2);
  Serial.println(" V");

  delay(200);
}

Sensor TMP36 (temperatura)

Cabeça plana virada para ti: - Pino esquerdo → 5V. - Pino do meio → A0. - Pino direito → GND.

void loop() {
  int raw = analogRead(A0);
  float volts = raw * (5.0 / 1023.0);
  float temp = (volts - 0.5) * 100.0;   // TMP36 datasheet

  Serial.print(temp, 1);
  Serial.println(" °C");
  delay(1000);
}

TMP36: 0.5V a 0°C, 10mV/°C. Por isso a fórmula.

LDR (foto-resistência)

Divisor de tensão com LDR + resistor 10kΩ:

5V ── LDR ── A0
              
            10
              
             GND

Mais luz = LDR menos resistente = leitura maior.

void loop() {
  int luz = analogRead(A0);
  if (luz < 300) Serial.println("Escuro");
  else if (luz < 700) Serial.println("Médio");
  else Serial.println("Brilhante");
  delay(300);
}

HC-SR04 (distância ultrassónica)

4 pinos: VCC (5V), Trig, Echo, GND.

const int TRIG = 9, ECHO = 10;

void setup() {
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  Serial.begin(9600);
}

float medirDistancia() {
  digitalWrite(TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);

  long duracao = pulseIn(ECHO, HIGH);
  float cm = duracao * 0.0343 / 2;   // velocidade som 343 m/s
  return cm;
}

void loop() {
  float d = medirDistancia();
  Serial.print(d, 1);
  Serial.println(" cm");
  delay(200);
}

Range típico: 2cm-400cm. Útil para sensores de presença, parking, robots.

DHT22 (temperatura + humidade)

Sensor digital mais fiável que TMP36. Requer library:

Tools → Manage Libraries → "DHT sensor library" by Adafruit.

#include <DHT.h>

#define DHT_PIN 2
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

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

void loop() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  if (isnan(h) || isnan(t)) {
    Serial.println("Erro");
    return;
  }

  Serial.print(t, 1); Serial.print("°C, ");
  Serial.print(h, 1); Serial.println("%");
  delay(2000);   // mínimo 1s entre leituras
}

6. PWM — analog output

O que é PWM

Pinos digitais não conseguem "5V parcial". Mas com Pulse Width Modulation (PWM) podes simular tensão variável ligando e desligando muito rápido com duty cycle variável.

analogWrite(pino, valor): valor 0-255 (mapeia para 0-100% duty).

Só funciona em pinos PWM: 3, 5, 6, 9, 10, 11 no Uno (marcados com ~).

LED fade

const int LED = 9;

void setup() {
  pinMode(LED, OUTPUT);
}

void loop() {
  // Acender progressivamente
  for (int v = 0; v <= 255; v++) {
    analogWrite(LED, v);
    delay(5);
  }
  // Apagar progressivamente
  for (int v = 255; v >= 0; v--) {
    analogWrite(LED, v);
    delay(5);
  }
}

Controlar LED com potenciómetro

void loop() {
  int raw = analogRead(A0);      // 0-1023
  int brilho = map(raw, 0, 1023, 0, 255);
  analogWrite(LED, brilho);
}

map() converte de um range para outro — função muito útil.

7. Motores e movimento

Servo motor (SG90 e similares)

Servos são motores DC + caixa redutora + encoder + controlador. Aceitam posição alvo (0-180°).

SG90 cabos:
  Castanho/preto → GND
  Vermelho → 5V (ou fonte externa para servos grandes)
  Laranja/amarelo → pino digital
#include <Servo.h>

Servo servo;

void setup() {
  servo.attach(9);
}

void loop() {
  servo.write(0);     delay(1000);
  servo.write(90);    delay(1000);
  servo.write(180);   delay(1000);
}

Library Servo.h já vem com o IDE.

Controlo com potenciómetro:

void loop() {
  int raw = analogRead(A0);
  int ang = map(raw, 0, 1023, 0, 180);
  servo.write(ang);
  delay(20);
}

Motor DC bidireccional (ponte H L293D)

Servo só dá posição; motor DC dá rotação contínua. Para controlar direcção precisas de ponte H (chip L293D ou módulo L298N).

L293D:
  IN1, IN2 → pinos digitais Arduino (controlo direcção)
  EN1 (PWM) → pino PWM Arduino (controlo velocidade)
  OUT1, OUT2 → motor
  VCC1 (5V), VCC2 (fonte motor), GND (comum)
const int IN1 = 7, IN2 = 8, EN = 9;

void setup() {
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(EN, OUTPUT);
}

void frente(int v) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(EN, v);  // 0-255
}

void tras(int v) {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(EN, v);
}

void parar() {
  analogWrite(EN, 0);
}

void loop() {
  frente(200); delay(2000);
  parar();     delay(500);
  tras(200);   delay(2000);
  parar();     delay(500);
}

Sempre alimentar motor com fonte externa (não USB do Arduino — puxa demasiada corrente).

Stepper motors

Para precisão absoluta (impressoras 3D, CNC). Usar Stepper.h ou AccelStepper.h.

8. Displays

LCD 16x2 (com I2C)

LCDs originais Hitachi têm 16 pinos — confuso. Hoje vendidos com módulo I2C (PCF8574) atrás — usa só 4 fios.

LCD I2C: GND, VCC, SDA (A4 no Uno), SCL (A5)

Instalar library "LiquidCrystal_I2C" (procurar em Library Manager).

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.print("Hello World!");
  lcd.setCursor(0, 1);
  lcd.print("Linha 2");
}

void loop() {
  lcd.setCursor(8, 1);
  lcd.print(millis() / 1000);
  delay(1000);
}

Endereço I2C: normalmente 0x27 ou 0x3F. Se nada aparecer, corre i2c_scanner (sketch popular) para descobrir.

OLED SSD1306 (128x64)

Display monocromático bonito, alto contraste, baixo consumo.

OLED I2C: GND, VCC (3.3V ou 5V), SDA (A4), SCL (A5)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello!");

  display.setTextSize(1);
  display.println("Texto pequeno");

  display.drawRect(0, 40, 100, 20, SSD1306_WHITE);
  display.fillCircle(110, 50, 8, SSD1306_WHITE);

  display.display();   // OBRIGATÓRIO para mostrar
}

void loop() {}

Libraries: Adafruit_GFX (gráficos genéricos) + Adafruit_SSD1306 (driver).

Outros displays

9. Comunicação

Serial — debug essencial

Cada Arduino tem UART (Universal Asynchronous Receiver-Transmitter) → comunicação serial via USB.

void setup() {
  Serial.begin(9600);   // baud rate (deve match com Serial Monitor)
}

void loop() {
  Serial.println("Hello");
  Serial.print("Valor: ");
  Serial.println(analogRead(A0));
  delay(1000);
}

Tools → Serial Monitor (Ctrl+Shift+M). Define mesma baud rate.

Receber dados via Serial

void loop() {
  if (Serial.available()) {
    String linha = Serial.readStringUntil('\n');
    linha.trim();

    if (linha == "on") {
      digitalWrite(LED, HIGH);
    } else if (linha == "off") {
      digitalWrite(LED, LOW);
    } else {
      Serial.print("Recebido: ");
      Serial.println(linha);
    }
  }
}

Para enviar comandos do PC: no Serial Monitor, escreve no campo de cima e Enter.

I2C — dois fios para muitos dispositivos

Bus I2C tem dois fios: SDA (data) e SCL (clock). Vários dispositivos partilham — cada um com endereço único (7 bits).

No Uno: A4 = SDA, A5 = SCL.

#include <Wire.h>

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

// Scanner I2C
void loop() {
  for (int addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    byte err = Wire.endTransmission();
    if (err == 0) {
      Serial.print("Encontrado em 0x");
      Serial.println(addr, HEX);
    }
  }
  delay(5000);
}

SPI — mais rápido, 4 fios

Para SD cards, displays grandes, alguns sensores rápidos. Pinos no Uno: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). Library <SPI.h>.

WiFi (precisa de board com WiFi)

Uno R4 WiFi, Nano 33 IoT, ESP32, ESP8266.

// Para ESP32
#include <WiFi.h>

const char* ssid = "Aulify-WiFi";
const char* pass = "secret";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected!");
  Serial.println(WiFi.localIP());
}

Daí abre-se mundo IoT (UC00643).

10. Multi-tarefas — millis() em vez de delay()

delay() bloqueia tudo durante esse tempo. Para fazer várias coisas "ao mesmo tempo", usar millis():

unsigned long lastBlink = 0;
unsigned long lastSensor = 0;
unsigned long lastDisplay = 0;
bool ledOn = false;

void loop() {
  unsigned long now = millis();

  // Pisca LED a cada 500ms
  if (now - lastBlink >= 500) {
    lastBlink = now;
    ledOn = !ledOn;
    digitalWrite(LED, ledOn ? HIGH : LOW);
  }

  // Lê sensor a cada 1000ms
  if (now - lastSensor >= 1000) {
    lastSensor = now;
    int v = analogRead(A0);
    Serial.println(v);
  }

  // Actualiza display a cada 2000ms
  if (now - lastDisplay >= 2000) {
    lastDisplay = now;
    updateDisplay();
  }
}

millis() retorna ms desde o reset. Overflow após ~50 dias, mas a subtracção mantém-se correcta por aritmética unsigned.

11. Boas práticas

Hardware

Código

Workflow

12. Projectos de inspiração

13. Recursos

Aprendizagem

Compra

Simulador

14. Próximos passos

Glossário

Arduino é o melhor sítio para começar electrónica programada. A combinação de hardware barato + software acessível + comunidade enorme torna a curva de aprendizagem suave mas profunda. Em 50 horas vais conseguir construir projectos genuinamente úteis. Em 500 horas dominas as bases para qualquer carreira em embedded, IoT ou robótica.