Entendendo Parâmetros por Referência no Arduino: Como Usar Objetos e Funções de Forma Inteligente

Aprenda de forma simples e prática como usar referências em funções Arduino

Objetivo

O objetivo deste tutorial é mostrar, de forma clara e prática, o conceito de parâmetros por referência no Arduino, utilizando o operador & em funções. Você leitor entenderá a diferença entre passar variáveis e objetos por valor ou por referência, entendendo como isso impacta o desempenho, a memória e o comportamento do código.

Ao final do artigo, o leitor será capaz de:

  • Identificar quando usar referências (&) em funções;

  • Compreender como o Arduino manipula objetos e variáveis internamente;

  • Escrever códigos mais eficientes, modulares e profissionais;

  • Aplicar o conceito em projetos reais, como controle de servos, sensores, displays e bibliotecas.

Em resumo, este tutorial tem como propósito aprofundar o conhecimento de iniciantes e intermediários em Arduino na linguagem C++, tornando-os capazes de aproveitar todo o potencial das funções e objetos com passagem por referência.

Referências

Como criar e utilizar Funções para organizar seu código em Arduino

Projeto 48a - Como controlar um display LCD com o módulo I2C (LiquidCrystal_I2C)

Definições

Quando começamos a programar com Arduino, um dos primeiros conceitos que aprendemos é a criação de funções. Elas nos ajudam a organizar o código, reutilizar trechos e tornar os programas mais legíveis.

Com o tempo, nossos projetos vão ficando mais complexos — passamos a usar sensores, motores, displays LCD, módulos Wi-Fi e outras bibliotecas externas. É aí que surge uma dúvida muito comum entre desenvolvedores:

“Por que em algumas funções eu passo uma variável normalmente, como int x, e em outras vejo algo estranho como Servo &servo ou LiquidCrystal_I2C &lcd?”

Esse pequeno símbolo “&”, que aparece antes do nome do parâmetro, costuma causar confusão até mesmo entre quem já tem alguma experiência. Ele não significa endereço de memória, como muitos pensam ao associá-lo aos ponteiros, mas algo muito mais simples e prático: ele indica que o parâmetro está sendo passado por referência.

A passagem por referência é um conceito fundamental da linguagem C++, que está por trás da programação do Arduino. Ela define como os dados são transmitidos para dentro das funções — e entender isso muda completamente a forma como você escreve e otimiza seus programas.

Em vez de apenas enviar uma cópia do valor (como acontece normalmente), o Arduino pode permitir que uma função acesse diretamente a variável ou objeto original. Isso traz várias vantagens, como:

  • Maior eficiência, pois evita cópias desnecessárias;

  • Menor uso de memória, algo essencial nos microcontroladores;

  • E a possibilidade de alterar o valor original de dentro da função.

Compreender esse comportamento é o que separa o programador iniciante do programador consciente, capaz de escrever códigos otimizados e de entender como o Arduino lida com variáveis, objetos e memória

Entendendo como os parâmetros são passados

Toda vez que chamamos uma função no Arduino, podemos passar valores ou objetos de duas formas:

  1. Por valor (cópia)

  2. Por referência (acesso direto ao original)

1️⃣ Passagem por valor

Quando passamos um parâmetro por valor, o Arduino cria uma cópia da variável dentro da função. Isso significa que qualquer alteração feita ali não afeta o valor original.

Exemplo:

void dobrar(int numero) {
  numero = numero * 2;
}

void setup() {
  int valor = 10;
  dobrar(valor);
  Serial.begin(9600);
  Serial.println(valor); // Continua sendo 10, não mudou!
}

Atenção: Aqui, a função dobrar() recebeu uma cópia de valor. Alterar numero não altera valor fora da função.

2️⃣ Passagem por referência

Agora veja o mesmo exemplo, mas usando referência com o operador &:

void dobrar(int &numero) {
  numero = numero * 2;
}

void setup() {
  Serial.begin(9600);
  int valor = 10;
  dobrar(valor);
  Serial.println(valor); // Agora imprime 20!
}

Atenção: Nesse caso, numero não é uma cópia, mas um apelido (referência) para a mesma variável original. Qualquer modificação feita dentro da função reflete diretamente no valor real.

Passagem de objetos por referência

Quando lidamos com bibliotecas Arduino, como:

  • Servo

  • LiquidCrystal

  • SoftwareSerial

  • WiFiClient

  • Adafruit_Sensor

