Resolvido - Erro em Código nRF24L01?

Olá pessoal.

Estou a usar e código abaixo para comunicar dois arduinos.

/* COMUNICAÇÃO ENTRE: (MÓDULO_nRF24L01+) + ARDUINO + COMPUTADOR (PC):
   Para testar o MÓDULO será preciso dois ARDUINOS e dois nRF24L01+.
  
   Faça as conexões como descrito a seguir em ambos os MÓDULOS/ARDUINOS:
   - Pino 01-GND do MÓDULO conecta-se no pino GND do ARDUINO;
   - Pino 02-Vcc do MÓDULO conecta-se no pino 3,3V do ARDUINO;
   - Pino 03-CE (Chip Enable) do MÓDULO conecta-se no pino digital 09 do ARDUINO;
   - Pino 04-CSN (Chip Select) do MÓDULO conecta-se no pino digital 10 do ARDUINO;
   - Pino 05-SCK (Clock) do MÓDULO conecta-se no pino digital 13 do ARDUINO;
   - Pino 06-MOSI (Master Out Slave In) do MÓDULO conecta-se no pino digital 11 do ARDUINO;
   - Pino 07-MISO (Master In Slave Out) do MÓDULO conecta-se no pino digital 12 do ARDUINO;
   - Pino 08-IRQ (Interrupt Pin) do MÓDULO conecta-se no pino digital 02 do ARDUINO.
   - Conecte um LED no pino digital 06 do ARDUINO.     
   - Conecte um botão no pino digital 07 do ARDUINO.
   
   Após carregar este programa abra o Serial Monitor de ambos os ARDUINOS e ajuste a 
   velocidade para 9.600 bauds. Em seguida digite T (maiúsculo) no Serial Monitor do 
   Arduino que você deseja que opere como o transmissor e tecle <enter>. Agora digite R
   (maiúsculo) no Serial Monitor do Arduino que vai operar como receptor e tecle <enter>.
   Se tudo ocorrer bem ao pressionar o botão conectado no pino digital 07 do Arduino
   Transmissor (Tx) acederá o LED conectado no pino digital 06 do Arduino Receptor (Rx).
   
   Agora, caso queira que o transmissor opere como receptor e vice-versa, basta digitar
   T (maiúsculo) no Serial Monitor do Arduino que você deseja que opere como o transmissor,
   teclar <enter> e digitar R (maiúsculo) no Serial Monitor do Arduino que vai operar como
   receptor, teclar <enter> e por fim pressionar o botão do Tx para acender o LED no Rx.  
*/

// INICIALIZAÇÃO DAS BIBLIOTECAS //   


// Importando as bibliotecas necessárias
#include <SPI.h>
#include "RF24.h"


// INICIALIZAÇÃO DAS VARIÁVEIS //

RF24 moduloRF(9, 10);

 
const uint64_t tubo = 0x7878787878LL; 

const int pinoBotao = 7;              

boolean estadoBotao = 0;             
                         
int pinoLed = 6;                     
 
char  c;                             
                                      
// SETUP //
                                   
void setup()
{
    Serial.begin(9600);               //configurando a comunicação via porta 
                                      //serial à uma velocidade de 9600bps(baud).
                                      
    moduloRF.begin();                 
    moduloRF.setChannel(110);         //Configurando para trabalhar no canal de número 100, 
                                      //ou seja, canal de número 64 em hexadecimal.
  
    moduloRF.startListening();        //Inicializando o MÓDULO para "ouvir" as requisições.
 
    pinMode(pinoBotao, INPUT);        //Configurando o pino D7(pinoBotao)
                                      //como uma ENTRADA digital.
  
    digitalWrite(pinoBotao, LOW);     //Definindo o estado do pino D7(pinoBotao) em estado baixo 
                                      //(0V - botão não pressionado).
                                  
    pinMode(pinoLed, OUTPUT);         //Configurando o pino D6 do Arduino (pinoLed)
                                      //como uma SAÍDA digital.
                            
    digitalWrite(pinoLed, LOW);       //Definindo o pino6(pinoLed) em estado baixo (0V), 
                                      //isso resulta em desligar o LED.
    
    Serial.println("Digite 'T' ou 'R' ");  //Imprimindo no Serial Monitor uma mensagem.
}


