O módulo nRF24L01 é útil em aplicações de transmissão sem fio e ele poderoso e de baixo custo. Portanto, vamos aprender as características do nRF24L01 e como utilizá-lo com o Arduino por meio de bibliotecas.

Informações básicas

O que é

O nRF24L01 é um pequeno CI que pode transmitir e receber dados sem fio (RF). Atualmente já existem versões mais recentes do CI que possuem bem mais recursos. Entretanto, o modulo que utiliza o nRF24L01 é o mais fácil de encontrar pra comprar (e também o mais barato) até a data deste post (dezembro 2019). Veja como é o módulo na imagem abaixo.

Modulo nRF24L01

O nRF24L01 na realidade é o pequeno CI no centro da imagem acima. Entretanto, o módulo que o utiliza também é comumente chamado de nRF24L01. Este módulo basicamente faz pequenas conexões do CI com alguns capacitores, resistores e com um cristal de 16MHz. Desta forma, sua ligação com um microcontrolador ou um Arduino fica simplificada.

Aplicações

As aplicações do nRF24L01 são, de modo geral, em sistemas que se comunicam sem fio. Exemplo de possíveis aplicações: chave eletrônica, sensores remotos, brinquedos, periféricos de PC (teclado, mouse) etc…

Eu cheguei a implementar ele em um projeto da faculdade para fazer um sistema de chave eletrônica (de um veículo). A ideia funcionou bem, o que ficou ruim foi o consumo de corrente relativamente alto dele. Portanto, conforme veremos nas características abaixo, ele não é recomendado em aplicações em que o consumo seja algo crítico (onde o consumo desejado esteja na faixa dos μA).

Características

As características podem ser lidas no datasheet do CI.

A seguir estão listadas algumas características do nRF24L01. Ele permite que você configure alguns aspectos da comunicação:

  • Frequência de operação: 2.4GHz a 2.525GHz (não é configurável).
  • 126 canais de comunicação.
  • Tamanho máximo do pacote enviado/recebido: 32 bytes.
  • Endereço do transmissor/receptor (espécie de ID único):
    • Pode ter 3, 4 ou 5 bytes.
  • Velocidade de comunicação:
    • 1Mbps
    • 2Mbps
  • Potências do transmissor:
    • 0 dBm
    • -6 dBm
    • -12 dBm
    • -18 dBm
  • Sensibilidade do receptor (não é configurável diretamente):
    • -82 dBm (a 2Mbps)
    • -85 dBm (a 1Mbps)
  • Consumo de corrente na transmissão (não é configurável diretamente):
    • 11.3 mA (com transmissor em 0 dBm)
    • 7 mA (com transmissor em -18 dBm)
  • Consumo de corrente na recepção (não é configurável diretamente):
    • 12.3 mA (a 2 Mbps)
    • 11.8 mA (a 1 Mbps)
  • Alcance: cerca de 100m (algumas ressalvas serão feitas nos tópicos adiante).

Dentre as várias opções mostradas acima, cabe a você decidir qual utilizar dependendo da sua aplicação. Vou fazer alguns comentários para ajudar a entender estas escolhas. Então, não se preocupe se você não sabe o que dBm representa.

Se você ficar em dúvida sobre qual utilizar, recomendo trabalhar utilizando a menor quantidade de recursos possíveis: menor velocidade (1 Mbps) e menor potência (-18 dBm) para evitar gastos desnecessários.

Velocidade de comunicação

Esta opção não é difícil de entender do que se trata. Mas ainda assim cabe um comentário:

Se sua aplicação não necessita de altas taxas de transmissão/recepção, você pode utilizar 1Mbps para reduzir o consumo de corrente na recepção e melhorar a sensibilidade.

A sensibilidade indica o menor nível de potência que o receptor é capaz de reconhecer como sinal útil. Portanto, quanto menor, melhor. Por isto, a menor velocidade faz com que a sensibilidade melhore (reduz de -82 dBm para -85 dBm).

Alcance (Potência do transmissor)

O alcance da comunicação é bastante variável, pois depende dos parâmetros configurados e do ambiente em que você irá utilizar o nRF24L01.

Como a frequência de operação está na faixa dos GHz, obstáculos como paredes, móveis e pessoas podem ocasionar uma perda significativa do sinal enviado. É o mesmo problema do wi-fi (opera em frequência próxima).

Se você utilizar a máxima potência de transmissão (0 dBm) e a menor velocidade (1 Mbps), o alcance pode chegar a 100m em espaço aberto.

