Skip to Content

Como construir um comando IR universal e programável

Como construir um comando IR universal e programável

Neste artigo do blog, vais aprender a construir um comando universal programável por infravermelhos (IR) usando Arduino. Um comando por infravermelhos é um dispositivo comum usado para controlar vários aparelhos eletrónicos, como TVs, ar-condicionados e leitores de DVD. Com a ajuda do Arduino, podemos criar o nosso próprio comando IR que pode ser programado para controlar múltiplos dispositivos e unificar vários comandos num só.

No final deste tutorial, saberás como usar recetores e transmissores infravermelhos, e como armazenar dados na EEPROM não volátil. Terás também o protótipo de um comando IR programável que podes modificar ou expandir ao teu gosto. Ele permitirá que copies as funções das teclas dos teus comandos IR existentes para TV, ventoinha, etc., para o comando IR que estamos a construir aqui.

Então, vamos começar e mergulhar no emocionante mundo do Arduino e do controlo por comando IR!

Componentes Necessários

Abaixo encontras os componentes necessários para construir o comando IR programável. Também vais precisar de um comando IR, caso ainda não tenhas um.

Arduino Uno

Dupont wire set

Conjunto de fios Dupont

Half_breadboard56a

Breadboard

USB Data Sync cable Arduino

Cabo USB para Arduino UNO

Kit de resistores e LEDs

Recetor e transmissor IR

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Ligação das Peças

Nesta secção vou mostrar-te como ligar os componentes ao Arduino. A imagem abaixo mostra a ligação completa. Começamos por ligar a fonte de alimentação à breadboard.

Wiring diagram of a universal, programmable IR remote with an Arduino
Ligação das peças ao Arduino

Fonte de alimentação

Liga um fio azul do pino GND do Arduino à linha negativa de alimentação da breadboard (marcada com uma linha azul). Depois liga o pino 5V do Arduino à linha positiva de alimentação (marcada com uma linha vermelha) com um fio vermelho.

Connecting power supply for the Arduino
Ligação da Fonte de Alimentação
Connecting power supply  to the breadboar

Além disso, liga ambas as linhas positivas da breadboard com outro fio vermelho. Isto garante que temos alimentação positiva em ambas as linhas.

Connecting power supply across both rails
Ponte para as linhas de alimentação

Módulo Recetor IR

De seguida, vou mostrar-te como ligar o recetor IR. Ele recebe os sinais infravermelhos emitidos por um comando IR e envia esses sinais para o Arduino, onde são decodificados.

Liga um fio azul e um vermelho do recetor às respetivas linhas de alimentação da breadboard. O lado negativo é geralmente marcado com o sinal (-) no recetor, enquanto o pino do meio tende a ser o positivo. Depois, liga o pino de sinal (S) do recetor ao pino 2 do Arduino; mostrado abaixo com um fio roxo.

Connecting IR Receiver Module
Ligação do Módulo Recetor IR

Depois de ligar o recetor, vamos ligar o módulo transmissor.

Módulo Transmissor IR

O transmissor IR é o módulo com o LED IR branco/transparente. Este módulo emite os sinais infravermelhos usados para controlar dispositivos.

Novamente, começamos por ligar a alimentação (fio vermelho e azul). Depois ligamos o pino de sinal (S) do transmissor ao pino 3 do Arduino usando um fio branco.

Connecting IR Transmitter Module
Ligação do Módulo Transmissor IR

Como o nosso comando IR será programável, precisamos de um LED de estado. Ele indica se estamos em modo de programação ou em modo de envio. Abaixo está a descrição de como ligar o LED de estado.

LED de Estado

Coloca um LED vermelho na breadboard e liga o cátodo (o pino mais curto) do LED com um fio azul à linha negativa de alimentação da breadboard. Depois liga um 330 resistor Ohm ao ânodo do LED (o pino mais longo). Finalmente, liga o resistor com um fio laranja ao pino 11 do Arduino.

Connecting Status LED
Ligação do LED de Estado

Botões

Por fim, precisamos de três botões. Um botão para alternar entre o modo de programação e o modo normal do comando IR. E dois outros botões para duas funções diferentes do comando. Por exemplo, aumentar e diminuir o volume.

Como podes ver abaixo, os três botões estão ligados da mesma forma. Um resistor de 10K Ohm serve como pull-up resistor e está ligado à linha positiva de alimentação. O pino do outro lado do botão está ligado a um pino de entrada do Arduino (mais sobre isso abaixo). O outro pino está ligado com um fio azul à linha negativa de alimentação da breadboard.

