📚 NÍVEL 1 - BÁSICO (Semanas 3-6)

Progresso: [ ] Semana 3 [ ] Semana 4 [ ] Semana 5 [ ] Semana 6 [ ] Projeto Final

📑 Índice

Semana 3: GPIO Básico

Semana 4: PWM e Sons

Semana 5: ADC (Conversor Analógico-Digital)

Semana 6: Display 7 Segmentos

🎯 Projeto Final: Semáforo Inteligente

⚠️ Problemas Comuns e Soluções

🔗 Próximos Passos


Semana 3: GPIO Básico

📊 Metadados:

📖 Fundamentos - GPIO (General Purpose Input/Output)

O que é GPIO?

Modos de Operação:

Bouncing em Botões:

APIs Principais ESP-IDF:

1
2
3
4
5
gpio_reset_pin()           // Reseta configuração do pino
gpio_set_direction()       // Define modo (input/output)
gpio_set_level()           // Define estado (HIGH/LOW)
gpio_get_level()           // Lê estado do pino
gpio_set_pull_mode()       // Configura pull-up/pull-down

Objetivo: Piscar LED usando vTaskDelay

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define LED_PIN GPIO_NUM_2  // LED interno

void app_main(void)
{
    // Configurar pino como saída
    gpio_reset_pin(LED_PIN);
    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
    
    while(1) {
        gpio_set_level(LED_PIN, 1);  // Liga
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        gpio_set_level(LED_PIN, 0);  // Desliga
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

Desafios:

  1. 🟢 Fácil: Fazer piscar mais rápido e alternado com outro led
  2. 🟡 Médio: Criar padrão S.O.S em morse (curto-curto-curto, longo-longo-longo, curto-curto-curto)
  3. 🔴 Difícil: Usar 3 LEDs alternados criando efeito de “corrida”
  4. Extra: Fazer os três níveis anteriores ao mesmo tempo

Exercício 2: Leitura de Botão

Objetivo: Controlar LED com botão

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define LED_PIN GPIO_NUM_2
#define BUTTON_PIN GPIO_NUM_0  // Boot button

void app_main(void)
{
    // LED como saída
    gpio_reset_pin(LED_PIN);
    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
    
    // Botão como entrada com pull-up
    gpio_reset_pin(BUTTON_PIN);
    gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
    gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
    
    while(1) {
        int button_state = gpio_get_level(BUTTON_PIN);
        
        if(button_state == 0) {  // Botão pressionado (pull-up)
            gpio_set_level(LED_PIN, 1);
        } else {
            gpio_set_level(LED_PIN, 0);
        }
        
        vTaskDelay(10 / portTICK_PERIOD_MS);  // Pequeno delay
    }
}

Desafios:

  1. 🟢 Fácil: Inverter lógica (botão apaga LED ao invés de acender)
  2. 🟡 Médio: Toggle LED (liga/desliga ao pressionar uma vez)
  3. 🔴 Difícil: Contar quantas vezes o botão foi pressionado e exibir no serial

Exercício 3: Debounce de Botão

Objetivo: Eliminar bouncing mecânico do botão

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define DEBOUNCE_TIME_MS 50

bool read_button_debounced(gpio_num_t pin) {
    static int last_state = 1;
    static uint32_t last_time = 0;
    
    int current_state = gpio_get_level(pin);
    uint32_t current_time = xTaskGetTickCount() * portTICK_PERIOD_MS;
    
    if(current_state != last_state) {
        if((current_time - last_time) > DEBOUNCE_TIME_MS) {
            last_state = current_state;
            last_time = current_time;
            return true;  // Mudança válida
        }
    }
    
    return false;
}

void app_main(void)
{
    gpio_reset_pin(LED_PIN);
    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
    gpio_reset_pin(BUTTON_PIN);
    gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
    gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
    
    bool led_state = false;
    
    while(1) {
        if(read_button_debounced(BUTTON_PIN)) {
            if(gpio_get_level(BUTTON_PIN) == 0) {
                led_state = !led_state;
                gpio_set_level(LED_PIN, led_state);
            }
        }
        vTaskDelay(1 / portTICK_PERIOD_MS);
    }
}

Desafios:

  1. 🟢 Fácil: Ajustar tempo de debounce para 100ms
  2. 🟡 Médio: Implementar detecção de pressionamento longo (> 2 segundos)
  3. 🔴 Difícil: Criar contador de cliques duplos (double-click)

Semana 4: PWM e Sons

📊 Metadados:

📖 Fundamentos - PWM (Pulse Width Modulation)

O que é PWM?

Aplicações:

LEDC no ESP32:

APIs Principais:

1
2
3
4
5
ledc_timer_config()        // Configura timer PWM
ledc_channel_config()      // Configura canal
ledc_set_duty()           // Define duty cycle
ledc_update_duty()        // Aplica mudanças
ledc_set_freq()           // Muda frequência (para sons)

Exercício 4: Fade LED com PWM

Objetivo: Controlar brilho de LED com PWM

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "driver/ledc.h"

#define LED_PIN GPIO_NUM_2
#define PWM_CHANNEL LEDC_CHANNEL_0
#define PWM_TIMER LEDC_TIMER_0

void setup_pwm(void)
{
    // Configurar timer
    ledc_timer_config_t timer_conf = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .duty_resolution = LEDC_TIMER_8_BIT,  // 0-255
        .timer_num = PWM_TIMER,
        .freq_hz = 5000,
        .clk_cfg = LEDC_AUTO_CLK
    };
    ledc_timer_config(&timer_conf);
    
    // Configurar canal
    ledc_channel_config_t channel_conf = {
        .gpio_num = LED_PIN,
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = PWM_CHANNEL,
        .timer_sel = PWM_TIMER,
        .duty = 0,
        .hpoint = 0
    };
    ledc_channel_config(&channel_conf);
}

void app_main(void)
{
    setup_pwm();
    
    while(1) {
        // Fade in
        for(int duty = 0; duty <= 255; duty++) {
            ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, duty);
            ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
            vTaskDelay(10 / portTICK_PERIOD_MS);
        }
        
        // Fade out
        for(int duty = 255; duty >= 0; duty--) {
            ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, duty);
            ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
            vTaskDelay(10 / portTICK_PERIOD_MS);
        }
    }
}

