O módulo RF 433MHz é um dos componentes mais simples para a criação de uma comunicação sem fio. Portanto, neste post, veremos como utilizá-lo com e sem biblioteca utilizando o Arduino.


Informações importantes

O que é o módulo RF

O módulo RF consiste em um transmissor e um receptor de ondas eletromagnéticas de frequência de 433MHz. Isto é, são dois circuitos capazes de comunicar entre si sem a necessidade de fios, pois se comunicam utilizando ondas eletromagnéticas. A imagem abaixo mostra ambos.

Modulo RF transmissor e receptor
Transmissor na esquerda e receptor na direita

O transmissor possui um circuito relativamente simples. Isso porque o circuito é basicamente uma chave ligada a um gerador de onda de 433MHz. Quando a chave é ativada, o sinal de 433MHz sai na antena do módulo e é capaz de chegar ao receptor.

Já o receptor é mais complexo. Seu circuito possui uma antena para receber a onda de 433MHz e um circuito para filtrar ruídos e amplificar o sinal de interesse. Além disto, ele possui uma malha de captura de fase para sincronizar o sinal de saída.

Mais adiante, veremos como estes circuitos podem ser utilizados.

Pinos

A maioria dos pinos já vêm indicados, mas suas características podem não ser muito óbvias. Sendo assim, vamos analisar os pinos do modulo RF receptor e do transmissor.

Começando com o transmissor:

Transmissor RF pinos
  1. DATA. É por meio deste pino que os dados serão enviados para o receptor.
  2. Vcc. Pino de alimentação que suporta de 3.5-12V. Quanto maior for a tensão utilizada, maior será a distância que o modulo será capaz de transmitir a informação.
  3. GND. Terra da alimentação.
  4. Terminal para soldar uma antena.

Passando para o receptor:

Receptor RF pinos
  1. Vcc. Pino de alimentação que deve ser ligado em 5V ou em 3.3V (adiante veremos a diferença entre as duas tensões).
  2. DATA. É por meio deste pino que os dados serão recebidos do transmissor.
  3. DATA. Possui a mesma função do pino anterior. Portanto, tanto o pino 2 quanto o 3 poderão ser usados para receber os dados.
  4. GND. Terra da alimentação.
  5. Terminal para soldar uma antena

Antena

A utilização da antena é extremamente importante, pois ela garante que o alcance da comunicação aumente significativamente. Tanto é que, se você não utilizar uma antena, o alcance do transmissor será de apenas alguns metros.

E, conforme dito anteriormente, o alcance depende também da tensão de alimentação do transmissor. Sendo assim, se você deseja um alcance máximo, basta alimentar o transmissor com 12V e utilizar uma antena. E o alcance pode chegar a mais de 30 metros em uma área aberta.

Entretanto, o termo “antena” pode ser um pouco vago. Um modelo bem simples de antena que você pode utilizar é um fio enrolado. E o seu comprimento deve ser cerca de 17,3cm. Portanto, enrole dois fios de 17,3cm e solde um em cada terminal de antena dos módulos receptor e transmissor.

O cálculo anterior é feito considerando a quarta parte do comprimento de onda (λ) da onda de 433Mhz (considerando ela viajando no vácuo):

\frac{\lambda}{4} = \frac{\frac{c}{f}}{4} = \frac{\frac{3*10^8}{433M}}{4} = 0.17m


Formas de utilizar o módulo RF

Existem diferentes formas de se utilizar o modulo RF, embora o princípio de funcionamento delas seja o mesmo. Primeiro veremos como enviar um simples bit (0 ou 1) entre dois Arduinos.

Em seguida, veremos como transmitir vários bits (uma informação) de forma simples sem utilizar bibliotecas. Por fim, veremos a mesma coisa anterior, porém utilizando bibliotecas.

Uma outra maneira de utilizar o modulo RF é com o encoder e o decoder HT12E e o HT12D. Entretanto, não pretendo explicá-los neste post. Eles facilitam a comunicação, pois eliminam a necessidade de um microcontrolador no circuito todo. Porém, eles permitem o envio de 4 bits apenas.


Transmitindo um bit

Vamos imaginar que nossa aplicação seja apenas acender um LED que esteja no circuito do receptor. Para isto, iremos enviar no transmissor apenas nível alto ou nível baixo para acender ou apagar o LED.

Circuito

A ligação será feita conforme foi descrito no tópico sobre os pinos. Lembrando que utilizarei dois Arduinos para testar os módulos.

Transmissor (Arduino 1):

  • Vcc- 5V do Arduino 1.
  • GND – GND do Arduino 1.
  • Data – Pino 3 do Arduino 1.

Receptor (Arduino 2):

  • Vcc – 3.3V do Arduino 2.
  • GND – GND do Arduino 2.
  • Data (qualquer DATA) – pino 3 do Arduino 2.

Utilizei o pino 3 nos dois casos sem motivo aparente, pois qualquer pino digital serviria.

Código transmissor