Connecting buttons of the programmable IR remote
Ligação dos botões e resistores pull-up

No estado normal, aberto, do botão, a entrada está ligada a 5V através do resistor e vamos ler um sinal HIGH. No entanto, se pressionares um botão, a linha de entrada liga-se ao terra e vamos ler um sinal LOW na entrada.

O botão superior/primeiro será o nosso botão de mudança de modo. Liga-o com um fio amarelo ao pino 4 do Arduino. O botão abaixo será para a primeira função. Liga-o ao pino 5 (fio ciano). E o último botão é para a segunda função e ligamos com um fio verde ao pino 6.

Connecting Buttons
Ligação dos botões aos pinos

É tudo. Está tudo ligado – esperamos que corretamente. Na próxima secção vamos olhar para o software.

Escrevendo o Software

Primeiro mostro-te o código completo e depois vamos analisar as partes individuais para entender como funciona. Dá uma vista rápida para teres uma visão geral.

#include "EEPROM.h"
#include "IRremote.hpp"
#include "TinyIRSender.hpp"

const uint8_t irReceivePin = 2;
const uint8_t irSendPin = 3;
const uint8_t modePin = 4;
const uint8_t func1Pin = 5;
const uint8_t func2Pin = 6;
const uint8_t ledPin = 11;
const uint8_t sRepeats = 2;

uint8_t modeReceive = HIGH;

struct Code {
  uint16_t adr;
  uint16_t cmd;
} code;

bool isOn(int btn) {
  return btn == LOW;
}

bool pressed(int pin) {
  return isOn(digitalRead(pin));
}

int memadr(int btnId) {
  return (btnId - 1) * sizeof(Code);
}

void store_code(int btnId, IRData &irData) {
  digitalWrite(ledPin, LOW);
  code = { irData.address, irData.command };
  EEPROM.put(memadr(btnId), code);
  delay(200);
  digitalWrite(ledPin, HIGH);
}

void send_code(int btnId) {
  digitalWrite(ledPin, HIGH);
  EEPROM.get(memadr(btnId), code);
  sendNECMinimal(irSendPin, code.adr, code.cmd, sRepeats);
  delay(200);
  digitalWrite(ledPin, LOW);
}

void toggle_mode() {
  modeReceive = modeReceive == LOW ? HIGH : LOW;
  digitalWrite(ledPin, isOn(modeReceive) ? HIGH : LOW);
  isOn(modeReceive) ? IrReceiver.start() : IrReceiver.stop();
  delay(200);
}

void send() {
  if (pressed(func1Pin)) {
    send_code(1);
  } else if (pressed(func2Pin)) {
    send_code(2);
  }
}

void receive() {
  if (IrReceiver.decode()) {
    IRData &irData = IrReceiver.decodedIRData;
    IrReceiver.printIRResultShort(&Serial);
    if (pressed(func1Pin)) {
      store_code(1, irData);
    } else if (pressed(func2Pin)) {
      store_code(2, irData);
    }
    IrReceiver.resume();
  }
}

void setup() {
  Serial.begin(9600);
  IrReceiver.begin(irReceivePin, ENABLE_LED_FEEDBACK);
  pinMode(ledPin, OUTPUT);
  pinMode(modePin, INPUT);
  pinMode(func1Pin, INPUT);
  pinMode(func2Pin, INPUT);
  digitalWrite(ledPin, LOW);
}

void loop() {
  if (pressed(modePin)) toggle_mode();
  isOn(modeReceive) ? receive() : send();
  delay(100);
}

Bibliotecas incluídas

Para este projeto vais precisar de instalar as seguintes bibliotecas. EEPROM é usada para armazenar os códigos IR programados. A IRremote biblioteca é usada para decodificar os sinais IR que recebemos de um comando IR. E TinyIRSender faz parte da biblioteca IRremote e permite enviar sinais IR – embora limitado ao protocolo NEC protocol .

#include "EEPROM.h"
#include "IRremote.hpp"
#include "TinyIRSender.hpp"

Constantes

No bloco de código seguinte definimos quais os pinos do Arduino usados para cada componente. irReceivePin e irSendPin são os pinos ligados ao recetor e transmissor IR. modePin, func1Pin e func2Pin estão ligados aos botões. O LED de estado é controlado via o ledPin . E sRepeats define com que frequência um IR command é repetido durante o envio.

