Vous êtes sur la page 1sur 24

Prática 5

Atividade 1:
nRF24L01 2.4GHz Radio/Wireless Transceivers
How-To
(adapted from http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo and
http://maniacbug.wordpress.com/2011/11/02/getting-started-rf24/ )
Having two or more Arduinos be able to communicate with each other wirelessly
over a distance opens lots of possibilities:
- Remote sensors for temperature, pressure, alarms, much more
- Robot control and monitoring from 50 feet to 2000 feet distances
- Remote control and monitoring of nearby or neighborhood buildings
- Autonomous vehicles of all kinds
These are a series of 2.4 GHz Radio modules that are all based on the Nordic
Semiconductor nRF24L01+ chip. The Nordic nRF24L01+ integrates a complete
2.4GHz RF transceiver, RF synthesizer, and baseband logic including the Enhanced
ShockBurstTM hardware protocol accelerator supporting a high-speed SPI interface
for the application controller. The low-power short-range (200 feet or so) Transceiver
is available on a board with Arduino interface and built-in Antenna for less than $3!
Range??
Range is very dependent on the situation and is much more with clear line of sight
outdoors than indoors with effects of walls and materials. The usual distance quoted
by different suppliers for the low-power version module with the single chip is 200
Feet or 100 Meters. This is for open space between units operating at 250KHz.
Indoors the range will be less due to walls etc...
We suggest you test two units at your actual locations before making a
decision. There are units with an Antenna Preamplifier for the receiver and
transmitter power amplifier and external antenna. The range between that type unit
and several low-power units will be better than between two low-power units. Every
situation is a little different and difficult to get an exact number without actual tests.
You don't have to, but if you want to understand more about what you can do
with this "little" radio, download the datasheet. In particular you may want to read
pages 7-8-9 ( For Overview and Features), and page 39 (MultiCeiver, which allows 6
Arduinos to talk to a Primary Arduino in an organized manner). Fortunately the
board-level products we have take care of many of the physical and electrical details
and Antenna Impedance Matching etc., and this library takes care of lots of register
initialization and operational details.
There are additional modules which add Transmitter power amplifiers and
Receiver preamplifiers for longer distances.. up to 1 Km (3000 feet). These modules
use an external antenna which can be a simple directly-attached one or a cable-
connected antenna with more gain or directivity. Here's what some of these look like:
On the left is the low-power version, with it's built-in zig-zag antenna. On the right
you can see the pins sticking down (up in this photo) that connect to Arduino. Later
we will show the pinout.

Above is the version with Transmit Power amplifier and Receive Preamplifier. An
antenna needs to be connected, as on the unit shown on the right. The same 8 pins
connect to Arduino and the same software is used.
These transceivers use the 2.4 GHz unlicensed band like many WiFi routers,
some cordless phones, etc.
Transceivers like these both send and receive data in 'packets' of several bytes
at a time. There is built-in error correction and resending, and it is possible to have
one unit communicate with up to 6 other similar units at the same time.
These amazing low-cost units have a lot of internal complexity but some
talented people have written Arduino libraries that make them easy to us. We have
other pages that show examples and point to the free software libraries you may need.
They all use the same pinout as shown in the following diagram, which is a TOP
VIEW (Correction!):
- NOTE!! Most * problems with intermittent operation are because of electrical
noise on the 3.3V Power supply. The MEGA is more of a problem with this.
Solution: ADD bypass capacitors across GND and 3.3V ON the radio modules.
One user said, "Just Solder a 100nF ceramic cap across the gnd and 3.3v pins
direct on the nrf24l01+ modules!" Some have used a 1uF to 10uF capacitor.
- NOTE: Pin 8 IRQ is Unused by most software, but the RF24 library has an
example that utilizes it.
- NOTE: The COLOR is for optional color-coded flat cable.
- NOTE: These units VCC connection must go to 3.3V not 5.0V, although the
Arduino itself may run at 5.0V and the signals will be OK. The NRF24L01+
IC is a 3.3V device, but its I/O pins are 5 V tolerant , which makes it easier to
interface to Arduino. Arduino UNO and earlier versions have a 3.3V output
that can run the low-power version of these modules, but the high-power
versions must have a separate 3.3V supply.
nRF24L01 SOFTWARE AND LIBRARY
We will show an example of transmit and receive software below, and there are many
examples on the RF24 Library download page. You will need a library of software to
run the nRF24L01 radios. There are lots of details but you can ignore many of them
that the library will take care of.
Get Maniacbug's excellent RF24 Library:
Download it HERE: https://github.com/maniacbug/RF24/ (Click "Download ZIP" on
the lower right of the page)
Once you have downloaded the ZIP, you should see a folder called RF24-
master.ZIP. Change the name of this file to just RF24.ZIP. Double click on the ZIP
and you should see a non-ZIP folder also called RF24-master. Rename this to just
RF24 as well. When you have the library installed, you can run the examples below.