De todo modo, o alcance pode ser aumentado até cerca de 1Km em área aberta se você utilizar uma antena apropriada. O módulo da imagem que mostrei anteriormente já possui uma antena embutida na PCB (antena microstrip). Entretanto, é possível encontrar módulos em que existe um conector para antena como o da imagem abaixo:

Fonte: Wikipedia

126 canais de comunicação

O nRF24L01 é capaz de trabalhar em até 126 canais de frequências diferentes. Entretanto, ele só pode operar em uma frequência por vez. Com isto, você pode ter uma rede de dispositivos comunicando de forma cruzada sem um interferir com o outro (já que as frequências serão diferentes).

Além disto, o nRF24L01 possui uma estrutura interna contendo 6 “data pipes”. Cada “data pipe” pode ter um endereço (ID) de recebimento separado. Ou seja, um mesmo dispositivo pode ser configurado para ouvir outros 6 dispositivos (1 endereço em cada data pipe) considerando que estejam todos na mesma frequência.

Entretanto, não é possível definir mais de 1 endereço de transmissor por dispositivo. Portanto, a ideia desta estrutura, é que existam diversos dispositivos (6) que se comunicam com um dispositivo central que processa os dados de todos os 6.

Veja a estrutura dos “data pipes” abaixo:

Fonte: Datasheet do nRF24L01

Pinos

Para explicar os pinos, utilizaremos a imagem abaixo como referência.

Pinos do nRF24L01

O nRF24L01 se comunica via SPI. Sendo assim, é de se esperar que existam os 4 pinos padrões desta comunicação (MOSI, MISO, SCLK, SS ou CS). Além disto, existem outros pinos. Vejamos:

  • MISO, MOSI, SCLK, CSN (chip select): são os pinos da comunicação SPI.
  • Vcc e GND são os pinos de alimentação.
    • A alimentação pode ir de 1.9 a 3.6V
  • CE (chip enable): este pino tem a capacidade de habilitar/desabilitar o CI (funcionar normalmente ou entrar no modo de standby I).
  • IRQ: pino de interrupção.
    • Vai para nível baixo quando o CI termina de enviar um pacote ou quando ele recebe algum pacote.

Utilizar o nRF24L01 SEM BIBLIOTECA

O objetivo deste post é ensinar a utilizar o modulo com uma biblioteca. Mas se você desejar desenvolver sua própria biblioteca para utilizar em outra plataforma (outro microcontrolador), o processo não será difícil, e sim trabalhoso.

Conforme falei anteriormente, utilizei ele em um projeto da faculdade, e precisei desenvolver uma biblioteca, pois a plataforma da aplicação não era o Arduino. O meu primeiro passo foi desenvolver a biblioteca em C ainda na plataforma do Arduino para facilitar o desenvolvimento e os testes. Só depois deste passo que adequei o código para a outra plataforma.

Bem, se você desejar dar uma olhada no código, entre neste link. E, se você também precisa desenvolver uma biblioteca, precisará dar uma boa lida no datasheet do nRF24L01.

Utilizando o nRF24L01 com o Arduino

Biblioteca utilizada

A biblioteca utilizada foi a RF24: baixe ela aqui.

Circuito

Nos exemplos que mostrarei, não faremos uso do pino de interrupção. Portanto, ele ficará desconectado. Os demais pinos são ligados conforme a imagem abaixo:

Circuito nRF24L01

O Vcc é ligado ao 3.3V do Arduino e o GND ao GND. Os pinos da comunicação SPI são ligados do pino 11 ao 13 do Arduino (MOSI,MISO e SCK respectivamente). 

Por fim, os pinos CE e CSN podem ser ligados em qualquer pino digital do Arduino. Por padrão da biblioteca, resolvi ligá-los nos pinos 7 e 8 respectivamente.

Código do modulo como transmissor

Para utilizar o nRF24L01 com a biblioteca é bem simples. Veja o código abaixo e leia os comentários para entender.

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
#include <SPI.h>
#include <RF24.h>

RF24 radio(7, 8); // Pinos CE e CSN

const byte endereco[6] = "teste";

void setup() {
  // Inicializa a comunicação com o modulo
  radio.begin();

  // Define o endereço do transmissor
  radio.openWritingPipe(endereco);

  // Prepara para o modo de envio
  radio.stopListening();
}

void loop() {
  const char text[] = "Mundo projetado";

  // Envia o texto "Mundo projetado"
  radio.write(&text, sizeof(text));
 
  delay(1000);
}

Código do modulo como receptor

Veja o código abaixo e leia os comentários para entender.

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
#include <SPI.h>
#include <RF24.h>