const uint8_t irReceivePin = 2;
const uint8_t irSendPin = 3;
const uint8_t modePin = 4;
const uint8_t func1Pin = 5;
const uint8_t func2Pin = 6;
const uint8_t ledPin = 11;
const uint8_t sRepeats = 2;

Estruturas de dados

Além das constantes, precisamos de uma variável para armazenar o modo atual (programação ou normal) do nosso comando IR. modeReceive é HIGH quando estamos em modo de programação, e LOW caso contrário.

uint8_t modeReceive = HIGH;

struct Code {
  uint16_t adr;
  uint16_t cmd;
} code;

A Code struct armazena o endereço ( adr ) e o comando ( cmd ) dos códigos IR que vamos receber, armazenar e enviar. Por exemplo, o meu comando IR envia o endereço 0x20 e o comando 0x17 quando a tecla VOL+ é pressionada.

Para mais detalhes, vê a documentação da IRremote lib ou consulta o nosso tutorial sobre How to use an IR receiver and remote with Arduino .

Funções auxiliares

Para manter o código simples e legível, implementamos algumas funções auxiliares. A função isOn() retorna True , se um botão está LOW , o que significa que está pressionado. Com a função pressed() lemos o estado de um pino de entrada e depois usamos isOn() para determinar se o botão ligado está pressionado.

bool isOn(int btn) {
  return btn == LOW;
}

bool pressed(int pin) {
  return isOn(digitalRead(pin));
}

Função de endereço de memória

Para armazenar os códigos IR recebidos na memória, precisamos de uma função que nos diga em que endereço guardar os dados. A função memadr() é usada para calcular em que endereço de memória na EEPROM armazenamos e lemos os códigos de comando IR.

int memadr(int btnId) {
  return (btnId - 1) * sizeof(Code);
}

Esta função recebe um btnId , que é 1 ou 2 (para função 1 ou 2) e calcula o endereço de memória. Vê a imagem seguinte para entender melhor a relação entre btnId , o tamanho de uma Code struct e o endereço de memória.

Memory layout
Layout da memória

Funções de código IR

Para o armazenamento e envio dos códigos IR, usamos duas funções. A função store_code() recebe um id de botão ( btnId ) e um bloco de dados ( irData ) de dados IR recebidos.

No primeiro passo, desligamos o LED de estado para indicar que estamos a armazenar dados.

void store_code(int btnId, IRData &irData) {
  digitalWrite(ledPin, LOW);
  code = { irData.address, irData.command };
  EEPROM.put(memadr(btnId), code);
  delay(200);
  digitalWrite(ledPin, HIGH);
}

Depois extraímos o endereço do código e o comando do bloco de dados e armazenamo-los numa struct Code . Escrevemos esta struct na EEPROM com put() , usando a função memadr() para calcular o endereço de memória.

Precisamos de armazenar os dados na EEPROM porque, caso contrário, sempre que a energia for desligada, o Arduino perde todos os dados armazenados. Com os dados na EEPROM, os comandos/teclas programados permanecem guardados, mesmo quando o Arduino está desligado.

Depois de armazenar os dados, esperamos 200ms. Isto evita armazenamentos repetidos desnecessários quando a tecla de programação permanece pressionada. Finalmente, ligamos novamente o LED de estado para indicar que a programação está completa.

O envio dos códigos funciona essencialmente ao contrário. Vê a função send_code() abaixo. Primeiro, ligamos o LED de estado para indicar que estamos a enviar. Depois get o código a enviar da EEPROM para o botão pressionado ( btnId ). A função sendNECMinimal() envia o endereço do código e o comando com o número dado de repetições ( sRepeats ).

void send_code(int btnId) {
  digitalWrite(ledPin, HIGH);
  EEPROM.get(memadr(btnId), code);
  sendNECMinimal(irSendPin, code.adr, code.cmd, sRepeats);
  delay(200);
  digitalWrite(ledPin, LOW);
}

Depois disso, esperamos novamente 200ms e desligamos o LED de estado para indicar que o envio está completo.

Funções principais

Agora temos todas as funções básicas para construir as funções principais. Começamos com uma função toggle_mode() que alterna o nosso comando entre o modo de programação/receção e o modo de envio. A primeira linha faz a alternância do modo. Na segunda linha, ligamos o LED de estado se estivermos em modo de programação. Se estivermos em modo normal, o LED de estado estará desligado.