void loop()
{
 
  //verificando se há quaisquer dados enviados a partir do Serial Monitor.
  if(Serial.available())
  {
    c = Serial.read();    //Lendo o caracter pressionado no teclado e gravando na
                          //variável "c". 
    Serial.println(c);    //Imprimindo no Serial Monitor a tecla pressinada no PC.
  }  
  
  //Quando o caracter pressionado no teclado for 'T', coloca o módulo no modo Tx.
  if (c == 'T' )
  {
    Tx();                 //chamando a função de configuração do módulo em modo Tx
  }
    
  //Quando o caracter pressionado no teclado for 'R', coloca o módulo no modo Rx.
  if (c == 'R')
  {
    Rx();                 //chamando a função de configuração do módulo em modo Rx
  }  
}


// FUNÇÕES //

//Função responsável por configurar o módulo em modo Tx (transmissor).
void Tx()
{
  moduloRF.stopListening();       // encerrando qualquer modo de recepção,
                                  // ou seja, de "ouvir" as requisições
  
  moduloRF.openWritingPipe(tubo); // abrindo o meio de comunicação (Tubo), com
                                  // o endeço definido no ínicio do programa  

  estadoBotao = digitalRead(pinoBotao); //lê o estado do botão

  //Se o estado do botão for pressionado (HIGH), ligar LED, senão apagar LED 
  if (estadoBotao == HIGH)
  {
      Serial.print("Ligando o LED... ");
  }else{
      Serial.print("Apagando o LED... ");
  }
 
 
  boolean successo = moduloRF.write(&estadoBotao, sizeof(estadoBotao));
 
  if(successo)
  {
      Serial.println("Sucesso na comunicacao!");
  }else{
      Serial.println("Falha na comunicacao!");
  }
  
  delay(50);                 // aguardando um tempo em milissegundos.
    
  moduloRF.startListening(); // iniciando a permissão para receber "ouvir" 
                             // novas requisições.
}

//Função responsável por configurar o módulo em modo Rx (receptor).
void Rx()
{
  moduloRF.openReadingPipe(1, tubo); 

  if(moduloRF.available())
  {

    boolean concluido = false; // Armazenar o payloads até chegar tudo
    

    while (!concluido)
    { 
        concluido = moduloRF.read(&estadoBotao, sizeof(estadoBotao));
    }
    

    if(estadoBotao)
        {  
            Serial.println("LED ativado!");
            digitalWrite(pinoLed, HIGH);
        }else{
            Serial.println("LED desativado!");
            digitalWrite(pinoLed, LOW);
        }
  }
    
  delay(100);                        //aguardando um tempo em milissegundos.
}

Porém, ele oscila muito. Ao pressionar o botão do arduino em que defini como Transceiver, o led no Receiver pisca várias vezes até se estabilizar. Gostaria de saber porque a toda hora eles ficam se comunicando, e não apenas quando pressiono o botão.

Grato

Estas a fazer o debounce do botão?

Não prestei atenção nisso. Mas receio que não seja, pois mesmo tendo parado de pressionar, o led pisca umas 4 ou 5 vezes. Acredito que o arduino já deva tratar o debounce, mas caso contrário, meu problema não aparenta ser de origem o debounce.

Quantas vezes aparece a mensagem:

Ligando o LED...

do do do transmissor?

Apenas uma ou várias? Se for apenas uma o problema está relacionado com a lógica do programa, se forem varias o problema está relacionado com a leitura do botão (são feitas várias leituras do botão). Uma coisa que eu me estava a lembrar é que na leitura o botão não é vista a transição, mas sim o estado alto, e isso poderia muito bem originar o que descreve. Também não diz nada sobre a forma como tem o botão ligado, e isso também pode ter interferência.

Se eu apenas encostar no botão, ele pisca o led, o mesmo se pressionar. Então imagino que devo tratar sim o debounce, mas não sei como, pois ele executa a ação verificando esta linha

boolean successo = moduloRF.write(&estadoBotao, sizeof(estadoBotao));

Não sei como usar a função millis nessa situação.

Mas ele não está mais oscilando.. Então já é menos mal, além de que, o comando será feito pela net, e não por botão, pois é apenas um teste com os transceivers.

Só me preocupo pelo fato da luz rx do arduino receptor estar piscando freneticamente. É como se ele estivesse lendo a todo momento o estado LOW do botão e informando isso. É um problema?

Para já não tem nada a ver com o debounce. Não devia ter ligado o GND, as sim o +5V ao outro pino do botão. Por outro lado, eu gosto de ligar um pull-up/pull-down aos botões (e pelo que estou a ver também não tem) e isso pode trazer alguns problemas (como os que está a ter).

