Acionar relé remoto por botoeira

Imagine uma situação em que existam 2 prédios; prédio A e prédio B. Um segurança noturno passa desligando determinados pontos de energia no prédio A e posteriormente deve dirigir-se ao prédio B para o mesmo procedimento. Não seria mais eficiente se ele fosse apenas em um dos prédio e fizesse o desligamento remoto do prédio oposto? Bem, devido a um caso semelhante, tive que fazer esse pequeno projetinho – e com quase nenhum código, apenas implementando alguma funcionalidade no sketch de exemplo em Examples > RF24 > GettingStarted.

Mas como acionar esse relé remoto por botoeira?



Nesse outro artigo eu mostro um modelo de painel com botoeira. No caso real, quando o botão virar para a posição de acionamento do relé, ele deve colocar o respectivo pino de um PCF8574 em GND, então o Arduino faz a leitura do estado dos pinos do PCF8574 e envia um byte (unsigned char) para o outro lado via rádio NRF24L01. O Arduino do outro lado faz a recepção dessa informação e faz a correspondência dos bits (contidos nesse byte) com a posição do array de relés, que demonstro em seguida no código implementado sobre o sketch de exemplo.

#define TURN_OFF     1 //meu modulo desliga em HIGH
#define TURN_ON      0 //e liga em LOW

// UNO
#define SIDE_A 0
#define SIDE_B 1
bool role = SIDE_B;
bool radioNumber = SIDE_B;
#define ADDRESS  0x24 //jumpers: +-- (uno)

Nessa pequena porção de código, defini ligadodesligado porque o acionamento do relé é feito com o pino de IO em LOW. Isso evita fazer confusão.

Utilizei um Arduino UNO e um Arduino Nano, como você pode ver no video. Na comunicação dos rádios, algumas configurações especificas são necessárias. O role define quem está enviando (como mestre) e quem está recebendo. Porém isso não importa de fato, porque quando um dado chega, uma resposta é enviada, então a comunicação acontece de forma bidirecional em intervalos de 1.2s (esse tempo pode ser modificado tanto para o delay do loop como para a leitura do rádio).

O rádio deve possuir um identificado. Repare no código de exemplo que há uma definição para o identificar (que não é IP nem MAC, mas apenas um array de unsigned char):

byte addresses[][6] = {"1Node","2Node"};

Nessa lista estão dispostos apenas 2 rádios, e quando definimos a variável radioNumber estamos apontando um desses dois identificadores desse array, então não cometa o erro de colocar um número maior que 1 ou menor que 0. E já que só pode ser 0 ou 1, o jeito mais simples de evitar confusão é definir a variável radioNumber com o mesmo valor de role, usando um define para SIDE_A  ou SIDE_B.

Por fim, devemos definir um endereço para o PCF8574. Olhando para o módulo, você pode notar o sinal de de um lado dos jumpers e – do lado oposto. Para o endereço 0x22 coloquei o jumper em +– no Arduino Nano.

Defini uma variável para guardar o valor de leitura do rádio (buf) e o array de pinos dos relés. Seria muito mais simples adicionar outro PCF8574 e apenas transferir o valor advindo do rádio para ele, mas se quiser evitar wiring ou reduzir o custo em cada centavo, essa solução pode ser a mais próxima de ideal.

byte relays[8] = {2,3,4,5,6,9,10}; //pinos para cada um dos 7 reles
byte buf = 0;

Função de manipulação dos relés

E depois das poucas linhas acima, adicionei essa função para manipular os relés, o restante do sketch é o mesmo código contido no exemplo. Fácil implementar algo funcional sem esforço com Arduino, hum?

void changeRelayState(){
  byte state = buf; //equipara o buffer com o comparador e faz um loop nos pinos
  for (int i=0;i<7;i++){
    state = buf|(1<<i); //incrementa o valor do buffer com a respectiva posição
    //se for possível incrementar o valor do buffer, significa que o 
    //pino do PCF8574 está em LOW
    if (state != buf){
      digitalWrite(relays[i],TURN_OFF); //nesse caso, desliga o relay da posição 'i'
      Serial.print("OFF: ");
      Serial.println(relays[i]);
      state = buf;
    }
    /*Senão, liga o relay da posição 'i'*/
    else{
      digitalWrite(relays[i],TURN_ON);
      Serial.print("ON: ");
      Serial.println(relays[i]);
    }
  }
}

O código completo ficou assim (usando como base o Arduino UNO):

/*
* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20
*/

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

#define TURN_OFF     1 //meu modulo desliga em HIGH
#define TURN_ON      0 //e liga em LOW

// UNO
#define SIDE_A 0
#define SIDE_B 1
bool role = SIDE_B;
bool radioNumber = SIDE_B;
#define ADDRESS  0x24 //jumpers: +-- (uno)

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/


/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/

byte addresses[][6] = {"1Node","2Node"};


byte relays[8] = {2,3,4,5,6,9,10}; //pinos para cada um dos 7 reles
byte buf = 0;

void changeRelayState(){
  byte state = buf; //equipara o buffer com o comparador e faz um loop nos pinos
  for (int i=0;i<7;i++){
    state = buf|(1<<i); //incrementa o valor do buffer com a respectiva posição
    //se for possível incrementar o valor do buffer, significa que o 
    //pino do PCF8574 está em LOW
    if (state != buf){
      digitalWrite(relays[i],TURN_OFF); //nesse caso, desliga o relay da posição 'i'
      Serial.print("OFF: ");
      Serial.println(relays[i]);
      state = buf;
    }
    /*Senão, liga o relay da posição 'i'*/
    else{
      digitalWrite(relays[i],TURN_ON);
      Serial.print("ON: ");
      Serial.println(relays[i]);
    }
  }
}

