Tutoriais

Environments no PlatformIO e VSCode: Domine Compilações Avançadas em Projetos Arduino e ESP32

Eletrogate 23 de janeiro de 2026

Introdução

À medida que projetos com Arduino e ESP32 evoluem, surgem novas necessidades: modos de debug, firmware de produção, testes automatizados, cenários ou clientes diferentes, comportamentos específicos por versão e até variações de hardware usando o mesmo código-base.

Nesse cenário, usar apenas um projeto simples com um único main.cpp rapidamente se torna inviável. É exatamente aqui que o PlatformIO, integrado ao Visual Studio Code (VSCode), se destaca principalmente por meio do conceito de Environment.

Neste artigo, vamos explorar o que são os environments no PlatformIO, porque eles são fundamentais para projetos profissionais e como usá-los de forma avançada.
Para tornar tudo mais prático, todas as demonstrações serão baseadas em um circuito simples com ESP32, utilizando LEDs e botão, simulando diferentes cenários reais de desenvolvimento.

Ao final, você terá uma visão clara de como usar environments para criar firmwares distintos a partir do mesmo projeto, algo comum e essencial em produtos comerciais de IoT e sistemas embarcados.


O que é um Environment no PlatformIO?

De forma prática, um environment é um perfil completo de compilação. Cada projeto de firmware pode ter múltiplas configurações de compilação, definidas usando seções [env] e[env:NAME] no arquivo platformio.ini. Cada uma dessas seções é um environment (ambiente de configuração) que:

  • Define como o projeto será compilado
  • Quais opções de build serão usadas
  • Quais bibliotecas e fontes serão consideradas
  • Como será feito o upload, debug e monitoramento

Cada environment funciona como um contexto isolado de compilação, onde você pode ativar ou desativar funcionalidades, flags, arquivos ou mesmo modos de build.

Para saber mais sobre o VSCode e o PlatformIO veja o nosso artigo sobre: Como Programar o Arduino com VS Code e PlatformIO


Onde e como são definidos os environments?

Todos os environments ficam no arquivo: platformio.ini esse é o arquivo de configuração do projeto, nele podemos definir muitas configurações do projeto como, por exemplo:

  • Quais plataformas o projeto usa
  • Qual framework (por exemplo, Arduino, ESP-IDF etc.)
  • Quais ambientes (env) o projeto possui, usar diversas seções [env:NAME] permite que você crie diferentes tarefas de compilação para o mesmo projeto, sem precisar duplicar código ou criar múltiplos repositórios.

Esse é um exemplo de configuração de env:

[env]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

[platformio]
default_envs = release

[env:debug]
build_type = debug
build_flags =
  -D DEBUG_MODE
build_src_filter =
  +<main.cpp>

[env:release]
build_type = release
build_flags =
  -D RELEASE_MODE
build_src_filter =
  +<main.cpp>

[env:test]
build_flags =
  -D TEST_MODE
build_src_filter =
  +<main.cpp>

[env:other_functionality]
build_flags =
  -D OTHER_FUNCTIONALITY
build_src_filter =
  +<main.cpp>
  +<other_functionality.cpp>

[env:power_saving]
build_flags =
  -D POWER_SAVING
build_src_filter =
  +<main.cpp>

Neste exemplo:

  • A seção [env]contém configurações comuns, exemplo:
    • platform — Qual plataforma de desenvolvimento (ex: espressif32, atmelavr).
    • board — A placa física que você usará.
    • framework — O framework de desenvolvimento (ex: arduino, mbed, espidf).
    • monitor_speed — Baud rate do monitor serial.
    • build_flags — Flags extras enviadas ao compilador.
    • debug_tool — Ferramenta de debug configurada para o ambiente.
    • build_type — Pode ser debug ou release para ativar otimizações e símbolos de depuração.
  • As seções env:release,env:debug,env:test,env:other_functionality e env:power_saving herdam e ajustam essas configurações comuns e acrescentam ou modificam outras conforme necessário

Algumas opções mais usadas no environments:

  • Flags de compilação (build_flags)
  • Modo de teste (test)
  • Inclusão ou exclusão de fontes (build_src_filter)
  • Modo de build (build_type), como debug ou release
  • Quais bibliotecas serão usadas (lib_deps)

Para selecionar um environment basta clicar na seção “Switch platformIO project environment” na barra inferior do VSCode e selecionar o environments na lista que aparece, como na seguinte figura:

Isso significa que o mesmo projeto pode produzir firmwares completamente diferentes, apenas trocando o environment. Para mais opções consulte a documentação oficial: Documentação oficial


Environments usados neste artigo

Para a demonstração prática, vamos trabalhar com cinco environments distintos, simulando situações reais de desenvolvimento:

  1. env:debug – Build de desenvolvimento com logs e debug;
  2. env:release – Firmware final otimizado;
  3. env:test – Testes de lógica e hardware;
  4. env:other_functionality – Firmware com funcionalidades extras para algum cliente ou aplicação específica;
  5. env:power_saving – Firmware customizado que acendem os LEDs após pressionar o botão e apagam automaticamente após 2 segundos e faz o ESP32 entrar no modo deep sleep.

Antes de partir para o código, é fundamental entender o papel de cada environment e como eles impactam diretamente o firmware gerado.
Cada [env:NAME] representa um contexto isolado de build (Compilação), com suas próprias opções de compilação, macros, arquivos e comportamento final do programa.

[env:debug] — Ambiente de desenvolvimento e diagnóstico

Objetivo

O environment debug é usado durante o desenvolvimento do firmware. Ele prioriza visibilidade, facilidade de depuração e diagnóstico de problemas.

O que muda neste environment
  • Logs via Serial ficam ativos
  • LED 1 pisca de forma visível para indicar estados internos
  • LED 2 acende e apaga ao clicar no botão
  • Código não é otimizado
  • Ideal para testes em bancada
Impacto no código
  • Macros como DEBUG_MODE ficam ativas, no VSCode o código fica em destaque
  • Funções de log são compiladas
  • O botão imprime mensagens detalhadas no Serial Monitor

Na prática, esse firmware não é feito para produção, mas sim para o desenvolvedor entender o que está acontecendo internamente no ESP32.

[env:release] — Ambiente de produção (firmware final)

Objetivo

O release representa o firmware final, que será entregue ao usuário ou cliente.

O que muda neste environment
  • Logs são removidos
  • Código é otimizado
  • LED 1 pisca de forma visível para indicar estados internos
  • LED 2 acende e apaga ao clicar no botão
  • Menor tamanho de firmware
Impacto no código
  • Macro RELEASE_MODE ativa
  • Código de debug não é compilado
  • O botão executa ações silenciosas, sem mensagens
  • Apenas arquivos necessários entram na build

Esse é o firmware que você usaria em um produto real.

[env:test] — Ambiente de testes de hardware e lógica

Objetivo

O environment test é usado para validar o hardware e a lógica do sistema, muito comum em:

  • Testes de bancada
  • Testes de produção (end-of-line)
  • Validação de GPIOs
O que muda neste environment
  • LEDs piscam ao clicar no botão
  • Botão dispara rotinas de teste
  • Código focado em validação, não em funcionalidade final
Impacto no código
  • Macro TEST_MODE ativa
  • Funções de teste são compiladas
  • Código principal de aplicação pode nem ser usado

Esse firmware pode ser carregado temporariamente, apenas para validar o circuito verificando se o ESP32, LEDs e botão estão funcionando corretamente.

[env:other_functionality] – Firmware com funcionalidades extras para algum cliente ou aplicação específica;

Objetivo

Habilita um arquivo com funcionalidades extras para aplicações especificas ou necessidades específicas de algum cliente.

O que muda neste environment
  • LEDs representam estados específicos, piscam alternadamente
  • Botão executa uma ação exclusiva
  • Lógica interna diferente, mas reaproveitando o código comum
Impacto no código
  • Macro OTHER_FUNCTIONALITY ativa
  • Arquivos específicos entram na build
  • Fluxo de execução muda sem duplicar projeto

Esse modelo pode ser usado em alguma necessidade específica para algum cliente.

[env:power_saving] — Firmware customizado para economia de energia

Objetivo

Firmware customizado que acendem os LEDs e após 2 segundos desliga usando fade e faz o ESP32 entrar no modo deep sleep

O que muda neste environment
  • Função dos LEDs
  • Botão executa outra ação
  • Comportamento distinto do ESP32
Impacto no código
  • Macro POWER_SAVING ativa
  • O restante do código permanece reutilizável

Esse environment pode ser usado para cenários de economia de energia ou com uso de baterias.


Projeto de exemplo de environment