A ligação está correta, observe que a resposta foi editada.

Boas notícias. Reescrevi um pouco o código e todo o problema foi resolvido, exceto um, que vou falar no final.

Segue o código do Receptor:

#include <SPI.h>
#include "RF24.h"

 
RF24 moduloRF(9, 10);
const uint64_t tubo = 0x7878787878LL; //Configurando endereço de comunicação entre os MÓDULOS,
                                      //onde "LL" no final do endereço define a constante como
                                      //sendo do tipo "LongLong". 


boolean estadoBotao = 0;              //inicializando uma variável denominada
boolean clock = 0;                                      //estadoBotao para armazenar o valor 
                                      //da leitura de estado do Botão. 
                         
int pinoLed = 6;                      //inicializando uma variável denominada
                                      //pinoLed no pino digital D6 do Arduino.

                                      
void setup()
{
    Serial.begin(9600);               //configurando a comunicação via porta 
                                      //serial à uma velocidade de 9600bps(baud).
                                      
    moduloRF.begin();                 //Inicialidando o MÓDULO para comunicação.
    moduloRF.setChannel(110);         //Configurando para trabalhar no canal de número 100, 
                                      //ou seja, canal de número 64 em hexadecimal.
  
    moduloRF.startListening();        //Inicializando o MÓDULO para "ouvir" as requisições.
                                  
    pinMode(pinoLed, OUTPUT);         //Configurando o pino D6 do Arduino (pinoLed)
                                      //como uma SAÍDA digital.
                            
    digitalWrite(pinoLed, LOW);       //Definindo o pino6(pinoLed) em estado baixo (0V), 
                                      //isso resulta em desligar o LED.
    
}  
void loop()
{
 
  moduloRF.openReadingPipe(1, tubo);
  if(moduloRF.available())
  {

    boolean concluido = false; // Armazenar o payloads até chegar tudo
    
    while (!concluido)
    { 
        concluido = moduloRF.read(&estadoBotao, sizeof(estadoBotao));
    }
    
    if(estadoBotao)
        {  
            
          if (clock){
            clock = false;
            Serial.println("LED desativado!");
            digitalWrite(pinoLed, LOW);
          }else{
            clock = true;
            Serial.println("LED ativado!");
            digitalWrite(pinoLed, HIGH);
          }
    }
  
  }
  
  delay(100);                        //aguardando um tempo em milissegundos.
}

Transmissor:

#include <SPI.h>
#include "RF24.h"

RF24 moduloRF(9, 10); 
const uint64_t tubo = 0x7878787878LL; 
byte pinoBotao = 7;              
boolean estadoBotao = 0;             
int pinoLed = 6;                    
char  c;                                                      
void setup()
{
    Serial.begin(9600);                
    moduloRF.begin();                 
    moduloRF.setChannel(110);        
    moduloRF.startListening();       
    pinMode(pinoBotao, INPUT);       
    digitalWrite(pinoBotao, LOW);     
    pinMode(pinoLed, OUTPUT);         
    digitalWrite(pinoLed, LOW);       
}

void loop()
{
  estadoBotao = digitalRead(pinoBotao);
  if (estadoBotao == HIGH){
    TX();
  }
}
 void TX()
 {
  moduloRF.stopListening();       
  moduloRF.openWritingPipe(tubo); 
  estadoBotao = digitalRead(pinoBotao); 
 if (estadoBotao)
  {
      Serial.print("Comando Enviado... ");
  }

  boolean successo = moduloRF.write(&estadoBotao, sizeof(estadoBotao));
 
  if(successo)
  {
      Serial.println("Sucesso na comunicacao!");
  }else{
      Serial.println("Falha na comunicacao!");
  }
  
  delay(50);                 // aguardando um tempo em milissegundos.
    
  moduloRF.startListening(); // iniciando a permissão para receber "ouvir" 
                             // novas requisições.
}

Desta forma, eu passo a usar os transceivers apenas quando pressiono o botão, e o receptor entende o último status.

O pequeno probleminha agora, é que se eu pressionar o botão em velocidade média-rápida, ele ainda lê duas vezes, ou seja, é como seu eu tivesse que pressionar o botão mais rápido para ler apenas uma vez e manter o status do led como eu desejo.

Mas isso deve ser a sensibilidade do botão mesmo.

Quanto a ligação do mesmo, está igual ao da página oficial do arduino.

yago4xd: Se eu apenas encostar no botão, ele pisca o led, o mesmo se pressionar. Então imagino que devo tratar sim o debounce, mas não sei como, pois ele executa a ação verificando esta linha