Esses objetos contêm dados internos e ponteiros de hardware. Se você tentasse copiá-los, o Arduino ficaria sem saber qual instância é a “verdadeira”.

Por isso, sempre que for manipular um objeto existente, prefira usar (exemplos):

void atualizarDisplay(LiquidCrystal_I2C &lcd);
void moverMotor(Servo &motor);
void enviarDados(WiFiClient &cliente);

Resumo prático

  • mostrarMensagem(LiquidCrystal_I2C lcd, ...)Copia o objeto

  • mostrarMensagem(LiquidCrystal_I2C &lcd, ...)Usa o mesmo objeto original

Por que isso é importante no Arduino

O Arduino tem memória muito limitada (apenas 2 KB de RAM no Uno).

Ao trabalhar com objetos grandes (como um display LCD, sensor ultrassônico ou conexão WiFi), copiar esses dados cada vez que chamamos uma função é custoso e pode travar o microcontrolador.

Passar por referência resolve isso:

  • Nenhuma cópia é feita;

  • O código roda mais rápido;

  • O consumo de memória é menor;

  • A função pode modificar o objeto original, se necessário.

Exemplos práticos com um objeto: LCD I2C

a) Quando o & não aparece, mas a referência existe (sem necessidade do símbolo &)

Neste exemplo, o objeto lcd é criado uma única vez e usado diretamente no loop().

Mesmo sem criar uma função, o conceito de “referência” ainda está presente — pois estamos manipulando o mesmo objeto (lcd) ao longo de todo o programa.

#include <LiquidCrystal_I2C.h>

// Cria um único objeto LCD no endereço 0x27 e com 16 colunas por 2 linhas
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();       // Inicializa o display
  lcd.backlight();  // Liga a luz de fundo
  lcd.clear();      // Limpa o conteúdo inicial
}

void loop() {
  // --- Usa sempre o mesmo objeto LCD já criado ---
  lcd.setBacklight(HIGH);  // Liga a luz de fundo
  lcd.setCursor(1, 0);
  lcd.print("Squids Arduino");
  lcd.setCursor(0, 1);
  lcd.print("LCD e modulo I2C");

  delay(1000); // Espera 1 segundo

  lcd.setBacklight(LOW); // Desliga o backlight

  delay(1000); // Espera mais 1 segundo
}
  • O objeto lcd é criado fora de qualquer função, no início do código.

  • Isso significa que ele é global, ou seja, pode ser usado por todo o programa.

  • Todas as instruções no loop() acessam exatamente o mesmo display.

  • É o método mais eficiente, pois o objeto é inicializado apenas uma vez.

b) Sem passagem por referência (Passagem por Valor)

Neste exemplo, a função mostrarMensagem() cria seu próprio objeto LCD dentro dela — um objeto independente.

/*******************************************************************************
*
*  Projeto 48a: Ligando o Display LCD 16x2 (com passagem por referência)
*  http://squids.com.br/arduino
*
*******************************************************************************/
#include <LiquidCrystal_I2C.h>

// --- Função que cria e controla o LCD local ---
void mostrarMensagem() {
  LiquidCrystal_I2C display(0x27, 16, 2); // Cria novo objeto local
  display.init();
  display.backlight();

  display.setCursor(1, 0);
  display.print("Squids Arduino");
  display.setCursor(0, 1);
  display.print("LCD e modulo I2C");
  delay(1000);
  display.setBacklight(LOW);
  delay(1000);
}

void setup() {
  // Não há necessidade de inicializar o LCD globalmente
}

void loop() {
  mostrarMensagem(); // Chama a função (novo LCD a cada execução)
}
  • O objeto LiquidCrystal_I2C display é criado toda vez que a função é chamada.

  • Quando a função termina, o objeto é destruído da memória.

  • O display ainda funciona, porque é inicializado e usado dentro da função — mas essa prática é pouco eficiente.

  • Cada chamada cria e destrói o objeto, ocupando mais memória e aumentando o tempo de inicialização.

c) Quando é necessário a passagem por referência com o símbolo (&)

Neste exemplo, a função mostrarMensagem() recebe o objeto lcd por referência — ou seja, a função trabalha diretamente com o mesmo objeto já criado no programa, sem a precisar que o objeto LiquidCrystal_I2C display seja criado toda vez que a função é chamada.