Getting started
Connect Arduino and nRF24L01 according to
Line From Arduino Pin To Radio Pin
GND GND 1
3V3 3V3 2
CE 9 3
CSN 10 4
SCK 13 5
MOSI 11 6
MISO 12 7
Get the RF24 library from github. There is ample documentation at that link, as well
as a pointer to the downloads page. Unzip the archive in to your ‘libraries’ folder
under your sketch folder (something like …/Arduino/libraries), and restart the
Arduino IDE. From the File menu, select “Examples”, then “RF24″, and finally
“GettingStarted”. This will load up the GettingStarted example. It looks something
like this. Take a look below (end of Atividade 1) at the complete code of the
GettingStarted example.

/**
* Example for Getting Started with nRF24L01+ radios.
*
* This is an example of how to use the RF24 class. Write this sketch to two
* different nodes. Put one of the nodes into 'transmit' mode by connecting
* with the serial monitor and sending a 'T'. The ping node sends the current
* time to the pong node, which responds by sending the value back. The ping
* node can then see how long the whole cycle took.
*/

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

//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10

RF24 radio(9,10);
APÓS O COMANDO “radio.begin();” INCLUIR “radio.setChannel(# pra grupo);”.
NO LUGAR DE “# pra grupo” INCLUA UM INTEIRO ENTRE 0 E 127 COM O
NÚMERO DO CANAL DE COMUNICAÇÃO DO GRUPO.
Upload the sketch, start the serial monitor, set the speed to 57600, and you should see
this:
RF24/examples/GettingStarted/
ROLE: Pong back
STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0xf0f0f0f0d2 0xf0f0f0f0e1
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0xf0f0f0f0d2
RX_PW_P0-6 = 0x08 0x08 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x03
RF_CH = 0x4c
RF_SETUP = 0x07
CONFIG = 0x0f
DYNPD/FEATURE = 0x00 0x00
Data Rate = 1MBPS
Model = nRF24L01
CRC Length = 16 bits
PA Power = PA_HIGH
Instead, if you see a lot of zeroes everywhere, something is wrong with your
connections. Double check them all again! If you hooked everything else up right,
you will see numbers just like those above.
Make another one
Ok, do it all again, wiring another nRF24L01 on top of another Arduino, so our first
unit has something to talk to.
Start the second unit up, just like above, and launch the serial monitor at
57600. Press the ‘T’ key once the debugging text has printed successfully. That will
put this unit into Transmit mode, which sends a ping out to the other unit. Make sure
the other unit is still running, so this one has something to talk to!
Soon you will see the happy chatter of the radios doing their thing:
Now sending 90...ok...Got response 90, round-trip delay: 28
Now sending 1122...ok...Got response 1122, round-trip delay: 26
Now sending 2152...ok...Got response 2152, round-trip delay: 27
Now sending 3182...ok...Got response 3182, round-trip delay: 29
Now sending 4214...ok...Got response 4214, round-trip delay: 27
Now sending 5244...ok...Got response 5244, round-trip delay: 29
Now sending 6277...ok...Got response 6277, round-trip delay: 26
Now sending 7307...ok...Got response 7307, round-trip delay: 26
Now sending 8337...ok...Got response 8337, round-trip delay: 29
Now sending 9369...ok...Got response 9369, round-trip delay: 27
Now sending 10399...ok...Got response 10399, round-trip delay: 29
Now sending 11431...ok...Got response 11431, round-trip delay: 27
Now sending 12462...ok...Got response 12462, round-trip delay: 28

Software (complete code)


/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>

This program is free software; you can redistribute it and/or


modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/

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

//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10

RF24 radio(9,10);

//
// Topology
//

// Radio pipe addresses for the 2 nodes to communicate.


const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//
// Role management
//
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing.
//

// The various roles supported by this sketch


typedef enum { role_ping_out = 1, role_pong_back } role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch


role_e role = role_pong_back;

void setup(void)
{
//
// Print preamble
//

Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");

//
// Setup and configure rf radio
//

radio.begin();

// optionally, increase the delay between retries & # of retries


radio.setRetries(15,15);

// optionally, reduce the payload size. seems to


// improve reliability
radio.setPayloadSize(8);

//
// Open pipes to other nodes for communication
//

// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
// Open 'our' pipe for writing
// Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

if ( role == role_ping_out )
{
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
else
{
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
}
//
// Start listening
//

radio.startListening();

//
// Dump the configuration of the rf unit for debugging
//

radio.printDetails();
}

void loop(void)
{
//
// Ping out role. Repeatedly send the current time
//

if (role == role_ping_out)
{
// First, stop listening so we can talk.
radio.stopListening();

// Take the time, and send it. This will block until complete
unsigned long time = millis();
printf("Now sending %lu...",time);
bool ok = radio.write( &time, sizeof(unsigned long) );

if (ok)
printf("ok...");
else
printf("failed.\n\r");

// Now, continue listening


radio.startListening();

// Wait here until we get a response, or timeout (250ms)


unsigned long started_waiting_at = millis();
bool timeout = false;
while ( ! radio.available() && ! timeout )
if (millis() - started_waiting_at > 200 )
timeout = true;

// Describe the results


if ( timeout )
{
printf("Failed, response timed out.\n\r");
}
else
{
// Grab the response, compare, and send to debugging spew
unsigned long got_time;
radio.read( &got_time, sizeof(unsigned long) );

// Spew it
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
}

// Try again 1s later


delay(1000);
}

//
// Pong back role. Receive each packet, dump it out, and send it back
//

if ( role == role_pong_back )
{
// if there is data ready
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned long got_time;
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &got_time, sizeof(unsigned long) );

// Spew it
printf("Got payload %lu...",got_time);

// Delay just a little bit to let the other unit


// make the transition to receiver
delay(20);
}

// First, stop listening so we can talk


radio.stopListening();

// Send the final one back.


radio.write( &got_time, sizeof(unsigned long) );
printf("Sent response.\n\r");

// Now, resume listening so we catch the next packets.


radio.startListening();
}
}