void toggle_mode() {
  modeReceive = modeReceive == LOW ? HIGH : LOW;
  digitalWrite(ledPin, isOn(modeReceive) ? HIGH : LOW);
  isOn(modeReceive) ? IrReceiver.start() : IrReceiver.stop();
  delay(200);
}

Na terceira linha, ligamos ou desligamos o IrReceiver dependendo do modo. Se estivermos em modo de receção, o IrReceiver será iniciado, caso contrário será parado. Finalmente, temos o nosso atraso habitual de 200ms para lidar com pressões longas de botão.

A função send() abaixo usa send_code() para enviar os códigos IR armazenados para os botões 1 e 2. Ou seja, dependendo do botão pressionado, envia o código correspondente.

void send() {
  if (pressed(func1Pin)) {
    send_code(1);
  } else if (pressed(func2Pin)) {
    send_code(2);
  }
}

Finalmente, a última das funções principais é receive() . Nela recebemos os dados transmitidos de um comando IR e armazenamo-los para o botão 1 ou 2, dependendo de qual botão está atualmente pressionado. Para mais detalhes sobre como receber dados IR, vê o nosso tutorial: How to use an IR receiver and remote with Arduino .

void receive() {
  if (IrReceiver.decode()) {
    IRData &irData = IrReceiver.decodedIRData;
    IrReceiver.printIRResultShort(&Serial);
    if (pressed(func1Pin)) {
      store_code(1, irData);
    } else if (pressed(func2Pin)) {
      store_code(2, irData);
    }
    IrReceiver.resume();
  }
}

Função setup

Estamos quase a terminar! Faltam apenas duas funções muito simples para implementar. Na função setup() , estabelecemos a comunicação serial, inicializamos o IrReceiver e definimos os modos de IO para os pinos. Também garantimos que o LED de estado está desligado, o que indica que estamos em modo de envio no início.

void setup() {
  Serial.begin(9600);
  IrReceiver.begin(irReceivePin, ENABLE_LED_FEEDBACK);
  pinMode(ledPin, OUTPUT);
  pinMode(modePin, INPUT);
  pinMode(func1Pin, INPUT);
  pinMode(func2Pin, INPUT);
  digitalWrite(ledPin, LOW);
}

Função loop

Depois de todo o trabalho duro acima, o loop principal é agora muito simples. Observamos o botão de modo ligado ao modePin e, se estiver pressed , alternamos o modo. Depois verificamos se estamos em modo de receção via isOn(modeReceive) . Se for o caso, recebemos e potencialmente armazenamos dados IR. Caso contrário, enviamos dados.

void loop() {
  if (pressed(modePin)) toggle_mode();
  isOn(modeReceive) ? receive() : send();
  delay(100);
}

E é isso! Na próxima secção, vou explicar rapidamente como usar o comando que acabámos de construir.

Como Usar o Comando

Nesta secção, vou explicar como usar o comando. Temos três botões. O botão Mode é usado para alternar entre o modo de programação ou receção e o modo de envio. No início, o comando está em modo de envio e o LED de estado está desligado. Se pressionares brevemente o botão Mode, o comando muda para o modo de programação e o LED de estado acende.

The buttons on the programmable remote
Funções dos botões do comando IR

Programação

Para programar uma das duas teclas de função, deves apontar o teu outro comando IR para o díodo recetor e pressionar duas teclas em simultâneo. A tecla do outro comando que queres armazenar e a tecla de função do nosso comando universal. A imagem seguinte mostra como armazenaríamos a tecla Next Track como Função 1.

How to program the universal IR remote
Programar o comando IR

O LED de estado piscará brevemente para indicar que uma função foi armazenada e podes então soltar os botões.

Envio

Para enviar comandos IR, simplesmente pressiona o botão Mode (o LED de estado deve estar desligado) e pressiona uma das teclas de função que programaste. Novamente, o LED de estado piscará para indicar que o comando foi enviado.

Depuração

Alguns comandos IR não são suportados e não vais conseguir programá-los. Podes verificar isto ligando o monitor serial, mudando para o modo de programação (o LED de estado deve estar ligado) e verificando se a biblioteca IRremote consegue decodificar o sinal. A saída deve ser semelhante a esta:

Serial monitor output for IR signal
Saída do monitor serial para sinal IR