RF24 radio(7, 8); // Pinos CE e CSN

const byte endereco[6] = "teste";

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

  // Inicia a comunicação com o modulo
  radio.begin();

  // Define o endereço do receptor (data pipe 0)
  radio.openReadingPipe(0, endereco);

  // Entra no modo de recebimento
  radio.startListening();
}

void loop() {
  // Verifica constantemente se recebeu algum pacote
  if (radio.available()) {
    char recebido[32] = "";

    // Se sim, lê o conteudo na variável recebido
    radio.read(&recebido, sizeof(recebido));

    // Imprime o que foi recebido
    Serial.println(recebido);
  }
}

Uma coisa interessante de se reparar aqui é que o comando para definir o endereço do receptor aceita dois parâmetros: o primeiro define qual “data pipe” será alterado (0 a 5) e o segundo é o endereço desejado:

radio.openReadingPipe(data_pipe, endereco);

Modulo como receptor e transmissor

Imagine agora o seguinte exemplo: dois dispositivos se comunicando. Um deles sempre avisa o outro quando um certo evento ocorreu e aguarda uma resposta.

O outro aguarda o aviso e envia uma resposta assim que recebê-lo. É um exemplo bem simples apenas para demonstrar como fazer o envio e recebimento em um mesmo dispositivo.

Enfim, veja o código para este exemplo do dispositivo que fica aguardando o “aviso” no tópico abaixo. O código do dispositivo que envia o “aviso” é similar, portanto não pretendo mostrar como seria.

Código do dispositivo recebendo e transmitindo

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
#include <SPI.h>
#include <RF24.h>

RF24 radio(7, 8); // Pinos CE e CSN

const byte endereco[6] = "teste";

// Variável para saber se a mensagem recebida foi a esperada
uint8_t msg_certa = 0;
// Mensagem esperada por este dispositivo
char msg_esperada[] = "AVISO";


void setup() {
   // Inicia a comunicação serial
  Serial.begin(9600);
 
  // Inicia a comunicação com o modulo
  radio.begin();

  // Define o mesmo endereço para o transmissor e o receptor
  // O endereço tem que ser igual nos dois dispositivos
  radio.openWritingPipe(endereco);
  radio.openReadingPipe(0, endereco);

  // Entra no modo de recebimento
  radio.startListening();
}

void loop() {
  // Verifica constantemente se recebeu algum pacote
  if (radio.available()) {
    char recebido[32] = "";

    // Se sim, lê o conteudo na variável recebido
    radio.read(&recebido, sizeof(recebido));

    // Verifica se a mensagem recebida é diferente da esperada
    msg_certa = 1;
    for (uint8_t i = 0; i < sizeof(msg_esperada); i++)
    {
      if (recebido[i] != msg_esperada[i])
      {
        msg_certa = 0;
      }
    }

    // Se tiver recebido o "aviso" manda uma resposta
    if (msg_certa)
    {
      // Resposta deste dispositivo para o outro
      char msg_resposta[] = "RECEBIDO";

      // Prepara para o modo de envio
      radio.stopListening();

      // Envia a resposta
      radio.write(&msg_resposta, sizeof(msg_resposta));

      // Entra no modo de recebimento novamente
      radio.startListening();
    }

    // Imprime o que foi recebido
    Serial.println(recebido);
  }
}

Configurações do módulo nRF24L01

Para finalizar, pretendo mostrar como fazer algumas configurações no módulo utilizando a biblioteca.

Potência do transmissor

Para alterar a potência transmitida basta utilizar o seguinte comando:

radio.setPALevel(POTENCIA);

O parâmetro POTENCIA deve ser um dos seguintes:

  • RF24_PA_MIN (-18 dBm).
  • RF24_PA_LOW (-12 dBm).
  • RF24_PA_HIGH (-6 dBm).
  • RF24_PA_MAX (0 dBm).

Velocidade de comunicação

Para alterar a velocidade de comunicação é só usar o seguinte comando:

radio.setDataRate(VELOCIDADE);

O parâmetro VELOCIDADE deve ser um dos seguintes:

  • RF24_1MBPS (1Mbps).
  • RF24_2MBPS (2 Mbps).

Alterar canal de frequência

Para alterar o canal da frequência de comunicação, utilize o comando:

radio.setChannel(CANAL);

O parâmetro CANAL é um número de 0 a 125 que corresponde ao canal desejado.

Enfim, existem outras configurações possíveis, mas mostrei as principais dentro do que foi discutido. Se você deseja ir além, recomendo dar uma lida nesta página.