A seguir, um exemplo funcional completo, demonstrando claramente como o comportamento muda conforme o environment.

Essa é estrutura dos arquivos:

project/
├── platformio.ini
├── src/
│ ├── main.cpp
│ ├── other_functionality.cpp

Código completo (src/main.cpp)

#include <Arduino.h>

#ifdef OTHER_FUNCTIONALITY
void other_functionality_loop(bool buttonEvent);
#endif

#define LED1_PIN     2
#define LED2_PIN     4
#define BUTTON_PIN  15

bool lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;


void setup() {
  pinMode(LED1_PIN, OUTPUT);
  pinMode(LED2_PIN, OUTPUT);
#ifdef POWER_SAVING
  // Configura PWM para fade
  ledcAttachPin(LED1_PIN, 0); // canal 0
  ledcAttachPin(LED2_PIN, 1); // canal 1
  ledcSetup(0, 5000, 8); // canal 0, 5kHz, 8 bits
  ledcSetup(1, 5000, 8); // canal 1, 5kHz, 8 bits
#endif
  pinMode(BUTTON_PIN, INPUT); // Usando resistor de pulldown externo

#if defined(DEBUG_MODE) || defined(TEST_MODE) || defined(OTHER_FUNCTIONALITY)
  Serial.begin(115200);
  delay(500);
#endif

#ifdef DEBUG_MODE
  Serial.println("=== ENV: DEBUG ===");
  Serial.println("Modo de desenvolvimento ativo");
  Serial.println("Logs detalhados habilitados");
#endif

#ifdef TEST_MODE
  Serial.begin(115200);
  Serial.println("=== ENV: TEST ===");
  Serial.println("Firmware de teste de hardware");
#endif

#ifdef OTHER_FUNCTIONALITY
  Serial.println("=== ENV: OTHER_FUNCTIONALITY ===");
#endif
}

// Detecta evento de pressionamento (borda de subida) com debounce para pushbutton
bool buttonPressedEvent() {
  static bool lastButtonState = LOW;
  static bool debouncedState = LOW;
  static unsigned long lastDebounceTime = 0;
  bool event = false;
  bool reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
    Serial.println("[BTN] Mudança detectada, debounce iniciado");
  }
  lastButtonState = reading;

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (debouncedState != reading) {
      debouncedState = reading;
      if (debouncedState == HIGH) {
        event = true;
        Serial.println("[BTN] Evento de pressionamento detectado!");
      }
    }
  }
  return event;
}

void loop() {
  bool buttonEvent = buttonPressedEvent();

#ifdef DEBUG_MODE
  static unsigned long lastBlink = 0;
  if (millis() - lastBlink > 500) {
    digitalWrite(LED1_PIN, !digitalRead(LED1_PIN));
    lastBlink = millis();
    Serial.println("[DEBUG] LED1 piscando (heartbeat)");
  }
  if (buttonEvent) {
    Serial.println("[DEBUG] Botão pressionado");
    digitalWrite(LED2_PIN, !digitalRead(LED2_PIN));
    Serial.print("[DEBUG] LED2 agora está: ");
    Serial.println(digitalRead(LED2_PIN) ? "LIGADO" : "DESLIGADO");
  }
  delay(10);
#endif

#ifdef RELEASE_MODE
  static unsigned long lastBlink = 0;
  if (millis() - lastBlink > 500) {
    digitalWrite(LED1_PIN, !digitalRead(LED1_PIN));
    lastBlink = millis();
  }
  if (buttonEvent) {
    digitalWrite(LED2_PIN, !digitalRead(LED2_PIN));
  }
  delay(10);
#endif

#ifdef TEST_MODE
  if (digitalRead(BUTTON_PIN) == HIGH) {
    Serial.println("[TEST] Botão pressionado, piscando LED1");
    digitalWrite(LED1_PIN, HIGH);
    delay(150);
    digitalWrite(LED1_PIN, LOW);
    delay(150);

    Serial.println("[TEST] Botão pressionado, piscando LED2");
    digitalWrite(LED2_PIN, HIGH);
    delay(150);
    digitalWrite(LED2_PIN, LOW);
    delay(150);
  }
#endif

#ifdef OTHER_FUNCTIONALITY
  // Chama função especial do outro arquivo
  other_functionality_loop(buttonEvent);
#endif

#ifdef POWER_SAVING
  // Fade nos LEDs e entra em deep sleep após 3 segundos sem interação
  static unsigned long lastActivity = 0;
  if (buttonEvent) {
    for (int i = 0; i <= 255; i += 5) {
      ledcWrite(0, i); // LED1
      ledcWrite(1, i); // LED2
      delay(15);
    }
    lastActivity = millis();
  }
  if (millis() - lastActivity > 1500) {
    for (int i = 255; i >= 0; i -= 5) {
      ledcWrite(0, i);
      ledcWrite(1, i);
      delay(15);
    }
    Serial.println("[POWER_SAVING] Entrando em deep sleep para economizar energia");
    delay(100);
    esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, 1); // Acorda com nível alto
    esp_deep_sleep_start();
  }