A ideia do código do transmissor é acionar o pino DATA por 3 segundos e depois deixá-lo em nível baixo por 3 segundos. Adicionei também o pino 13 (pino do LED da placa) para enxergar o melhor o que está acontecendo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Pino do transmissor
#define TX 3

void setup() {
  pinMode(TX, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() {
  // Coloca o pino TX em alta a cada x segundos
  digitalWrite(TX, HIGH);
  digitalWrite(13, HIGH);
  delay(3000);
  digitalWrite(TX, LOW);
  digitalWrite(13, LOW);
  delay(3000);
}

Código receptor

O código do receptor fica lendo o estado do pino do receptor e escreve ele no Serial. E, se o valor for nível lógico alto, o código liga o LED do pino 13 e desliga caso contrário.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Pino do receptor
#define RX 3

void setup() {
  Serial.begin(9600);
 
  pinMode(RX, INPUT);
  pinMode(13, OUTPUT); // Define o pino 13 como saída (LED)
}

void loop() {
  // Se o pino RX ficou em alta
  if(digitalRead(RX)){
    digitalWrite(13, HIGH);
  }else{
    digitalWrite(13, LOW);
  }

  // Printa o valor de RX e da um pequeno delay entre cada medição
  Serial.println(digitalRead(RX));
  delay(50);
}

Resultados

Após realizar as ligações e fazer upload dos códigos em cada Arduino, o resultado recebido foi o seguinte:

Plotter serial 3.3v leitura sem ruidos

De certa forma, foi dentro do esperado, apesar do último pulso ter tido uma largura diferente do padrão anterior. O curioso nesta parte é que, quando o transmissor envia um nível alto, o receptor recebe um nível baixo e vice-versa.

Portanto, a lógica está trocada. E, se quisermos acionar um LED com um pulso de nível lógico alto do transmissor, bastaria verificar se o receptor detectou um nível lógico baixo.

Obs: o receptor normalmente nao fica em nível alto todo o tempo em que o transmissor manda o sinal de nível baixo. Este sensor serve mais para detectar pequenos pulsos.

Problema de alimentar o receptor com 5V

Agora, o mais importante é entender porquê alimentei o receptor com 3.3V e não 5V, que é a tensão de operação comum dele. Acontece que, quando alimentamos ele com 5V, o sinal recebido fica como o mostrado abaixo:

Plotter serial 5v leitura sinal com ruidos

A imagem acima foi resultado do mesmo código de antes. Portanto, é perceptível que alimentar o receptor com 5V gera bastante ruído no sinal recebido.

É possível perceber alguns momentos onde o sinal fica mais tempo em baixa ou mais tempo em alta. Possivelmente são os momentos em que o transmissor envia algum pulso. Entretanto, fica difícil trabalhar com este sinal sendo que o objetivo é acionar um simples LED.

Sendo assim, basta alimentar de volta o modulo receptor com 3.3V.


Transmitindo uma informação – Sem biblioteca

Vamos imaginar que nossa aplicação agora seja enviar uma mensagem, como uma frase. A forma mais fácil de fazer isto é utilizar a comunicação serial do próprio Arduino.

Por ela, nós iremos enviar um conjunto de bits que formam uma mensagem para, no fim, termos uma frase. No fim das contas, o processo é o mesmo que enviar um bit, porém agora estaremos enviando vários bits em sequência.

Circuito

A ligação é parecida com a anterior, com a diferença sendo a ligação do pino DATA do receptor e do transmissor.

Transmissor (Arduino 1):

  • Vcc- 5V do Arduino 1.
  • GND – GND do Arduino 1.
  • Data – Pino TX (digital 1) do Arduino 1.

Receptor (Arduino 2):

  • Vcc – 3.3V do Arduino 2.
  • GND – GND do Arduino 2.
  • Data (qualquer DATA) – pino RX (digital 0) do Arduino 2.

Código transmissor

A ideia do código é apenas escrever uma frase para ser enviada via comunicação serial. Um detalhe importante é a velocidade máxima que o módulo RX pode trabalhar, que é em torno de 2000 baud. Portanto, criarei uma comunicação serial com uma velocidade de 1200 baud.

Além disto, no fim da mensagem, enviarei o caractere # que será o indicador de fim de mensagem.

1
2
3
4
5
6
7
8
9
10
11
void setup()  
{
  Serial.begin(1200); // Cria a comunicação serial (<2000 baud)
}

void loop()
{
   Serial.write("Mundo Projetado#");
   Serial.flush(); // Aguarda a mensagem ser enviada
   delay(5000);
}

Código receptor

O código do receptor ficará apenas “ouvindo” o barramento serial do Arduino e armazenando os dados que chegarem. E, caso chegue o caractere “#”, a mensagem é recebida por completo e ele escreve ela no monitor serial.

Vale ressaltar que o receptor deve possuir uma comunicação serial com a mesma velocidade do transmissor para não haver incompatibilidade de comunicação.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
String buf = "";

void setup()
{
  Serial.begin(1200);
}

void loop()
{
  // Caso tenha algum dado sendo recebido
  if (Serial.available()) {
    char a = Serial.read();
   
    // Verifica se o dado recebido é o caractere #
    if(a == '#'){ // Se sim, printa a mensagem recebida
      Serial.println(buf);
      buf = "";
    }else{ // Senão, apenas adiciona ele à mensagem
      buf += a;
    }
  }
}

Resultados

As mensagens recebidas vieram com bastante ruído e muitos caracteres extras. Tentei diminuir o mau contato da protoboard mudando os sensores de posição e consegui transmitir e receber as mensagem sem ruído. Entretanto, não deixou de ser algo instável.

A imagem abaixo mostra como ficou minha ligação.

Modulo RF comunicação serial

Acabei decidindo visualizar o sinal do receptor utilizando um osciloscópio. Sendo assim, liguei o canal 1 do osciloscópio no pino DATA do receptor e o referencial no GND. A imagem abaixo mostra o sinal recebido:

Receptor com comunicação serial e osciloscópio

O sinal não faz muito sentido em relação ao que está sendo enviado, pois parece que é apenas uma onda quadrada. Mas ele se refere apenas a um pedaço do sinal. De qualquer forma, dá para ver que o modulo receptor está recebendo as variações dos bits.

Por fim, uma última observação importante: testei o circuito tanto com 5V, quanto com 3.3V e os dois níveis de tensão funcionaram corretamente, apesar dos caracteres extras.


Transmitindo uma informação – Com biblioteca

A ideia aqui é a mesma do tópico anterior com a diferença que a comunicação será feita por meio de uma biblioteca. A biblioteca comumente utilizada considerando a data do post é a RadioHead. Ela pode ser baixada aqui e sua página de referência é esta.

A vantagem de utilizar a biblioteca é que ela é à prova de ruídos, pois possui um código de verificação de erros robusto. Sendo assim, a mensagem recebida é limpa e livre de erros, porque, se houver um, a mensagem é desconsiderada.

Circuito

A biblioteca, por padrão, utiliza os pinos 11 e 12 do módulo RF. Entretanto, é possível alterá-los editando os arquivos da biblioteca. Enfim, abaixo está mostrada a ligação padrão dos módulos:

Transmissor (Arduino 1):

  • Vcc- 5V do Arduino 1.
  • GND – GND do Arduino 1.
  • Data – Pino 12 do Arduino 1.

Receptor (Arduino 2):

  • Vcc – 5V do Arduino 2.
  • GND – GND do Arduino 2.
  • Data (qualquer DATA) – pino 11 do Arduino 2.

Consegui fazer o modulo funcionar com o receptor alimentado tanto em 5V quanto em 3.3V. Embora o recomendável seja alimentá-lo com 5V.

Código transmissor

Leia os comentários para entender como utilizar os comandos da biblioteca. O código do transmissor fica enviando a mensagem “Mundo Projetado” a cada 3 segundos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Inclui as bibliotecas base
#include <RH_ASK.h>
#include <SPI.h>

// Instancia o objeto da comunicação
RH_ASK rf_driver;

void setup()
{
  // Inicia a comunicação
  rf_driver.init();
}

void loop()
{
  const char *msg = "Mundo Projetado"; // Cria a mensagem
  // Envia a mensagem e aguarda terminar de ser enviada
  rf_driver.send((uint8_t *)msg, strlen(msg));
  rf_driver.waitPacketSent();
  delay(3000); // Delay entre mensagens
}

Código receptor

Leia os comentários para entender como utilizar os comandos da biblioteca. O código do receptor fica aguardando a mensagem ser recebida, sendo que ele tem noção do tamanho da mensagem que está por vir. E, se a mensagem for recebida corretamente, ele mostra no monitor serial.

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
// Inclui as bibliotecas base
#include <RH_ASK.h>
#include <SPI.h>

// Instancia o objeto da comunicação
RH_ASK rf_driver;

void setup()
{
  // Inicia a comunicação
  rf_driver.init();
  Serial.begin(9600);
}

void loop()
{
  // Cria o buffer do tamanho da mensagem esperada
  uint8_t buf[11];
  uint8_t buflen = sizeof(buf);
  // Verifica se o pacote recebido possui o tamanho certo
  if (rf_driver.recv(buf, &buflen)){
    // Se sim, a mensagem foi recebida corretamente
    Serial.println((char*)buf);
  }
}

Resultados

A mensagem foi recebida diversas vezes sem problemas. O único porém foi alguns caracteres que foram printados no fim da frase recebida, embora eles de fato não tenham sido recebidos na mensagem. Portanto, é algo que pode ser facilmente resolvido.

Considerando o que foi exposto, se você não vê problemas em utilizar bibliotecas, eu recomendo bastante utilizar a RadioHead.

Isso porque ela previne muitos ruídos e erros de comunicação entre o transmissor e o receptor. Principalmente se houver algum dispositivo eletrônico que também trabalhe na faixa de frequência de 433MHz, já que ele irá influenciar no sinal do modulo RF.