Skip to content
SPONSORS
Picture of Marco Mello
Marco Mello

Encoder Rotativo ​

Você já deve ter visto um encoder em botões de volume, menus de equipamentos ou painéis de controle. Ele permite transformar rotação em comandos digitais.

O que o encoder resolve? ​

Um potenciômetro informa posição absoluta.
O encoder informa movimento incremental:

  • girou para um lado → incrementa
  • girou para o outro → decrementa

Funcionamento ​

Encoder = botão que gira e gera passos digitais

O microcontrolador mantém uma variável interna:

text
posição = 0
horário   -> posição++
anti-horário -> posição--

Por que usamos dois sinais? ​

Com apenas um sinal não conseguimos detectar direção.
Por isso usamos dois canais:

  • Canal A
  • Canal B

Esses sinais são defasados (quadratura).

Sinais em quadratura ​

Sentido horário ​

text
Tempo →

A: _|‾|_|‾|_
B: __|‾|_|‾|

A muda primeiro → horário

Sentido anti-horário ​

text
Tempo →

A: __|‾|_|‾|
B: _|‾|_|‾|_

B muda primeiro → anti-horário

Sequência de estados ​

text
Horário:       00 -> 10 -> 11 -> 01 -> 00
Anti-horário:  00 -> 01 -> 11 -> 10 -> 00

👉 Regra prática:

Quem muda primeiro define a direção

Ligação com a Pico ​

  • A → GPIO
  • B → GPIO
  • BTN → GPIO com pull-up
  • GND → GND

Snippets ​

Códigos de exemplo para o uso do LCD.

Demo ​

c
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"

const int ENCODER_A_PIN = 21;
const int ENCODER_B_PIN = 20;
const int ENCODER_BTN_PIN = 19;

volatile int g_direction = 0;
volatile int g_position = 0;

void callback(uint gpio, uint32_t events) {

    if (gpio == ENCODER_A_PIN) {

        if (events == 0x4) {
            if (gpio_get(ENCODER_B_PIN) == 0) {
                g_direction = 1;
                g_position++;
            } else {
                g_direction = -1;
                g_position--;
            }
        }
        else if (events == 0x8) {
            if (gpio_get(ENCODER_B_PIN) == 1) {
                g_direction = 1;
                g_position++;
            } else {
                g_direction = -1;
                g_position--;
            }
        }
    }
}

int main() {
    stdio_init_all();

    gpio_init(ENCODER_A_PIN);
    gpio_set_dir(ENCODER_A_PIN, GPIO_IN);
    gpio_pull_up(ENCODER_A_PIN);
    gpio_set_irq_enabled_with_callback(
        ENCODER_A_PIN,
        GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL,
        true,
        &callback
    );

    gpio_init(ENCODER_B_PIN);
    gpio_set_dir(ENCODER_B_PIN, GPIO_IN);
    gpio_pull_up(ENCODER_B_PIN);

    while (true) {
        printf("Posicao: %d | Direcao: %s\n",
               g_position,
               (g_direction == 1) ? "horario" : "anti-horario");
        sleep_ms(100);
    }
}

Resumo ​

  • encoder mede movimento incremental
  • usa dois sinais em quadratura
  • direção depende da ordem das transições
  • interrupções são a melhor abordagem