#endif

}

Código completo (src/other_functionality.cpp)

#include <Arduino.h>
#define LED1_PIN     2
#define LED2_PIN     4

// Funcionalidade adicional: ao detectar o evento de botão, pisca LED1 5x e LED2 3x
void other_functionality_loop(bool buttonEvent) {
    static int stage = 0, count = 0;
    static unsigned long lastBlink = 0;
    static bool ledState = LOW;

    if (buttonEvent && stage == 0) {
        stage = 1; count = 0; ledState = LOW; lastBlink = millis();
    }

    if (stage == 1 && millis() - lastBlink > 150) { // Pisca LED1 5x
        ledState = !ledState;
        digitalWrite(LED1_PIN, ledState);
        lastBlink = millis();
        if (ledState == HIGH) count++;
        if (count >= 5 && ledState == LOW) {
            digitalWrite(LED1_PIN, LOW);
            stage = 2; count = 0; ledState = LOW; lastBlink = millis();
        }
    }

    if (stage == 2 && millis() - lastBlink > 150) { // Pisca LED2 3x
        ledState = !ledState;
        digitalWrite(LED2_PIN, ledState);
        lastBlink = millis();
        if (ledState == HIGH) count++;
        if (count >= 3 && ledState == LOW) {
            digitalWrite(LED2_PIN, LOW);
            stage = 0;
        }
    }
}

Essa organização permite ativar ou desativar módulos inteiros por environment, sem bagunçar o código.


Materiais Necessários para o Projeto

Todos os materiais podem ser comprados em nossa loja


Circuito

Abaixo a imagem do circuito simples para a demonstração dos environments

Conexões usadas

Componente GPIO
LED 1 GPIO 2
LED 2 GPIO 4
Botão GPIO 15


Resultado e Demonstração

Na imagem a baixo tem um print das mensagens que aparecem quando é usado o environment de Debug:

Vídeo com a demonstração dos environments:


Conclusão

O conceito de environment no PlatformIO vai muito além de uma simples configuração. Ele é a base para:

  • Projetos escaláveis
  • Firmwares profissionais
  • Produtos comerciais
  • Manutenção de longo prazo

Neste artigo, vimos como um simples circuito com ESP32, dois LEDs e um botão pode se comportar de cinco formas completamente diferentes, apenas trocando o environment ativo. Se você quer sair do nível hobby e começar a desenvolver firmware de verdade, dominar environments não é opcional é essencial. Para mais materiais como esse, continue acompanhando as postagens semanais do blog e não deixe de visitar nossa loja. Lá, você encontra todos os componentes necessários para desenvolver esse e muitos outros projetos!

Que a força esteja com vocês e até mais!


Referências

Algumas referências utilizadas no artigo:

https://docs.platformio.org/en/latest/projectconf/sections/env/index.html


Sobre o Autor


Saulo Aislan

Graduando em Tecnologia em Telemática pelo IFPB – Campus de Campina Grande – PB. Tenho experiência com os microcontroladores da família Arduino, ESP8266, ESP32, STM32 e microprocessador Raspberry Pi. Tenho projetos na áreas de IoTs voltada para a indústria 4.0, agroindústria e indústria aeroespacial civil utilizando LoRa, Bluetooth, ZigBee e Wi-Fi. Atualmente estudando e desenvolvendo em FreeRTOS para sistemas em tempo real com ESP32 e LoRaWan para Smart City e compartilhando alguns projetos no blog da Eletrogate.


Eletrogate

23 de janeiro de 2026

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Os comentários estão desativados.

Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!

Eletrogate Robô

Assine nossa newsletter e
receba  10% OFF  na sua
primeira compra!