//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");

// Become the primary transmitter (ping out)


role = role_ping_out;
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");

// Become the primary receiver (pong back)


role = role_pong_back;
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
}
}
}

Atividade 2:
Transmissão de duas entradas analógicas
(adaptada de http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo)
Conecte dois potenciômetros às entradas analógicas A0 e A1 da Arduino
transmissora (lembrar que os outros dois pinos do potenciômetro estarão em GND e
5V, respectivamente). Executem os programas abaixo nas placas transmissoras e
receptoras pra comunicar os valores lidos em A0 e A1 de uma placa para a outra.
APÓS O COMANDO “radio.begin();” INCLUIR “radio.setChannel(# pra grupo);”.
NO LUGAR DE “# pra grupo” INCLUA UM INTEIRO ENTRE 0 E 127 COM O
NÚMERO DO CANAL DE COMUNICAÇÃO DO GRUPO.
PROGRAMA PARA ARDUINO TRANSMISSORA
/* YourDuinoStarter Example: nRF24L01 Transmit Joystick values
- WHAT IT DOES: Reads Analog values on A0, A1 and transmits
them over a nRF24L01 Radio Link to another transceiver.
- SEE the comments after "//" on each line below
- CONNECTIONS: nRF24L01 Modules See:
http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
1 - GND
2 - VCC 3.3V !!! NOT 5V
3 - CE to Arduino pin 9
4 - CSN to Arduino pin 10
5 - SCK to Arduino pin 13
6 - MOSI to Arduino pin 11
7 - MISO to Arduino pin 12
8 - UNUSED
-
Analog Joystick or two 10K potentiometers:
GND to Arduino GND
VCC to Arduino +5V
X Pot to Arduino A0
Y Pot to Arduino A1

- V1.00 11/26/13
Based on examples at http://www.bajdi.com/
Questions: terry@yourduino.com */

/*-----( Import needed libraries )-----*/


#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define CE_PIN 9
#define CSN_PIN 10
#define JOYSTICK_X A0
#define JOYSTICK_Y A1

// NOTE: the "LL" at the end of the constant is "LongLong" type


const uint64_t pipe = 0xE8E8F0F0E1LL; // Define the transmit pipe

/*-----( Declare objects )-----*/


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
/*-----( Declare Variables )-----*/
int joystick[2]; // 2 element array holding Joystick readings

void setup()
{
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(pipe);
}//--(end setup )---

void loop()
{
joystick[0] = analogRead(JOYSTICK_X);
joystick[1] = analogRead(JOYSTICK_Y);

radio.write( joystick, sizeof(joystick) );

PROGRAMA PARA ARDUINO RECEPTORA


/* YourDuinoStarter Example: nRF24L01 Receive Joystick values

- WHAT IT DOES: Receives data from another transceiver with


2 Analog values from a Joystick or 2 Potentiometers
Displays received values on Serial Monitor
- SEE the comments after "//" on each line below
- CONNECTIONS: nRF24L01 Modules See:
http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
1 - GND
2 - VCC 3.3V !!! NOT 5V
3 - CE to Arduino pin 9
4 - CSN to Arduino pin 10
5 - SCK to Arduino pin 13
6 - MOSI to Arduino pin 11
7 - MISO to Arduino pin 12
8 - UNUSED

- V1.00 11/26/13
Based on examples at http://www.bajdi.com/
Questions: terry@yourduino.com */

/*-----( Import needed libraries )-----*/


#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define CE_PIN 9
#define CSN_PIN 10

// NOTE: the "LL" at the end of the constant is "LongLong" type


const uint64_t pipe = 0xE8E8F0F0E1LL; // Define the transmit pipe

/*-----( Declare objects )-----*/


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
/*-----( Declare Variables )-----*/
int joystick[2]; // 2 element array holding Joystick readings

void setup()
{
Serial.begin(9600);
delay(1000);
Serial.println("Nrf24L01 Receiver Starting");
radio.begin();
radio.openReadingPipe(1,pipe);
radio.startListening();;
}//--(end setup )---

void loop()
{
if ( radio.available() )
{
// Read the data payload until we've received everything
bool done = false;
while (!done)
{
// Fetch the data payload
done = radio.read( joystick, sizeof(joystick) );
Serial.print("X = ");
Serial.print(joystick[0]);
Serial.print(" Y = ");
Serial.println(joystick[1]);
}
}
else
{
Serial.println("No radio available");
}
}
Atividade 3:
Acionamento de LEDs a distância
Controle remotamente a ligação de 3 LEDs de cores diferentes em uma Arduino com
três botões distintos em uma outra Arduino.

Atividade 4:
Chaveamento de lâmpada
(adaptado de http://hack.lenotta.com/arduino-raspberry-pi-switching-light-with-nrf24l01/ )
Nessa atividade iremos ligar e desligar uma lâmpada remotamente. Para isso,
instalaremos uma chave tipo relé em uma lâmpada (ver figura abaixo). O relé é um
dispositivo eletromecânico que aciona uma chave dependendo da passagem ou não
de corrente por uma bobina. A bobina pode ser acionada por uma corrente
relativamente baixa, que poderia assim controlar a passagem de uma corrente bem
mais alta através da chave. No caso da nossa atividade, o relé seria controlado
remotamente por uma Arduino, que com isso deixaria ou não passar corrente para
ligar uma lâmpada. O acionamento do relé se daria pelo recebimento de uma
mensagem “1” pelo rádio, e seu desligamento ocorreria em qualquer outra situação.

APÓS O COMANDO “radio.begin();” INCLUIR “radio.setChannel(# pra grupo);”.


NO LUGAR DE “# pra grupo” INCLUA UM INTEIRO ENTRE 0 E 127 COM O
NÚMERO DO CANAL DE COMUNICAÇÃO DO GRUPO.
Para a Arduino transmissora, devemos instalar um botão na entrada digital 4, de
modo que o acionamento do botão indique um estado “HIGH” para a entrada
(mensagem “1” transmitida pelo rádio) e seu não acionamento indique um estado
“LOW” (mensagem “0” transmitida pelo rádio).
PROGRAMA PARA ARDUINO TRANSMISSORA
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define CE_PIN 9
#define CSN_PIN 10

// NOTE: the "LL" at the end of the constant is "LongLong" type


const uint64_t pipe = 0xE8E8F0F0E1LL; // Define the transmit pipe

/*-----( Declare objects )-----*/


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
/*-----( Declare Variables )-----*/
int message;

void setup()
{
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(pipe);
pinMode(4,INPUT);
}

void loop()
{
message = digitalRead(4);
radio.write(&message, sizeof(message));
}
PROGRAMA PARA ARDUINO RECEPTORA
/*
Hack.lenotta.com
Modified code of Getting Started RF24 Library
It will switch a relay on if receive a message with text 1,
turn it off otherwise.
*/

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
int relay = 8;

//
// Hardware conf
//

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10

RF24 radio(9,10);

//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
void setup(void)
{
//
// Print preamble
//

Serial.begin(57600);
pinMode(relay, OUTPUT);
digitalWrite(relay, HIGH);
printf_begin();
printf("\nLight Switch Arduino\n\r");

//
// Setup and configure rf radio
//

radio.begin();
radio.setRetries(15,15);

radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
radio.printDetails();
}

void loop(void)
{

// if there is data ready


if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned long message;
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &message, sizeof(unsigned long) );

// Spew it
printf("Got message %lu...",message);
if (message == 1){
digitalWrite(relay, LOW);
}else{
digitalWrite(relay, HIGH);
}

// Delay just a little bit to let the other unit


// make the transition to receiver
delay(20);
}

// First, stop listening so we can talk


radio.stopListening();

// Send the final one back.


radio.write( &message, sizeof(unsigned long) );
printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}

Atividade 5:
Chat
(adaptado de https://github.com/stanleyseow/RF24/blob/master/examples/Serial_Chat/nRF24_Serial_Chat.ino)

Nessa atividade iremos estabelecer um chat entre dois computadores utilizando as


portas seriais para comunicação com as respectivas Arduinos, e os rádios para
transmitir a informação entre Arduinos. Segue o programa a ser usado em ambas as
estações.
APÓS O COMANDO “radio.begin();” INCLUIR “radio.setChannel(# pra grupo);”.
NO LUGAR DE “# pra grupo” INCLUA UM INTEIRO ENTRE 0 E 127 COM O
NÚMERO DO CANAL DE COMUNICAÇÃO DO GRUPO.
/*
nRF Serial Chat
Date : 22 Aug 2013
Author : Stanley Seow
e-mail : stanleyseow@gmail.com
Version : 0.90
Desc :
I worte this simple interactive serial chat over nRF that can be used
for both sender
and receiver as I swapped the TX & RX addr during read/write operation.
It read input from Serial Monitor and display the output to the other
side
Serial Monitor or 16x2 LCD (if available)... like a simple chat program.
Max payload is 32 bytes for radio but the serialEvent will chopped the
entire buffer
for next payload to be sent out sequentially.
*/

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

RF24 radio(9,10);

const uint64_t pipes[2] = { 0xDEDEDEDEE7LL, 0xDEDEDEDEE9LL };

boolean stringComplete = false; // whether the string is complete


static int dataBufferIndex = 0;
boolean stringOverflow = false;
char charOverflow = 0;

char SendPayload[31] = "";


char RecvPayload[31] = "";
char serialBuffer[31] = "";
void setup(void) {

Serial.begin(57600);

printf_begin();
radio.begin();

radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_MAX);
radio.setChannel(70);

radio.enableDynamicPayloads();
radio.setRetries(15,15);
radio.setCRCLength(RF24_CRC_16);

radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);

radio.startListening();
radio.printDetails();

Serial.println();
Serial.println("RF Chat V0.90");
delay(500);
}

void loop(void) {

nRF_receive();
serial_receive();

} // end loop()

void serialEvent() {
while (Serial.available() > 0 ) {
char incomingByte = Serial.read();

if (stringOverflow) {
serialBuffer[dataBufferIndex++] = charOverflow;
// Place saved overflow byte into buffer
serialBuffer[dataBufferIndex++] = incomingByte;
// saved next byte into next buffer
stringOverflow = false;
// turn overflow flag off
} else if (dataBufferIndex > 31) {
stringComplete = true; // Send this buffer out to radio
stringOverflow = true; // trigger the overflow flag
charOverflow = incomingByte;
// Saved the overflow byte for next loop
dataBufferIndex = 0; // reset the bufferindex
break;
}
else if(incomingByte=='\n'){
serialBuffer[dataBufferIndex] = 0;
stringComplete = true;
} else {
serialBuffer[dataBufferIndex++] = incomingByte;
serialBuffer[dataBufferIndex] = 0;
}
} // end while()
} // end serialEvent()

void nRF_receive(void) {
int len = 0;
if ( radio.available() ) {
bool done = false;
while ( !done ) {
len = radio.getDynamicPayloadSize();
done = radio.read(&RecvPayload,len);
delay(5);
}

RecvPayload[len] = 0; // null terminate string

Serial.print("R:");
Serial.print(RecvPayload);
Serial.println();
RecvPayload[0] = 0; // Clear the buffers
}

} // end nRF_receive()

void serial_receive(void){

if (stringComplete) {
strcat(SendPayload,serialBuffer);
// swap TX & Rx addr for writing
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(0,pipes[0]);
radio.stopListening();
bool ok = radio.write(&SendPayload,strlen(SendPayload));

Serial.print("S:");
Serial.print(SendPayload);
Serial.println();
stringComplete = false;

// restore TX & Rx addr for reading


radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
SendPayload[0] = 0;
dataBufferIndex = 0;
} // endif
} // end serial_receive()

Atividade 6:
RF24Networking for Wireless Sensor Networking
(adapted from http://maniacbug.wordpress.com/2012/03/30/rf24network/ )
RF24Network is a network layer for Nordic nRF24L01+ radios running on Arduino-
compatible hardware. It’s goal is to have an alternative to Xbee radios for
communication between Arduino units. It provides a host address space and message
routing for up to 6,000 nodes. The layer forms the background of a capable and
scalable Wireless Sensor Network system. At the same time, it makes communication
between even two nodes very simple.

Get Maniacbug's RF24Network Library:


Download it HERE: https://github.com/maniacbug/RF24Network/ (Click "Download
ZIP" on the lower right of the page)

Simple Transmit/Receive
The Hello World examples illustrate how simple it is to communicate between two
nodes. The receive example (helloworld_rx) goes on one node, and the transmit
example (helloworld_tx) on the other.
There are three simple sections:
Static Initialization
First, the static setup to prepare the radio, and set the addresses. In this case, we
consider ourselves “Node #1”, and will communicate with “Node #0”. Of course,
it’s important to get the pins right. To use the boards from the Getting Started
example, you’d use pins 9 & 10.
// nRF24L01(+) radio attached using Getting Started board
RF24 radio(9,10);

// Network uses that radio


RF24Network network(radio);

// Address of our node


const uint16_t this_node = 1;

// Address of the other node


const uint16_t other_node = 0;

// How often to send 'hello world to the other unit


const unsigned long interval = 2000; //ms
// When did we last send?
unsigned long last_sent;

// How many have we sent already


unsigned long packets_sent;

// Structure of our payload


struct payload_t
{
unsigned long ms;
unsigned long counter;
};

setup()
Second, the ‘setup()’ simply prints out a quick salutation, and initializes the radio
layers.
void setup(void)
{
Serial.begin(57600);
Serial.println("RF24Network/examples/helloworld_tx/");

SPI.begin();
radio.begin();
network.begin(/*channel*/ 90, /*node address*/ this_node);
}

Transmitter loop()
Finally, the ‘loop()’ regularly sends a message to the other unit. Note that
RF24Network requires a regular call to “update()” to process packets from the radio.
It’s best to avoid calling delay() anywhere in a sketch that uses this system.
void loop(void)
{
// Pump the network regularly
network.update();

// If it's time to send a message, send it!


unsigned long now = millis();
if ( now - last_sent >= interval )
{
last_sent = now;

Serial.print("Sending...");
payload_t payload = { millis(), packets_sent++ };
RF24NetworkHeader header(/*to node*/ other_node);
bool ok = network.write(header,&payload,sizeof(payload));
if (ok)
Serial.println("ok.");
else
Serial.println("failed.");
}
}

Receiver loop()
Also, we can look at the receiver example, which is equivalent to the transmitter
sketch, with the difference of the loop(). It keeps a look out for packets, pulls them
off the radio, and prints them to the console.
void loop(void)
{
// Pump the network regularly
network.update();

// Is there anything ready for us?


while ( network.available() )
{
// If so, grab it and print it out
RF24NetworkHeader header;
payload_t payload;
network.read(header,&payload,sizeof(payload));
Serial.print("Received packet #");
Serial.print(payload.counter);
Serial.print(" at ");
Serial.println(payload.ms);
}
}

Addressing in Detail

RF24Network works great with a few nodes, but it was designed for a house-full of
nodes. Nodes are automatically configured in a tree topology, according to their node
address. Nodes can only directly communicate with their parent and their children.
The network will automatically send messages to the right place.
Node 00 is the ‘base’ node. Nodes 01-05 directly communicate with Node 00,
but not with each other. So for Node 01 to send a message to Node 02, it will travel
through Node 00. Nodes 011, 021, 031 and so on are children of Node 01. So for
Node 011 to send to 02, it will send to 01, then to 00, then to 02. Therefore, if you put
a Node 011 on your network, be sure that there is a Node 01 on the network, and it’s
powered up, and it’s in range!

Building a Wireless Sensor Network


The ‘sensornet’ example is the place to start from when building out a network of
sensors. This example demonstrates how to send a pair of sensor readings back to the
base from any number of nodes. The readings are a temperature sensor connected to
Analog input 2, and a voltage sensor connected to Analog input 3. Every node will
send a ping to the base every 4 seconds, which is a good interval for testing, while in
practice you’ll want a much longer interval. Leaf nodes will sleep in between
transmissions to conserve battery life.
The base simply dumps the ping to the console, and tracks the packet loss. This
way we can monitor the health of the network while testing it. In a real application,
you’d want to store or transmit those values somewhere.
Payload Details
RF24Network sends two pieces of information out on the wire in each frame, a
header and a message. The header is defined by the library, and used to route frames
to the correct place, and provide standard information. This is defined in
RF24Network.h.
/**
* Header which is sent with each message
*
* The frame put over the air consists of this header and a message
*/
struct RF24NetworkHeader
{
uint16_t from_node; /**< Logical address where the message was generated */
uint16_t to_node; /**< Logical address where the message is going */
uint16_t id; /**< Sequential message ID, incremented every message */
unsigned char type; /**< Type of the packet. 0-127 are user-defined types,
128-255 are reserved for system */
unsigned char reserved; /**< Reserved for future use */

...

The message is application-defined, and the header keeps track of the TYPE of
message using a single character. So your application can have different types of
messages to transmit different kinds of information. For the sensornet example, we’ll
use only a type ‘S’ message, meaning “Sensor Data”.
This message is defined in the example, in S_message.h:
/**
* Sensor message (type 'S')
*/

struct S_message
{
uint16_t temp_reading;
uint16_t voltage_reading;
S_message(void): temp_reading(0),voltage_reading(0),counter(next_counter++){}
char* toString(void);
};

This simply contains a temperature and voltage reading. These values are 8.8-bit
“fixed point” values, which is to say that the high byte is the decimal part and the low
byte is the fractional part. For example, 3.5V is represented as 0x380. Also included
is a method to convert it to a string for easy printing.
Voltage Sensor
It is interesting to monitor the battery level of each node, so we can see when it’s
time to track one down and replace its batteries. To do so, we connect the VIN from
power source, to the ‘voltage sensor’ input, via a voltage divider:

We suggest a 1M/470k divider circuit, which will reduce 3.44V down to 1.1V. In the
sensornet example it works like this:
// What voltage is a reading of 1023?
const unsigned voltage_reference = 5 * 256; // 5.0V
// How many measurements to take. 64*1024 = 65536, so 64 is the max we // can
fit in a uint16_t.
const int num_measurements = 64;
...
// Take the voltage reading
i = num_measurements;
reading = 0;
while(i--)
reading += analogRead(voltage_pin);

// Convert the voltage reading to volts*256


message.voltage_reading = ( reading * voltage_reference ) >> 16;

First, we take 64 readings, to get a good sample size. The other advantage to 64
readings is that it uses the full 16-bits of a uint16_t. Next, we multiply it by the
voltage reference. That reference considers the voltage divider we have in place,
telling us what voltage we ‘really’ have on the battery if we get an 0xFFFF reading.
In the case of the example, it’s 0x500, or 5V. Finally, we shift it down so the decimal
point is in the correct place for an 8.8 fixed point value.
Temperature Sensor
The sensornet example uses the LM35 temperature sensor. Here’s how its used in the
example:
// Take the temp reading
i = num_measurements;
uint32_t reading = 0;
while(i--)
reading += analogRead(temp_pin);

// Convert the voltage reading to celsius*256


// This is the formula for MCP9700.
// V = reading * 1.1
// C = ( V - 1/2 ) * 100
message.temp_reading = ( ( ( reading * 0x120 ) - 0x800000 ) * 0x64 ) >> 16;

Same as above, we first take 64 samples to get a reading in the range of 0x0000-
0xFFFF. Then convert it using these steps:
- Multiply by 0x120, which is 1.1 in 8.8-fixed point. This converts the
reading into volts, and increases the decimal place by 8 bits.
- Subtract 0x800000, which is 0.5, because the decimal point is way out at
24 bits.
- Multiply by 0x64 which is 100.
- Shift right 16, which reduces the decimal point from 24 bits to 8 bits
which is where we need it.
All of this is done in a 32-bit integer so there are plenty of bits to do this calculation.
Deploying
Put the sketch on every node. Start it first while connected to the serial port, so you
can give it an address:
RF24network/examples/sensornet/
PLATFORM: Getting Started Board
VERSION: 013b4d3
*** No valid address found. Send node address via serial of the form 011<cr>

Once you get a bunch of them going, you’ll see the whole spew:
1733003: APP Received #16 24.23C / 3.21V from 053
1733709: APP Received #37 23.82C / 2.70V from 043
1734297: APP Received #109 24.46C / 3.06V from 013
1735108: APP Received #55 25.16C / 3.06V from 033
1735224: APP Received #134 22.66C / 2.71V from 031
1735286: APP Received #287 25.10C / 3.24V from 01
1735565: APP Received #299 24.79C / 3.36V from 03
1736871: APP Received #71 25.78C / 3.07V from 023
1737094: APP Received #137 22.89C / 3.01V from 041
1737119: APP Received #120 23.69C / 2.98V from 011
1737247: APP Received #17 24.23C / 3.21V from 053
1738025: APP Received #38 23.82C / 2.70V from 043
1738361: APP Received #110 24.45C / 3.06V from 013
1739286: APP Received #288 25.11C / 3.24V from 01
1739404: APP Received #56 25.16C / 3.06V from 033
1739565: APP Received #300 24.78C / 3.36V from 03
1739574: APP Received #135 22.68C / 2.71V from 031
1741043: APP Received #72 25.77C / 3.07V from 023
1741213: APP Received #138 22.87C / 3.01V from 041
1741490: APP Received #121 23.68C / 2.98V from 011
1741492: APP Received #18 24.21C / 3.21V from 053

Setting the sleep interval


Once it’s up and running, you can change the sleep interval to something more
rational. For production networks, I shoot for one reading from each node every
minute, which is probably overkill but it gives me some flexibility because
sometimes nodes have trouble reaching the base for several minutes at a time. These
are the values to adjust:
// Sleep constants. In this example, the watchdog timer wakes up
// every 4s, and every single wakeup we power up the radio and send
// a reading. In real use, these numbers which be much higher.
// Try wdt_8s and 7 cycles for one reading per minute.> 1
const wdt_prescalar_e wdt_prescalar = wdt_4s;
const int sleep_cycles_per_transmission = 1;

Vous aimerez peut-être aussi