Como utilizar um encoder rotativo com Arduino
Conhece o encoder rotativo? Por fora, ele é um componente muito parecido com um potenciômetro, mas internamente funciona de uma forma bem diferente, sendo um componente interessante para você utilizar com seus projetos para Arduino. Eu utilizei um módulo encoder KY-040 para criar um pequeno sistema de seleção com display LCD 20×4.
O encoder é um componente utilizado para conversão de movimentos rotativos (ou lineares) em impulsos elétricos de onda quadrada. Esse impulsos podem ser lidos por um microcontrolador (no nosso caso, vamos utilizar o Arduino), e geram uma quantidade exata de impulsos por volta.
O encoder que utilizamos tem rotação contínua, e também um botão (basta empurrar o eixo) que vamos usar para selecionar uma das opções do “menu” no display.
Ligando o encoder no Arduino
O primeiro circuito de testes utiliza somente o encoder. Vamos utilizar 3 pinos do Arduino para ligar o componente, sendo que os pinos analógicos A2 e A3 serão ligados nos pinos de medição, e o pino digital 7 no pino do botão, junto com um resistor pull-up.
Caso você esteja utilizando somente o encoder (sem o módulo, siga o esquema ligação abaixo:
Teste esse circuito carregando o programa abaixo, que utiliza a biblioteca RotaryEncoder(download). Baixe a biblioteca e coloque-a na pasta LIBRARIES da IDE do Arduino.
//Programa : Teste basico encoder Arduino //Autor : Arduino e Cia //Carrega a biblioteca do encoder #include <RotaryEncoder.h> //Pinos de ligacao do encoder RotaryEncoder encoder(A2, A3); //Variavel para o botao do encoder int valor = 0; int newPos = 0; void setup() { pinMode(7, INPUT); Serial.begin(9600); Serial.println("Gire o encoder...."); } void loop() { //Verifica se o botao do encoder foi pressionado valor = digitalRead(7); if (valor != 1) { Serial.println("Botao pressionado"); while (digitalRead(7) == 0) delay(10); } //Le as informacoes do encoder static int pos = 0; encoder.tick(); int newPos = encoder.getPosition(); //Se a posicao foi alterada, mostra o valor //no Serial Monitor if (pos != newPos) { Serial.print(newPos); Serial.println(); pos = newPos; } }
O programa aguarda que o usuário gire o encoder para a direita ou para a esquerda, atualizando o valor de um contador. Girando para a direita, o contador aumenta, e para a esqueda, o contador diminui. Caso o botão seja pressionado, uma mensagem também aparece no serial monitor:
Esse é um circuito bem simples que você pode usar para testar se o seu encoder está funcionando corretamente.
Sistema de menu com display LCD 20×4 e encoder rotativo
Neste segundo circuito, vamos manter as ligações do encoder que utilizamos anteriormente, e adicionar um display LCD 20×4 ao circuito. O potenciômetro é de 10K e serve para ajustar o contraste do display. O resistor utilizado como pull-up do botão do encoder é de 330 ohms.
No programa deste circuito, vamos primeiramente criar caracteres customizados para os números de 1 a 6 que forem selecionados (são os números “invertidos”). Conforme giramos o encoder, os números no display vão sendo substituídos por esses número invertidos.
No loop, testamos se o botão foi pressionado, e também limitamos as opções de seleção entre 1 e 6, através do comando encoder.setPosition(). O programa checa se o valor do encoder foi alterado e, em caso positivo, chama a rotina destaque_selecionado(), que atualiza os dados da tela.
//Programa : Menu com encoder e LCD 20x4 //Autor : Arduino e Cia //Carrega biblioteca LCD e encoder #include <LiquidCrystal.h> #include <RotaryEncoder.h> //Inicializa o LCD LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Pinos de ligacao do encoder RotaryEncoder encoder(A2, A3); int contador = 1; int contador_anterior = 1; int valor = 0; byte Bloco_Cheio[8] = {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111 }; byte Um_invertido[8] = {0b11011, 0b10011, 0b11011, 0b11011, 0b11011, 0b11011, 0b10001, 0b11111 }; byte Dois_invertido[8] = {0b10001, 0b01110, 0b11110, 0b11101, 0b11011, 0b10111, 0b00000, 0b11111 }; byte Tres_invertido[8] = {0b00000, 0b11101, 0b11011, 0b11101, 0b11110, 0b01110, 0b10001, 0b11111 }; byte Quatro_invertido[8] = {0b11101, 0b11001, 0b10101, 0b01101, 0b00000, 0b11101, 0b11101, 0b11111 }; byte Cinco_invertido[8] = {0b00000, 0b01111, 0b00001, 0b11110, 0b11110, 0b01110, 0b10001, 0b11111 }; byte Seis_invertido[8] = {0b11001, 0b10111, 0b01111, 0b00001, 0b01110, 0b01110, 0b10001, 0b11111 }; static int pos = 1; int newPos = 0; int selecionado = 0; void setup() { Serial.begin(9600); //Inicializa o botao do encoder no pino 7 pinMode(7, INPUT); //Define o LCD com 20 colunas e 4 linhas lcd.begin(20, 4); //Cria os caracteres customizados lcd.createChar(0, Bloco_Cheio); lcd.createChar(1, Um_invertido); lcd.createChar(2, Dois_invertido); lcd.createChar(3, Tres_invertido); lcd.createChar(4, Quatro_invertido); lcd.createChar(5, Cinco_invertido); lcd.createChar(6, Seis_invertido); //Informacoes iniciais lcd.setCursor(0, 0); lcd.print(" 1 2 3 4 5 6"); lcd.setCursor(1, 2); lcd.print("Valor atual: 0"); lcd.setCursor(1, 3); lcd.print("Selecionado: -"); } void loop() { //Verifica se o botao do encoder foi pressionado valor = digitalRead(7); Serial.println(valor); if (valor != 1) { Serial.println("Botao pressionado"); lcd.setCursor(14, 3); selecionado = newPos; lcd.print(selecionado); //while (digitalRead(7) == 1) // delay(10); } //Le as informacoes do encoder encoder.tick(); newPos = encoder.getPosition(); if (pos != newPos) { //Limite maximo menu if (newPos > 6) { encoder.setPosition(6); newPos = 6; } //Limite minimo menu if (newPos < 1) { encoder.setPosition(1); newPos = 1; } Serial.print("Posicao: "); Serial.println(newPos); //Atualiza o menu no display destaque_selecionado(newPos); pos = newPos; } } void destaque_selecionado(int conta) { //Define posicao inicial int posicao = (conta * 3) - 1; //Apaga selecao anterior if (conta > pos) { lcd.setCursor(posicao - 4, 0); lcd.print(" "); lcd.print(conta - 1); lcd.print(" "); } //Apaga selecao posterior if (conta < pos) { lcd.setCursor(posicao + 2, 0); lcd.print(" "); lcd.print(conta + 1); lcd.print(" "); } //Imprime blocos cheios lcd.setCursor(posicao - 1, 0); lcd.write((uint8_t)0); lcd.write((uint8_t)0); lcd.write((uint8_t)0); //imprime valor lcd.setCursor(posicao, 0); lcd.write((uint8_t)(conta)); //Imprime Opcao atual lcd.setCursor(14, 2); lcd.print(conta); }
Achou a explicação muito complicada ? Dê uma olhada no vídeo abaixo, que mostra esse circuito em funcionamento:
O programa atualiza os valores somente na tela, mas você pode modificar facilmente este programa para que ele acione portas do Arduino ou envie e receba dados de algum sensor.
Gostou? Use este encoder também com Raspberry Pi! Confira no post Como usar encoder rotativo com Raspberry Pi.
I just couldnt leave your website before letting you know that I really enjoyed the useful information you offer to your visitors… Will be back often to check up on new posts.
electronic display boards india
Hi !
I really appreciate your comments. You are always welcome. 🙂
Best regards !
Adilson
como consigo gravar esse programa na EEPROM, me seria muito util pois acabando a energia resetaria tudo comecando o encoder da posicao pode me ajudar ?
Oi Janderson,
Dê uma olhada neste post aqui sobre gravação de dados em memória Eprom no Arduino, creio que vc vai achar o que precisa:
https://www.arduinoecia.com.br/2015/03/gravar-dados-memoria-eeprom-arduino.html
Abraço!
Adilson
gostaria de adquirir alguns contadores de passagem para instalar em minhas lojas aqui em sp, como faço? obrigado
Boa noite,
Ok, por favor entre em contato utilizando o formulário de contato no lado direito da página. Conversamos por email.
Abraço!
Pensei que os encoders eram para controlar o giro de motores?
Bom dia Eduardo,
O encoder pode ter várias aplicações, inclusive controlar o giro de motores, o menu que eu criei é só um exemplo. 🙂
Abraço!
Qual o raio de rotação do encoder? Tipo, uma rotação (20 pulsos) equivale a quantos mm em linha reta?
Tudo depende o tipo do ecoder, os mais utilizados em automação variam entre 100 e 500 pulsos por volta (360 graus).
e possível saber posições com o encoder, tipo um leve giro de 10 graus e fazer a leitura, ou só funciona com voltas completas ? se sim, à algum material para ajudar ?
Bom dia,
Esse encoder que eu uso no post tem um número fixo de pontos, à medida que vc gira o eixo. Você pode dividir 360 pelo número de pontos (não sei exatamente quantos são), para descobrir quantos graus por ponto ele se desloca.
Abraço!
no me funciona
Obrigado pelo artigo! Foi muito útil para meu estudo.
Só pra agilizar a vida do pessoal, o resistor do exemplo é de 220 ohms.
Oi Luís,
Muito obrigado e valeu a dica.
Abraço!
Adilson
boa noite, gostaria de ter uma grande ajuda pois estou travado no meu projeto de tcc
preciso que quando inicializado o arduino o mesmo represente no display a palavra bem vindo
em seguida a seguinte frase
pressione ligar para iniciar
e preciso que quando pressionar outro botao reset escreva
seção encerrada
estou utilizando os seguintes codigos ate o momento.
//Programa: Contador com sensor indutivo e capasitivo
#include
#include
// Inicializa o display no endereco 0x27
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
//variaveis para ligar.
#define pinoligar 40
#define pinoledliga 42
//contagem total
int pino_total = 25;
int valor0 = 1; //Variavel leitura sensor indutivo
int contadortotal = 0;
// variáveis sensor indutivo.
int pino_indutivo = 22;
int valor1 = 1; //Variavel leitura sensor indutivo
int contadormetal = 0;
// variaveis sensor capacitivo
int pino_capacitivo = 24;
int valor2 = 1; //Variavel leitura sensor capacitivo
int contadorvidro = 0;
//variaveis sensor infra 2 plastico
int pino_plastico = 26;
int valor3 = 1; //Variavel leitura sensor infra 3
int contadorplastico = 0;
void setup()
{
//Define o pino do sensor indutivo como entrada
pinMode(pino_indutivo, INPUT);
//Define o pino do sensor capacitivo como entrada
pinMode(pino_capacitivo, INPUT);
//Inicializa o display LCD 20×4 I2C
lcd.begin (20, 4);
lcd.setCursor(5,1);
lcd.print("Bem vindo");
delay (3000);
lcd.clear();
//display lcd total
lcd.setCursor(0,3);
lcd.print("total");
lcd.setCursor(9,3);
lcd.print(contadortotal);
//display lcd plastico
lcd.setCursor(0,2);
lcd.print("plastico");
lcd.setCursor(9,2);
lcd.print(contadorplastico);
//display lcd metal
lcd.setCursor(0,0);
lcd.print("metal");
lcd.setCursor(9,0);
lcd.print(contadormetal);
// display lcd vidro
lcd.setCursor(0,1);
lcd.print("vidro");
lcd.setCursor(9,1);
lcd.print(contadorvidro);
}
void loop()
//logico sensor total
{
//Le o pino do sensor infra 1 total
valor1 = digitalRead(pino_total);
//Verifica se algum objeto foi detectado (valor0 = 0)
if (valor0 == 0)
{
//Incrementa o contador0 total
contadortotal++;
//Mostra o valor do contador1 no display
lcd.setCursor(9, 3);
lcd.print(contadortotal);
//Loop caso o objeto fique parado em frente ao sensor
while (digitalRead(pino_total) == 0)
{
delay(100);
}
}
//logico sensor plastico
{
//Le o pino do sensor infra 2
valor1 = digitalRead(pino_plastico);
//Verifica se algum objeto foi detectado (valor3 = 0)
if (valor3 == 0)
{
//Incrementa o contador3 total
contadorplastico++;
//Mostra o valor do contador1 no display
lcd.setCursor(9, 2);
lcd.print(contadorplastico);
//Loop caso o objeto fique parado em frente ao sensor
while (digitalRead(pino_plastico) == 0)
{
delay(100);
}
}
//logica sensor indutivo
{
//Le o pino do sensor indutivo
valor1 = digitalRead(pino_indutivo);
//Verifica se algum objeto foi detectado (valor1 = 0)
if (valor1 == 0)
{
//Incrementa o contador1 meetal
contadormetal++;
//Mostra o valor do contador1 no display
lcd.setCursor(9, 0);
lcd.print(contadormetal);
//Loop caso o objeto fique parado em frente ao sensor
while (digitalRead(pino_indutivo) == 0)
{
delay(100);
}
//logica sensor capacitivo
{
//Le o pino do sensor capacitivo
valor2 = digitalRead(pino_capacitivo);
//Verifica se algum objeto foi detectado (valor1 = 0)
if (valor2 == 0)
{
//Incrementa o contador1
contadorvidro++;
//Mostra o valor do contador1 no display
lcd.setCursor(9, 1);
lcd.print(contadorvidro);
//Loop caso o objeto fique parado em frente ao sensor
while (digitalRead(pino_capacitivo) == 0)
{
delay(100);
}
}
}
}
}
}
}
agradeço muito que puder me ajudar.
ola, tem como me mandar o codigo com o mesmo funcionamento do contador de encoder, mascom zeramento e valor de cada pulso?
desculpa achei muito interessante o programa porem preciso ler a posicao do encoder e mantela gravada caso falte energia a unica maneira seria com a EEPROM porem nao consigo alguem poderia me ajudar ou publicar um programa resolvendo essa questao ?
Qual o motivo de utilizar as entradas analógicas ao invés das digitais?
Não consigo instalar a biblioteca do encoder. Alguém pode me ajudar?
Oi, esta biblioteca esta dando error: “…libraries/RotaryEncoder/RotaryEncoder.cpp: In member function ‘RotaryEncoder::Direction RotaryEncoder::getDirection()’:
…libraries/RotaryEncoder/RotaryEncoder.cpp:62:36: error: ‘Direction’ is not a class or namespace”
Já baixei em outros sites e continua a dar erro!
o que pode ser?
Oi Benedito!
Qual versão da IDE do Arduino vc está usando? Acabei de baixar a biblioteca aqui (achei que ela pudesse estar desatualizada) e usei o programa do post. Compilou normalmente.
Estou usando a versão 1.8.13 da IDE.
Abraço!
Adilson
Oi, eu uso linux debian, instalei este ano ainda, e instalei pelo repositório deles, fui verificar o IDE e tem: 2:1.05+dfsg2-4.1, será que ta desatualizada? Eu baixei direto no site do Arduino e vou instalar pra ver se dar certo!
De já obrigado!
Benedito
Instalei e não deu mais erro! Agora queria saber se da pra usar as portas digitais? No exemplo só fala de portas analógicas!
Obg!
Oi Benedito,
Que bom que funcionou! Dá pra usar as portas digitais sim. 🙂
Abraço!
Adilson
Posso usar essa biblioteca com mais de um encoder
Oi Lorenzo,
Pode sim.
Abraço!
Adilson
Bom dia, teria como utilizar este encoder para limitar o sentido de giro?
No caso ele teria que contar uma determinada quantidade de voltas para o lado horário e acionar o rele de saída quando atingir o valor setado,, assim que inverter a rotação, desliga a saída e quando chegar na quantidade de voltas definidas no sentido anti-horário será acionada outra siada e assim por diante.
Oi Paulo,
É possível sim. Você pode fazer um tipo de contador e quando ele chegar no número que vc quer, ele faz alguma ação.
Abraço!
Adilson
Olá Adilson,
Este foi o primeiro projecto que fiz depois de descobrir o Arduino e Cia.
Tenho um pequeno senão com o programa e gostaria de entender. Para que mude o valor (para cima ou para baixo) eu tenho que dar sempre 2 impulsos no Rotary Encoder. A que se deve isso? Há forma de resolver, para que cada impulso tenha resposta imediata?
Obrigado.
Oi João!
Você está usando o mesmo modelo de encoder do post? Talvez seja alguma coisa com relação à quantidade de pulsos do encoder que você está usando.
Abraço!
Adilson