Aqui recebemos com sucesso um comando com o endereço 0x20 e o código de comando 0x8 .

Para depurar a funcionalidade de envio, um destes testadores de componentes será muito útil. Caso contrário, terás de recorrer a tentativa e erro para descobrir o que está errado.

Multifunction component tester

 Testador Multi-Funções

O testador de componentes acima pode decodificar sinais IR e um sinal recebido com sucesso aparece assim:

Decoded IR signal
Sinal IR decodificado

Conclusões

Neste tutorial, aprendeste a construir um comando universal programável por IR usando Arduino. Seguindo as instruções passo a passo, podes facilmente criar o teu próprio comando que pode operar uma vasta gama de dispositivos infravermelhos.

Começámos por discutir as peças necessárias para este projeto, que incluem uma placa Arduino, um módulo recetor IR e um módulo transmissor IR. Descrevemos as ligações entre estes componentes e fornecemos o código para os controlar. Além disso, explicámos como usar o comando para programar comandos IR de outros comandos.

Se tiveres mais perguntas ou precisares de orientação adicional, consulta a secção de Perguntas Frequentes ou explora os links fornecidos para mais recursos e inspiração.

Boas construções!

Perguntas Frequentes

Aqui estão algumas perguntas frequentes sobre a construção de um comando universal programável por IR com Arduino:

Posso ter mais botões de função?

Sim, basta replicar a ligação dos botões existentes para os novos botões e expandir o código. Especificamente, as funções receive() e send() precisam ser estendidas para lidar com os botões adicionais.

Como posso aumentar o alcance do comando IR?

Podes ligar LEDs IR adicionais a outros pinos de saída. Ou podes usar um LED IR com uma voltagem mais alta, mas isso requer um transistor ou MOSFET para controlar o sinal de entrada do LED. Aqui está um circuito de exemplo que usa uma bateria de 9V para alimentar um díodo transmissor IR:

Díodo IR controlado via MOSFET

Para mais detalhes e exemplos sobre MOSFETs, vê o nosso tutorial sobre Control Air-Conditioner via IR with ESP32 or ESP8266 e How To Control Fan using Arduino UNO .

Não funciona com o meu comando IR?

A biblioteca IrRemote é ótima, mas não suporta todos os protocolos de comunicação IR que existem. Especificamente, para envio, usamos TinyIRSender , que é limitado ao protocolo NEC, mas a biblioteca IrRemote suporta outros protocolos também. Se isso não for suficiente, vê a IRremoteESP8266 como possível alternativa.

Quero controlar o meu ar-condicionado com o comando IR?

Experimenta a biblioteca IRremoteESP8266 . Ela tem ótimo suporte para muitas unidades de ar-condicionado.

Posso usar qualquer placa Arduino para este projeto?

Sim, podes usar qualquer placa Arduino para este projeto, desde que possas ligar um recetor e transmissor infravermelhos e as bibliotecas necessárias sejam suportadas. Um ESP32, por exemplo, seria uma ótima alternativa ao Arduino.

Como sei quais códigos IR usar para os meus dispositivos?

Podes encontrar os códigos IR para os teus dispositivos pesquisando online ou consultando o manual do utilizador do dispositivo. Muitos fabricantes fornecem bases de dados de códigos IR que podem ser usados com bibliotecas Arduino. Alternativamente, podes usar um módulo recetor IR para capturar os códigos de um comando existente. Vê o nosso tutorial sobre How to use an IR receiver and remote with Arduino .

Posso controlar vários dispositivos com este comando IR?

Sim, podes controlar vários dispositivos com este comando IR. Programando diferentes códigos IR para cada dispositivo, podes alternar entre eles usando botões ou um sistema de menu no teu código Arduino. Nota, no entanto, que o código acima suporta apenas o protocolo NEC, mas felizmente a maioria dos comandos IR usa-o.

Posso adicionar funcionalidades adicionais ao comando IR?

Claro! A plataforma Arduino permite personalização ilimitada. Podes adicionar funcionalidades como um ecrã LCD retroiluminado, um encoder rotativo para navegação em menus, ou até integrá-lo com outros dispositivos inteligentes usando protocolos de comunicação sem fios como Wi-Fi ou Bluetooth.

Se tiveres mais perguntas ou precisares de ajuda adicional, não hesites em perguntar na secção de comentários abaixo.

Links

Abaixo alguns links úteis para explicações adicionais e construções alternativas.