Desafios:

  1. 🟢 Fácil: Inverter animação (começar com fade out)
  2. 🟡 Médio: Criar efeito de “respiração” com velocidade variável
  3. 🔴 Difícil: Controlar 3 LEDs RGB independentemente criando efeitos de cores

Exercício 5: Buzzer com Notas Musicais

Objetivo: Gerar tons musicais diferentes

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#define BUZZER_PIN GPIO_NUM_4
#define PWM_CHANNEL LEDC_CHANNEL_0

// Frequências das notas (Hz)
#define NOTE_C4 262
#define NOTE_D4 294
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_G4 392
#define NOTE_A4 440
#define NOTE_B4 494
#define NOTE_C5 523

void play_note(int frequency, int duration_ms)
{
    if(frequency > 0) {
        ledc_set_freq(LEDC_LOW_SPEED_MODE, PWM_TIMER, frequency);
        ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, 128);  // 50%
        ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
    }
    
    vTaskDelay(duration_ms / portTICK_PERIOD_MS);
    
    // Silêncio
    ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, 0);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
    vTaskDelay(50 / portTICK_PERIOD_MS);
}

void app_main(void)
{
    // Setup PWM igual ao exercício anterior
    setup_pwm();
    
    while(1) {
        // Toca escala C maior
        play_note(NOTE_C4, 500);
        play_note(NOTE_D4, 500);
        play_note(NOTE_E4, 500);
        play_note(NOTE_F4, 500);
        play_note(NOTE_G4, 500);
        play_note(NOTE_A4, 500);
        play_note(NOTE_B4, 500);
        play_note(NOTE_C5, 500);
        
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

Desafios:

  1. 🟢 Fácil: Tocar melodia simples (ex: Parabéns pra Você)
  2. 🟡 Médio: Adicionar pausas entre notas e controlar ritmo
  3. 🔴 Difícil: Criar sistema de alarme com padrões de beep diferentes

Semana 5: ADC (Conversor Analógico-Digital)

📊 Metadados:

📖 Fundamentos - ADC (Analog-to-Digital Converter)

O que é ADC?

Características ESP32:

Atenuação (Attenuation):

Conversões Úteis:

1
2
float voltage = (raw_value / 4095.0) * 3.3;  // Para voltagem
int percent = (raw_value * 100) / 4095;     // Para percentual

APIs Principais:

1
2
3
adc1_config_width()        // Define resolução
adc1_config_channel_atten() // Define atenuação
adc1_get_raw()             // Lê valor bruto

Exercício 6: Ler Potenciômetro

Objetivo: Ler valores analógicos e converter para voltagem

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "driver/adc.h"

#define POT_PIN ADC1_CHANNEL_6  // GPIO34

void app_main(void)
{
    // Configurar ADC
    adc1_config_width(ADC_WIDTH_BIT_12);  // 0-4095
    adc1_config_channel_atten(POT_PIN, ADC_ATTEN_DB_11);  // 0-3.3V
    
    while(1) {
        int raw_value = adc1_get_raw(POT_PIN);
        float voltage = (raw_value / 4095.0) * 3.3;
        
        printf("Raw: %d, Voltage: %.2fV\n", raw_value, voltage);
        
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

Desafios:

  1. 🟢 Fácil: Exibir valor em percentual (0-100%)
  2. 🟡 Médio: Criar barágrafo no serial (ex: [==== ] 40%)
  3. 🔴 Difícil: Implementar média móvel para suavizar leituras ruidosas

Exercício 7: Controlar LED com Potenciômetro

Objetivo: Integrar ADC + PWM para controle de brilho

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void app_main(void)
{
    setup_pwm();
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_config_channel_atten(POT_PIN, ADC_ATTEN_DB_11);
    
    while(1) {
        int raw = adc1_get_raw(POT_PIN);
        int duty = (raw * 255) / 4095;  // Mapeia 0-4095 para 0-255
        
        ledc_set_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL, duty);
        ledc_update_duty(LEDC_LOW_SPEED_MODE, PWM_CHANNEL);
        
        printf("Brilho: %d%%\n", (duty * 100) / 255);
        
        vTaskDelay(50 / portTICK_PERIOD_MS);
    }
}

Desafios:

  1. 🟢 Fácil: Adicionar histerese para evitar flickering
  2. 🟡 Médio: Controlar freqüência de buzzer com potenciômetro
  3. 🔴 Difícil: Controlar cor de LED RGB usando 3 potenciômetros (R, G, B)

Semana 6: Display 7 Segmentos

📊 Metadados:

📖 Fundamentos - Display 7 Segmentos

O que é?

Controle:

Padrões de Dígitos:


Exercício 8: Controlar Display 7seg

Objetivo: Exibir dígitos 0-9 em display 7 segmentos

Componentes Necessários:

Conceitos:

Código Básico pro Exercício
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Definir pinos (ajuste conforme sua conexão)
#define SEG_A GPIO_NUM_13
#define SEG_B GPIO_NUM_12
#define SEG_C GPIO_NUM_14
#define SEG_D GPIO_NUM_27
#define SEG_E GPIO_NUM_26
#define SEG_F GPIO_NUM_25
#define SEG_G GPIO_NUM_33

const gpio_num_t segments[] = {SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_F, SEG_G};

// Padrões para dígitos 0-9 (catodo comum)
const uint8_t digit_patterns[] = {
    0b00111111,  // 0
    0b00000110,  // 1
    0b01011011,  // 2
    0b01001111,  // 3
    0b01100110,  // 4
    0b01101101,  // 5
    0b01111101,  // 6
    0b00000111,  // 7
    0b01111111,  // 8
    0b01101111   // 9
};

void setup_7seg(void)
{
    for(int i = 0; i < 7; i++) {
        gpio_reset_pin(segments[i]);
        gpio_set_direction(segments[i], GPIO_MODE_OUTPUT);
    }
}

void display_digit(int digit)
{
    if(digit < 0 || digit > 9) return;
    
    uint8_t pattern = digit_patterns[digit];
    
    for(int i = 0; i < 7; i++) {
        gpio_set_level(segments[i], (pattern >> i) & 1);
    }
}

void app_main(void)
{
    setup_7seg();
    
    int counter = 0;
    
    while(1) {
        display_digit(counter);
        counter = (counter + 1) % 10;
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

Desafios:

  1. 🟢 Fácil: exibir os dígitos de 0 a 9 ao pressionar um botão (incrementa a cada clique)
  2. 🟡 Médio: contar de 0 a 9 e depois de 9 para 0, alternando a cada ciclo
  3. 🔴 Difícil: exibir um contador controlado por dois botoes: um incrementa e outro decrementa

🎯 Projeto Final: Semáforo Inteligente

📊 Metadados do Projeto:

Descrição: Sistema de semáforo completo com controle automático, botão de pedestre, display de contagem regressiva e sinalizador sonoro.

Componentes Necessários:

Funcionalidades Obrigatórias:

  1. ✅ Ciclo automático: Verde (10s) → Amarelo (3s) → Vermelho (10s)
  2. ✅ Botão de pedestre interrompe ciclo (com debounce)
  3. ✅ Display 7seg mostra tempo restante em cada estado
  4. ✅ Buzzer sinaliza mudanças de estado
  5. ✅ LED verde pisca antes de mudar para amarelo (aviso)

Diagrama de Estados:

1
2
3
4
VERDE (10s) --> AMARELO (3s) --> VERMELHO (10s) --> [loop]
    ↑                                    |
    |         BOTÃO PEDESTRE             |
    +------------------------------------+

Pinout Sugerido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// LEDs
#define LED_RED    GPIO_NUM_25
#define LED_YELLOW GPIO_NUM_26
#define LED_GREEN  GPIO_NUM_27

// Botão
#define BTN_PEDESTRIAN GPIO_NUM_0  // Botão BOOT

// Display 7seg
#define SEG_A GPIO_NUM_13
#define SEG_B GPIO_NUM_12
#define SEG_C GPIO_NUM_14
#define SEG_D GPIO_NUM_27
#define SEG_E GPIO_NUM_26
#define SEG_F GPIO_NUM_25
#define SEG_G GPIO_NUM_33

// Buzzer
#define BUZZER GPIO_NUM_4
Template Básico pro Projeto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
typedef enum {
    STATE_GREEN,
    STATE_YELLOW,
    STATE_RED,
    STATE_PEDESTRIAN_WAIT
} traffic_state_t;

typedef struct {
    traffic_state_t current_state;
    int time_remaining;
    bool pedestrian_requested;
} traffic_system_t;

void setup_leds(void);

void setup_button(void);

void setup_display(void) {
    // Configurar pinos do display 7seg
    // (implementar baseado no Exercício 8)
}

void setup_buzzer(void) {
    // Configurar PWM para buzzer
    // (implementar baseado no Exercício 5)
}

void set_traffic_light(traffic_state_t state) {
    // Configurar os leds para seguirem o padrão de acordo com os estados
}

void play_beep(void) {
    // Tocar beep curto (implementar com buzzer)
}

void display_number(int num) {
    // Exibir número no display (implementar baseado no Exercício 8)
}

bool read_pedestrian_button(void) {
    // Implementar leitura com debounce (Exercício 3)
    static int last_state = 1;
    static uint32_t last_time = 0;
    // ... código de debounce aqui
    return false;
}

void traffic_light_task(void *pvParameters) {
    traffic_system_t system = {
        .current_state = STATE_GREEN,
        .time_remaining = 10,
        .pedestrian_requested = false
    };
    
    while(1) {
        // Verificar botão pedestre
        
        // Exibir tempo no display
        
        // Lógica da máquina de estados
            // Piscar LED verde nos últimos 3 segundos 
            // Se pedestre solicitou o vermelho, dar mais tempo
    }
}

void app_main(void) {
    setup_leds();
    setup_button();
    setup_display();
    setup_buzzer();
    
    xTaskCreate(traffic_light_task, "traffic_light", 4096, NULL, 5, NULL);
}

Critérios de Avaliação:

Extensões Opcionais (🌟 Desafios Extras):

  1. 🟡 Adicionar modo noturno (amarelo piscando)
  2. 🟡 Usar ADC para sensor de luminosidade (ativa modo noturno)
  3. 🔴 Implementar semáforo duplo (cruzamento)
  4. 🔴 Adicionar comunicação serial para monitoramento/controle
  5. 🔴 Criar interface web com WiFi para mudar parâmetros

⚠️ Problemas Comuns e Soluções

GPIO não funciona

Sintoma: Pino não responde ou sempre em LOW/HIGH

Soluções:

PWM não gera sinal

Sintoma: LED não varia brilho ou buzzer não emite som

Soluções:

ADC retorna valores estranhos

Sintoma: Leituras inconsistentes, sempre 4095 ou 0

Soluções:

Botão detecta múltiplos cliques

Sintoma: Um pressionamento conta como vários

Soluções:

Display 7seg mostra dígitos errados

Sintoma: Números aparecem incorretos ou fragmentados

Soluções:

Código compila mas ESP32 reinicia constantemente

Sintoma: Bootloop, mensagens de “panic” no serial

Soluções:

Serial não exibe nada

Sintoma: Monitor serial em branco

Soluções:


🔗 Próximos Passos

🎉 Parabéns por completar o Nível 1!

Você agora domina:

Pré-requisitos atendidos para Nível 2:

Próximo Nível: 🔼 [Nível 2 - Intermediário]

O que você vai aprender:

Recomendações antes de avançar:

  1. 📝 Revisar exercícios que tiveram dificuldade
  2. 🛠️ Experimentar com variações dos desafios
  3. 📚 Ler documentação oficial: ESP-IDF GPIO Guide
  4. 🔍 Explorar exemplos oficiais: ESP-IDF Examples

Recursos de Referência:


Última atualização: 15/01/2026