boolean successo = moduloRF.write(&estadoBotao, sizeof(estadoBotao));

Não sei como usar a função millis nessa situação.

Mas ele não está mais oscilando.. Então já é menos mal, além de que, o comando será feito pela net, e não por botão, pois é apenas um teste com os transceivers.

Só me preocupo pelo fato da luz rx do arduino receptor estar piscando freneticamente. É como se ele estivesse lendo a todo momento o estado LOW do botão e informando isso. É um problema?

O botão não é lido na linha indicada, mas sim em:

  estadoBotao = digitalRead(pinoBotao); //lê o estado do botão

  //Se o estado do botão for pressionado (HIGH), ligar LED, senão apagar LED
  if (estadoBotao == HIGH)
  {
      Serial.print("Ligando o LED... ");
  }else{
      Serial.print("Apagando o LED... ");
  }

Para além disso, cada vez que a função Tx é executada é enviada alguma mensagem e penso que não é a melhor maneira de fazer isso:

 boolean successo = moduloRF.write(&estadoBotao, sizeof(estadoBotao));

Por outro lado, não entendo como consegue ligar e desligar o led, pois nunca o vai mandar ligar.

yago4xd: A ligação está correta, observe que a resposta foi editada.

Se a montagem está como descreveu, ela não está correcta. O estado quando não está premido é LOW:

digitalWrite(pinoBotao, LOW);

e quando carrega no botão, volta a ligá-lo a GND (portanto, LOW).

Isso nunca irá funcionar.

Só me preocupo pelo fato da luz rx do arduino receptor estar piscando freneticamente. É como se ele estivesse lendo a todo momento o estado LOW do botão e informando isso.

Sim, é mesmo isso que está a acontecer. O seu botão nunca passa para o estado alto.

Acho que estamos comentando muito rápido aqui no fórum kkk. Na última mensagem eu digo que alterei o código e todo o funcionamento do circuito mudou

yago4xd:
Boas notícias. Reescrevi um pouco o código e todo o problema foi resolvido, exceto um, que vou falar no final.

Segue o código do Receptor:

#include <SPI.h>

#include “RF24.h”

RF24 moduloRF(9, 10);
const uint64_t tubo = 0x7878787878LL; //Configurando endereço de comunicação entre os MÓDULOS,
                                      //onde “LL” no final do endereço define a constante como
                                      //sendo do tipo “LongLong”.

boolean estadoBotao = 0;              //inicializando uma variável denominada
boolean clock = 0;                                      //estadoBotao para armazenar o valor
                                      //da leitura de estado do Botão.
                       
int pinoLed = 6;                      //inicializando uma variável denominada
                                      //pinoLed no pino digital D6 do Arduino.