#include <LiquidCrystal_I2C.h>

// Define o endereço I2C e o tamanho do display
LiquidCrystal_I2C lcd(0x27, 16, 2); // Exemplo para display 16x2

// --- Função que controla o LCD ---
void mostrarMensagem(LiquidCrystal_I2C &display) {
  display.setBacklight(HIGH);
  display.setCursor(1, 0);
  display.print("Squids Arduino");
  display.setCursor(0, 1);
  display.print("LCD e modulo I2C");
  delay(1000);
  display.setBacklight(LOW);
  delay(1000);
}

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
}

void loop() {
  mostrarMensagem(lcd); // Passa o objeto por referência
}
  • LiquidCrystal_I2C &display → o símbolo & indica referência, ou seja, a função não cria uma cópia do objeto.

  • A função mostrarMensagem() atua diretamente sobre o mesmo LCD declarado no início do código.

  • É eficiente: baixo consumo de memória e execução rápida.

  • Todas as alterações feitas dentro da função afetam o mesmo display.

d) Usando 2 displays LCD diferentes (PASSAGEM POR REFERÊNCIA)

Recomendado quando quiser operar o mesmo objeto:

Aqui os displays são objetos globais criados no topo. A função recebe uma referência ao objeto (LiquidCrystal_I2C &display), ou seja, ela trabalha diretamente com o mesmo objeto já inicializado.

/*******************************************************************************
*
*   Projeto: Dois Displays LCD I2C - Passagem por Referência
*   Descrição: Exemplo funcional com dois displays I2C de endereços diferentes.
*   Autor: Arduino Maestro
*******************************************************************************/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Dois displays com endereços diferentes
LiquidCrystal_I2C lcd1(0x27, 16, 2);
LiquidCrystal_I2C lcd2(0x3F, 16, 2);

// Função que recebe o display por referência (sem cópia)
void mostrarMensagem(LiquidCrystal_I2C &display, String texto) {
  display.clear();
  display.setCursor(0, 0);
  display.print("Display Teste:");
  display.setCursor(0, 1);
  display.print(texto);
}

void setup() {
  lcd1.init();
  lcd1.backlight();

  lcd2.init();
  lcd2.backlight();

  // Agora a função manipula o mesmo objeto original
  mostrarMensagem(lcd1, "Squids Arduino");
  delay(2000);
  mostrarMensagem(lcd2, "Bem Vindos");
}

void loop() {
  // Nada aqui
}
  • A função não cria cópias; ela opera diretamente no objeto original.

  • Muito eficiente em memória e tempo — ideal para microcontroladores com pouca RAM.

  • Padrão recomendado ao trabalhar com LiquidCrystal_I2C, Servo, etc.

  • Obs.: Para ligar os dois displays no mesmo barramento, e eles devem ter endereços diferentes para que sejam acionados de forma independente e correta. 

Benefícios práticos do uso de referências

Eficiência: evita cópias desnecessárias de variáveis e objetos.
Velocidade: a função acessa o mesmo dado em memória.
Flexibilidade: permite alterar valores sem precisar de return.
Compatibilidade: algumas bibliotecas só aceitam objetos passados por referência.
Organização: facilita criar funções genéricas reutilizáveis.

Quando não usar referência

Apesar de útil, há casos em que não vale a pena usar referências:

  • Quando a função só precisa ler o valor e não alterá-lo (a cópia é mais segura).

  • Quando a variável é muito pequena (ex: int, bool, byte) e o ganho de desempenho é insignificante.

  • Quando é importante manter o valor original intacto.

Nessas situações, a passagem por valor é mais simples e segura.

Conclusão

Compreender a passagem por referência (&) é um dos passos mais importantes para quem quer sair do nível básico e programar de forma profissional com Arduino.

Esse recurso:

  • Otimiza memória e desempenho;

  • Permite criar funções mais flexíveis e modulares;

  • É essencial ao trabalhar com objetos de bibliotecas externas.

Portanto, sempre que você vir algo como Servo &servo ou LiquidCrystal_I2C &lcd, lembre-se: Essa função não cria cópia — ela manipula o objeto real, com eficiência e precisão

O anúncio abaixo ajuda a manter o Squids Arduino funcionando

Comentários

×

Infomações do site / SEO








×

Adicionar Marcadores