void setup() {
  Wire.begin();
  Serial.begin(115200);

  for (byte i=0;i<2;i++){
    pinMode(relays[i],OUTPUT);
  }
  Serial.println(F("RF24/examples/GettingStarted"));
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
  
  radio.begin();

  // Set the PA Level low to prevent power supply related issues since this is a
 // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
  radio.setPALevel(RF24_PA_LOW);
  
  // Open a writing and reading pipe on each radio, with opposite addresses
  if(radioNumber){
    radio.openWritingPipe(addresses[1]);
    radio.openReadingPipe(1,addresses[0]);
  }else{
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1,addresses[1]);
  }
  
  // Start the radio listening for data
  radio.startListening();
}

void loop() {
  
  
/****************** Ping Out Role ***************************/  
if (role == 1)  {
    byte state;
    radio.stopListening();                                    // First, stop listening so we can talk.
    
    
    Serial.println(F("Now sending"));
    Wire.beginTransmission(ADDRESS); //inicia transmissao no barramento i2c
  Wire.write(0xFF); //coloca tudo em HIGH. O que estiver em GND vai para LOW sozinho.
  Wire.endTransmission(); //fim do envio do comando.
  delay(1000);

  Wire.requestFrom(ADDRESS,1); //solicita 1 byte (8 bits)
  if (Wire.available()){
    state = Wire.read();
  }
  Serial.print("Enviando: ");
  Serial.println(state);


     if (!radio.write(state, sizeof(byte) )){
       Serial.println(F("failed"));
     }
        
    radio.startListening();                                    // Now, continue listening
    
    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    boolean timeout = false;                                   // Set up a variable to indicate if a response was received or not
    
    while ( ! radio.available() ){                             // While nothing is received
      if (micros() - started_waiting_at > 200000 ){            // If waited longer than 200ms, indicate timeout and exit while loop
          timeout = true;
          break;
      }      
    }
        
    if ( timeout ){                                             // Describe the results
        Serial.println(F("Failed, response timed out."));
    }else{
        byte got_time;                                 // Grab the response, compare, and send to debugging spew
        radio.read( &got_time, sizeof(byte) );
        unsigned long end_time = micros();

        buf = got_time;
        changeRelayState();
        
        // Spew it
        Serial.print(F("Sent "));

        Serial.print(F(", Got response "));
        Serial.print(got_time);
        Serial.print(F(", Round-trip delay "));

        Serial.println(F(" microseconds"));
    }

    // Try again 1s later
    delay(1000);
  }



/****************** Pong Back Role ***************************/

  if ( role == 0 )
  {
    byte got_time;
    
    if( radio.available()){
                                                                    // Variable for the received timestamp
      while (radio.available()) {                                   // While there is data ready
        radio.read( &got_time, sizeof(byte) );             // Get the payload
        buf = got_time;
        changeRelayState();
      }
     Wire.beginTransmission(ADDRESS); //inicia transmissao no barramento i2c
  Wire.write(0xFF); //coloca tudo em HIGH. O que estiver em GND vai para LOW sozinho.
  Wire.endTransmission(); //fim do envio do comando.
  delay(1000);

  Wire.requestFrom(ADDRESS,1); //solicita 1 byte (8 bits)
  if (Wire.available()){
    got_time = Wire.read();
  }
  Serial.print("Enviando: ");
  Serial.println(got_time);
      radio.stopListening();                                        // First, stop listening so we can talk   
      radio.write( &got_time, sizeof(byte) );              // Send the final one back.      
      radio.startListening();                                       // Now, resume listening so we catch the next packets.     
      Serial.print(F("Sent response "));
      Serial.println(got_time);  
   }
 }




/****************** Change Roles via Serial Commands ***************************/

  if ( Serial.available() )
  {
    char c = toupper(Serial.read());
    if ( c == 'T' && role == 0 ){      
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1;                  // Become the primary transmitter (ping out)
    
   }else
    if ( c == 'R' && role == 1 ){
      Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));      
       role = 0;                // Become the primary receiver (pong back)
       radio.startListening();
       
    }
  }


} // Loop

O resultado você vê no video a seguir.

Inscreva-se no nosso newsletter, alí em cima à direita e receba novos posts por email.

Siga-nos no Do bit Ao Byte no Facebook.

Prefere twitter? @DobitAoByte.

Inscreva-se no nosso canal Do bit Ao Byte Brasil no YouTube.

Nossos grupos:

Arduino BR – https://www.facebook.com/groups/microcontroladorarduinobr/
Raspberry Pi BR – https://www.facebook.com/groups/raspberrybr/
Orange Pi BR – https://www.facebook.com/groups/OrangePiBR/
Odroid BR – https://www.facebook.com/groups/odroidBR/
Sistemas Embarcados BR – https://www.facebook.com/groups/SistemasEmbarcadosBR/
MIPS BR – https://www.facebook.com/groups/MIPSBR/
Do Bit ao Byte – https://www.facebook.com/groups/dobitaobyte/

Próximo post a caminho!

Deixe uma resposta