void setup()
{
    Serial.begin(9600);              //configurando a comunicação via porta
                                      //serial à uma velocidade de 9600bps(baud).
                                     
    moduloRF.begin();                //Inicialidando o MÓDULO para comunicação.
    moduloRF.setChannel(110);        //Configurando para trabalhar no canal de número 100,
                                      //ou seja, canal de número 64 em hexadecimal.
 
    moduloRF.startListening();        //Inicializando o MÓDULO para “ouvir” as requisições.
                                 
    pinMode(pinoLed, OUTPUT);        //Configurando o pino D6 do Arduino (pinoLed)
                                      //como uma SAÍDA digital.
                           
    digitalWrite(pinoLed, LOW);      //Definindo o pino6(pinoLed) em estado baixo (0V),
                                      //isso resulta em desligar o LED.
   

void loop()
{

moduloRF.openReadingPipe(1, tubo);
  if(moduloRF.available())
  {

boolean concluido = false; // Armazenar o payloads até chegar tudo
   
    while (!concluido)
    {
        concluido = moduloRF.read(&estadoBotao, sizeof(estadoBotao));
    }
   
    if(estadoBotao)
        { 
           
          if (clock){
            clock = false;
            Serial.println(“LED desativado!”);
            digitalWrite(pinoLed, LOW);
          }else{
            clock = true;
            Serial.println(“LED ativado!”);
            digitalWrite(pinoLed, HIGH);
          }
    }
 
  }
 
  delay(100);                        //aguardando um tempo em milissegundos.
}




Transmissor:


#include <SPI.h>
#include “RF24.h”

RF24 moduloRF(9, 10);
const uint64_t tubo = 0x7878787878LL;
byte pinoBotao = 7;             
boolean estadoBotao = 0;           
int pinoLed = 6;                   
char  c;                                                     
void setup()
{
    Serial.begin(9600);               
    moduloRF.begin();               
    moduloRF.setChannel(110);       
    moduloRF.startListening();     
    pinMode(pinoBotao, INPUT);     
    digitalWrite(pinoBotao, LOW);   
    pinMode(pinoLed, OUTPUT);       
    digitalWrite(pinoLed, LOW);     
}

void loop()
{
  estadoBotao = digitalRead(pinoBotao);
  if (estadoBotao == HIGH){
    TX();
  }
}
void TX()
{
  moduloRF.stopListening();     
  moduloRF.openWritingPipe(tubo);
  estadoBotao = digitalRead(pinoBotao);
if (estadoBotao)
  {
      Serial.print("Comando Enviado… ");
  }

boolean successo = moduloRF.write(&estadoBotao, sizeof(estadoBotao));

if(successo)
  {
      Serial.println(“Sucesso na comunicacao!”);
  }else{
      Serial.println(“Falha na comunicacao!”);
  }
 
  delay(50);                // aguardando um tempo em milissegundos.
   
  moduloRF.startListening(); // iniciando a permissão para receber “ouvir”
                            // novas requisições.
}




Desta forma, eu passo a usar os transceivers apenas quando pressiono o botão, e o receptor entende o último status.

O pequeno probleminha agora, é que se eu pressionar o botão em velocidade média-rápida, ele ainda lê duas vezes, ou seja, é como seu eu tivesse que pressionar o botão mais rápido para ler apenas uma vez e manter o status do led como eu desejo.

Mas isso deve ser a sensibilidade do botão mesmo.

Quanto a ligação do mesmo, está igual ao da página oficial do arduino.

PS: Digo que a ligação está correta pois está montado como se vê no site

https://www.arduino.cc/en/Tutorial/Debounce

E quanto ao problema:

O pequeno probleminha agora, é que se eu pressionar o botão em velocidade média-rápida, ele ainda lê duas vezes, ou seja, é como seu eu tivesse que pressionar o botão mais rápido para ler apenas uma vez e manter o status do led como eu desejo.

Mas isso deve ser a sensibilidade do botão mesmo.

Já foi resolvido, bastando colocar um delay(150) após pressionar o botão.

Ou seja, Tópico Resolvido

Esta resolvido ate alguem chegar ai e demorar mais de 150ms com o dedo no botao... ;)

Na resposta #3 eu disse:

luisilva: (...) na leitura o botão não é vista a transição, mas sim o estado alto, e isso poderia muito bem originar o que descreve (...)

Se tem problemas é porque quer.

bubulindo: Esta resolvido ate alguem chegar ai e demorar mais de 150ms com o dedo no botao... ;)

Se ela demorar mais de 150ms, ela terá que pressionar novamente, dessa vez mais rápido. Já que é um botão, não tem porque ficar segurando-o. E fiz o teste, 150 é um tempo ótimo pra não acionar 2 vezes.

luisilva: Na resposta #3 eu disse: Se tem problemas é porque quer.

Não entendi esse problema. Como disse, ao alterar o código, resolvo o problema do envio constante do estado LOW. Simplesmente pega apenas o estado HIGH.

Na resposta #3 digo que na leitura do botão devia ser vista a transição (de baixo para alto) em vez do estado alto. Segundo percebo, o problema é esse. Optando por ver a transição pode demorar o tempo que quiser com o dedo em cima do botão, que apenas "vê" um clique. Já agora, para ver a transição, apenas tem que guardar o valor que estava no botão no ciclo anterior e no "if" para além de ver se o estado está alto, tem que ver se o estado anterior era baixo.

Acho que compreendi. Serial algo assim:

boolean clock = false; 
void loop()
{
  estadoBotao = digitalRead(pinoBotao);
  
  if (estadoBotao == HIGH){
    if (clock = false){
      clock = true;
      TX();
    }else{
      clock = false;
    }
  }
}

A sua aproximação, pode ser que também funcione, no entanto, estava-e a referir a uma coisa assim:

int estadoAnterior;

void loop()
{
  estadoBotao = digitalRead(pinoBotao);

  if (estadoBotao == HIGH && estadoAnterior == LOW){
      TX();
  }
  estadoAnterior = estadoBotao;
}

Certo. Testei ambos e funciona perfeitamente.

Enfim, acho que agora sim podemos dizer que está resolvido.