added
This commit is contained in:
commit
de083c964d
|
@ -0,0 +1,12 @@
|
|||
Aruino driver for nRF24L01 2.4GHz Wireless Transceiver
|
||||
|
||||
See Datasheet at http://www.nordicsemi.com/files/Product/data_sheet/nRF24L01_Product_Specification_v2_0.pdf
|
||||
|
||||
This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or
|
||||
the SPI hardware will go into 'slave' mode.
|
||||
|
||||
Design Goals: This library is designed to be...
|
||||
* Maximally compliant with the intended operation of the chip
|
||||
* Easy for beginners to use
|
||||
* Consumed with a public interface that's similiar to other Arduino standard libraries
|
||||
* Built against the standard SPI library.
|
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <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 <WProgram.h>
|
||||
#include <SPI.h>
|
||||
#include "RF24.h"
|
||||
#include "nRF24L01.h"
|
||||
|
||||
#undef SERIAL_DEBUG
|
||||
#ifdef SERIAL_DEBUG
|
||||
#define IF_SERIAL_DEBUG(x) (x)
|
||||
#else
|
||||
#define IF_SERIAL_DEBUG(x)
|
||||
#endif
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::csn(int mode)
|
||||
{
|
||||
digitalWrite(csn_pin,mode);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::ce(int mode)
|
||||
{
|
||||
digitalWrite(ce_pin,mode);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
while ( len-- )
|
||||
*buf++ = SPI.transfer(0xff);
|
||||
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
while ( len-- )
|
||||
SPI.transfer(*buf++);
|
||||
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::write_register(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) );
|
||||
SPI.transfer(value);
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::write_payload(const void* buf)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
const uint8_t* current = (const uint8_t*)buf;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( W_TX_PAYLOAD );
|
||||
uint8_t len = payload_size;
|
||||
while ( len-- )
|
||||
SPI.transfer(*current++);
|
||||
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::read_payload(void* buf)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t* current = (uint8_t*)buf;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( R_RX_PAYLOAD );
|
||||
uint8_t len = payload_size;
|
||||
while ( len-- )
|
||||
*current++ = SPI.transfer(0xff);
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::flush_rx(void)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( FLUSH_RX );
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::flush_tx(void)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( FLUSH_TX );
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::get_status(void)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
csn(LOW);
|
||||
status = SPI.transfer( NOP );
|
||||
csn(HIGH);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::print_status(uint8_t status)
|
||||
{
|
||||
printf("STATUS=%02x: RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\n\r",
|
||||
status,
|
||||
(status & _BV(RX_DR))?1:0,
|
||||
(status & _BV(TX_DS))?1:0,
|
||||
(status & _BV(MAX_RT))?1:0,
|
||||
((status >> RX_P_NO) & B111),
|
||||
(status & _BV(TX_FULL))?1:0
|
||||
);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::print_observe_tx(uint8_t value)
|
||||
{
|
||||
printf("OBSERVE_TX=%02x: POLS_CNT=%x ARC_CNT=%x\n\r",
|
||||
value,
|
||||
(value >> PLOS_CNT) & B1111,
|
||||
(value >> ARC_CNT) & B1111
|
||||
);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
RF24::RF24(int _cepin, int _cspin):
|
||||
ce_pin(_cepin), csn_pin(_cspin)
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::setChannel(int channel)
|
||||
{
|
||||
write_register(RF_CH,min(channel,127));
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::setPayloadSize(uint8_t size)
|
||||
{
|
||||
payload_size = min(size,32);
|
||||
write_register(RX_PW_P0,min(size,32));
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24::getPayloadSize(void)
|
||||
{
|
||||
return payload_size;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::print_details(void)
|
||||
{
|
||||
uint8_t buffer[5];
|
||||
uint8_t status = read_register(RX_ADDR_P0,buffer,5);
|
||||
print_status(status);
|
||||
printf("RX_ADDR_P0 = 0x",buffer);
|
||||
uint8_t *bufptr = buffer + 5;
|
||||
while( bufptr-- > buffer )
|
||||
printf("%02x",*bufptr);
|
||||
printf("\n\r");
|
||||
|
||||
status = read_register(RX_ADDR_P1,buffer,5);
|
||||
printf("RX_ADDR_P1 = 0x",buffer);
|
||||
bufptr = buffer + 5;
|
||||
while( bufptr-- > buffer )
|
||||
printf("%02x",*bufptr);
|
||||
printf("\n\r");
|
||||
|
||||
status = read_register(TX_ADDR,buffer,5);
|
||||
printf("TX_ADDR = 0x",buffer);
|
||||
bufptr = buffer + 5;
|
||||
while( bufptr-- > buffer )
|
||||
printf("%02x",*bufptr);
|
||||
printf("\n\r");
|
||||
|
||||
read_register(EN_AA,buffer,1);
|
||||
printf("EN_AA = %02x\n\r",*buffer);
|
||||
|
||||
read_register(EN_RXADDR,buffer,1);
|
||||
printf("EN_RXADDR = %02x\n\r",*buffer);
|
||||
|
||||
read_register(RF_CH,buffer,1);
|
||||
printf("RF_CH = %02x\n\r",*buffer);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::begin(void)
|
||||
{
|
||||
pinMode(ce_pin,OUTPUT);
|
||||
pinMode(csn_pin,OUTPUT);
|
||||
|
||||
ce(LOW);
|
||||
csn(HIGH);
|
||||
|
||||
SPI.begin();
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV8);
|
||||
|
||||
// Set generous timeouts, to make testing a little easier
|
||||
write_register(SETUP_RETR,(B1111 << ARD) | (B1111 << ARC));
|
||||
|
||||
// Reset current status
|
||||
write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
|
||||
// Flush buffers
|
||||
flush_rx();
|
||||
flush_tx();
|
||||
|
||||
// Set up default configuration. Callers can always change it later.
|
||||
setChannel(1);
|
||||
setPayloadSize(8);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::startListening(void)
|
||||
{
|
||||
write_register(CONFIG, _BV(EN_CRC) | _BV(PWR_UP) | _BV(PRIM_RX));
|
||||
write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
|
||||
// Flush buffers
|
||||
flush_rx();
|
||||
|
||||
// Go!
|
||||
ce(HIGH);
|
||||
|
||||
// wait for the radio to come up (130us actually only needed)
|
||||
delay(1);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::stopListening(void)
|
||||
{
|
||||
ce(LOW);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
boolean RF24::write( const void* buf )
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
// Transmitter power-up
|
||||
write_register(CONFIG, _BV(EN_CRC) | _BV(PWR_UP));
|
||||
|
||||
// Send the payload
|
||||
write_payload( buf );
|
||||
|
||||
// Allons!
|
||||
ce(HIGH);
|
||||
|
||||
// IN the end, the send should be blocking. It comes back in 60ms worst case, or much faster
|
||||
// if I tighted up the retry logic. (Default settings will be 750us.
|
||||
// Monitor the send
|
||||
uint8_t observe_tx;
|
||||
uint8_t status;
|
||||
do
|
||||
{
|
||||
status = read_register(OBSERVE_TX,&observe_tx,1);
|
||||
IF_SERIAL_DEBUG(Serial.print(status,HEX));
|
||||
IF_SERIAL_DEBUG(Serial.print(observe_tx,HEX));
|
||||
}
|
||||
while( ! ( status & ( _BV(TX_DS) | _BV(MAX_RT) ) ) );
|
||||
|
||||
if ( status & _BV(TX_DS) )
|
||||
result = true;
|
||||
|
||||
IF_SERIAL_DEBUG(Serial.println(result?"...OK.":"...Failed"));
|
||||
|
||||
// Yay, we are done.
|
||||
ce(LOW);
|
||||
|
||||
// Power down
|
||||
write_register(CONFIG, _BV(EN_CRC) );
|
||||
|
||||
// Reset current status
|
||||
write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
|
||||
|
||||
// Flush buffers
|
||||
flush_tx();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
boolean RF24::available(void)
|
||||
{
|
||||
uint8_t status = get_status();
|
||||
boolean result = ( status & _BV(RX_DR) );
|
||||
|
||||
if (result)
|
||||
{
|
||||
IF_SERIAL_DEBUG(print_status(status));
|
||||
|
||||
// Clear the status bit
|
||||
write_register(STATUS,_BV(RX_DR) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
boolean RF24::read( void* buf )
|
||||
{
|
||||
// was this the last of the data available?
|
||||
boolean result = false;
|
||||
|
||||
// Fetch the payload
|
||||
read_payload( buf );
|
||||
|
||||
uint8_t fifo_status;
|
||||
read_register(FIFO_STATUS,&fifo_status,1);
|
||||
if ( fifo_status & _BV(RX_EMPTY) )
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::openWritingPipe(uint64_t value)
|
||||
{
|
||||
// Note that AVR 8-bit uC's store this LSB first, and the NRF24L01
|
||||
// expects it LSB first too, so we're good.
|
||||
|
||||
write_register(RX_ADDR_P0, reinterpret_cast<uint8_t*>(&value), 5);
|
||||
write_register(TX_ADDR, reinterpret_cast<uint8_t*>(&value), 5);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24::openReadingPipe(uint8_t child, uint64_t value)
|
||||
{
|
||||
const uint8_t child_pipe[] = {
|
||||
RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5 };
|
||||
const uint8_t child_payload_size[] = {
|
||||
RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5 };
|
||||
const uint8_t child_pipe_enable[] = {
|
||||
ENAA_P1, ENAA_P2, ENAA_P3, ENAA_P4, ENAA_P5 };
|
||||
|
||||
if (--child < 5)
|
||||
{
|
||||
write_register(child_pipe[child], reinterpret_cast<uint8_t*>(&value), 5);
|
||||
write_register(child_payload_size[child],payload_size);
|
||||
|
||||
// Note this is kind of an inefficient way to set up these enable bits, bit I thought it made
|
||||
// the calling code more simple
|
||||
uint8_t en_aa;
|
||||
read_register(EN_AA,&en_aa,1);
|
||||
en_aa |= _BV(child_pipe_enable[child]);
|
||||
write_register(EN_AA,en_aa);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <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.
|
||||
*/
|
||||
|
||||
#ifndef __RF24_H__
|
||||
#define __RF24_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* Driver for nRF24L01 2.4GHz Wireless Transceiver
|
||||
*
|
||||
* See <a href="http://www.nordicsemi.com/files/Product/data_sheet/nRF24L01_Product_Specification_v2_0.pdf">Datasheet</a>
|
||||
*
|
||||
* This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or
|
||||
* the SPI hardware will go into 'slave' mode.
|
||||
*
|
||||
* Design Goals: This library is designed to be...
|
||||
* * Maximally compliant with the intended operation of the chip
|
||||
* * Easy for beginners to use
|
||||
* * Consumed with a public interface that's similiar to other Arduino standard libraries
|
||||
* * Built against the standard SPI library.
|
||||
*/
|
||||
|
||||
class RF24
|
||||
{
|
||||
private:
|
||||
int ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */
|
||||
int csn_pin; /**< SPI Chip select */
|
||||
int payload_size; /**< Fixed size of payloads */
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @name Low-level internal interface.
|
||||
*
|
||||
* Protected methods that address the chip directly.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* Set chip select pin
|
||||
*
|
||||
* @param mode HIGH to take this unit off the SPI bus, LOW to put it on
|
||||
*/
|
||||
void csn(int mode) ;
|
||||
|
||||
/**
|
||||
* Set chip enable
|
||||
*
|
||||
* @param mode HIGH to actively begin transmission or LOW to put in standby. Please see data sheet
|
||||
* for a much more detailed description of this pin.
|
||||
*/
|
||||
void ce(int mode);
|
||||
|
||||
/**
|
||||
* Read a chunk of data in from a register
|
||||
*
|
||||
* @param reg Which register. Use constants from nRF24L01.h
|
||||
* @param buf Where to put the data
|
||||
* @param len How many bytes of data to transfer
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len) ;
|
||||
|
||||
/**
|
||||
* Write a chunk of data to a register
|
||||
*
|
||||
* @param reg Which register. Use constants from nRF24L01.h
|
||||
* @param buf Where to get the data
|
||||
* @param len How many bytes of data to transfer
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t write_register(uint8_t reg, const uint8_t* buf, uint8_t len);
|
||||
|
||||
/**
|
||||
* Write a single byte to a register
|
||||
*
|
||||
* @param reg Which register. Use constants from nRF24L01.h
|
||||
* @param value The new value to write
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t write_register(uint8_t reg, uint8_t value);
|
||||
|
||||
/**
|
||||
* Write the transmit payload
|
||||
*
|
||||
* The size of data written is the fixed payload size, see getPayloadSize()
|
||||
*
|
||||
* @param buf Where to get the data
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t write_payload(const void* buf);
|
||||
|
||||
/**
|
||||
* Read the receive payload
|
||||
*
|
||||
* The size of data read is the fixed payload size, see getPayloadSize()
|
||||
*
|
||||
* @param buf Where to put the data
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t read_payload(void* buf) ;
|
||||
|
||||
/**
|
||||
* Empty the receive buffer
|
||||
*
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t flush_rx(void);
|
||||
|
||||
/**
|
||||
* Empty the transmit buffer
|
||||
*
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t flush_tx(void);
|
||||
|
||||
/**
|
||||
* Retrieve the current status of the chip
|
||||
*
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t get_status(void) ;
|
||||
|
||||
/**
|
||||
* Decode and print the given status to stdout
|
||||
*
|
||||
* @param status Status value to print
|
||||
*
|
||||
* @warning Does nothing if stdout is not defined. See fdevopen in stdio.h
|
||||
*/
|
||||
void print_status(uint8_t status) ;
|
||||
|
||||
/**
|
||||
* Decode and print the given 'observe_tx' value to stdout
|
||||
*
|
||||
* @param Value The observe_tx value to print
|
||||
*
|
||||
* @warning Does nothing if stdout is not defined. See fdevopen in stdio.h
|
||||
*/
|
||||
void print_observe_tx(uint8_t value) ;
|
||||
|
||||
/**@}*/
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param _cepin The pin attached to Chip Enable on the RF module
|
||||
* @param _cspin The pin attached to Chip Select
|
||||
*/
|
||||
RF24(int _cepin, int _cspin);
|
||||
|
||||
/**
|
||||
* Begin operation of the chip
|
||||
*
|
||||
* Call this in setup(), before calling any other methods.
|
||||
*/
|
||||
void begin(void);
|
||||
|
||||
/**
|
||||
* Set RF communication channel
|
||||
*
|
||||
* @param channel Which RF channel to communicate on, 0-127
|
||||
*/
|
||||
void setChannel(int channel);
|
||||
|
||||
/**
|
||||
* Set Payload Size
|
||||
*
|
||||
* This implementation uses a pre-stablished fixed payload size for all
|
||||
* transmissions.
|
||||
*
|
||||
* @todo Implement variable-sized payloads feature
|
||||
*
|
||||
* @param size The number of bytes in the payload
|
||||
*/
|
||||
void setPayloadSize(uint8_t size);
|
||||
|
||||
/**
|
||||
* Get Payload Size
|
||||
*
|
||||
* @see setPayloadSize()
|
||||
*
|
||||
* @return The number of bytes in the payload
|
||||
*/
|
||||
uint8_t getPayloadSize(void) ;
|
||||
|
||||
/**
|
||||
* Print a giant block of debugging information to stdout
|
||||
*
|
||||
* @warning Does nothing if stdout is not defined. See fdevopen in stdio.h
|
||||
*/
|
||||
void print_details(void) ;
|
||||
|
||||
/**
|
||||
* Start listening on the pipes opened for reading.
|
||||
*
|
||||
* Be sure to open some pipes for reading first. Do not call 'write'
|
||||
* while in this mode, without first calling 'stopListening'.
|
||||
*/
|
||||
void startListening(void);
|
||||
|
||||
/**
|
||||
* Stop listening for incoming messages
|
||||
*
|
||||
* Necessary to do this before writing.
|
||||
*/
|
||||
void stopListening(void);
|
||||
|
||||
/**
|
||||
* Write to the open writing pipe
|
||||
*
|
||||
* This blocks until the message is successfully acknowledged by
|
||||
* the receiver or the timeout/retransmit maxima are reached. In
|
||||
* the current configuration, the max delay here is 60ms.
|
||||
*
|
||||
* The size of data written is the fixed payload size, see getPayloadSize()
|
||||
*
|
||||
* @param buf Pointer to the data to be sent
|
||||
* @return True if the payload was delivered successfully false if not
|
||||
*/
|
||||
boolean write( const void* buf );
|
||||
|
||||
/**
|
||||
* Test whether there are bytes available to be read
|
||||
*
|
||||
* @return True if there is a payload available, false if none is
|
||||
*/
|
||||
boolean available(void) ;
|
||||
|
||||
/**
|
||||
* Read the payload
|
||||
*
|
||||
* Return the last payload received
|
||||
*
|
||||
* The size of data read is the fixed payload size, see getPayloadSize()
|
||||
*
|
||||
* @todo Indicate which pipe it came from
|
||||
*
|
||||
* @note I specifically chose 'void*' as a data type to make it easier
|
||||
* for beginners to use. No casting needed.
|
||||
*
|
||||
* @param buf Pointer to a buffer where the data should be written
|
||||
* @return True if the payload was delivered successfully false if not
|
||||
*/
|
||||
boolean read( void* buf ) ;
|
||||
|
||||
/**
|
||||
* Open a pipe for writing
|
||||
*
|
||||
* Only one pipe can be open at once, but you can change the pipe
|
||||
* you'll listen to. Do not call this while actively listening.
|
||||
* Remember to stopListening() first.
|
||||
*
|
||||
* Addresses are 40-bit hex values, e.g.:
|
||||
* @code
|
||||
* openWritingPipe(0xF0F0F0F0F0);
|
||||
* @endcode
|
||||
*
|
||||
* @param value The 40-bit address of the pipe to open. This can be
|
||||
* any value whatsoever, as long as you are the only one writing to it
|
||||
* and only one other radio is listening to it. Coordinate these pipe
|
||||
* addresses amongst nodes on the network.
|
||||
*/
|
||||
void openWritingPipe(uint64_t address);
|
||||
|
||||
/**
|
||||
* Open a pipe for reading
|
||||
*
|
||||
* Up to 5 pipes can be open for reading at once. Open all the
|
||||
* reading pipes, and then call startListening().
|
||||
*
|
||||
* @see openWritingPipe
|
||||
*
|
||||
* @warning all 5 reading pipes should share the first 32 bits.
|
||||
* Only the least significant byte should be unique, e.g.
|
||||
* @code
|
||||
* openReadingPipe(0xF0F0F0F0AA);
|
||||
* openReadingPipe(0xF0F0F0F066);
|
||||
* @endcode
|
||||
*
|
||||
* @todo Enforce the restriction that all pipes must share the top 32 bits
|
||||
*
|
||||
* @param number Which pipe# to open, 1-5.
|
||||
* @param address The 40-bit address of the pipe to open.
|
||||
*/
|
||||
void openReadingPipe(uint8_t number, uint64_t address);
|
||||
|
||||
};
|
||||
#endif // __RF24_H__
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example RF Radio Ping Pair
|
||||
*
|
||||
* This sketch is an example of using the RF24 library for Arduino. Deploy this on
|
||||
* two nodes, set one as the 'trasmit' and the other the 'receive' unit. The transmit
|
||||
* unit will send out the value of millis() once a second. The receive unit will respond
|
||||
* back with a copy of the value. The transmit unit can get that 'ping' back, and
|
||||
* determine 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 8 & 9
|
||||
|
||||
RF24 radio(8,9);
|
||||
|
||||
// sets the address (and therefore the role of operation) of this unit.
|
||||
// lo = node0, hi = node1
|
||||
const int addr_pin = 7;
|
||||
|
||||
// The actual value of the node's address will be filled in by the sketch
|
||||
// when it reads the addr_pin
|
||||
int node_address;
|
||||
|
||||
//
|
||||
// Topology
|
||||
//
|
||||
|
||||
// Radio pipe addresses for the 2 nodes to communicate.
|
||||
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
|
||||
|
||||
//
|
||||
// Role management
|
||||
//
|
||||
// Set up address & role. This sketch uses the same software for all the nodes
|
||||
// in this system. Doing so greatly simplifies testing. The hardware itself specifies
|
||||
// which node it is.
|
||||
//
|
||||
// This is done through the addr_pin. Set it low for address #0, high for #1.
|
||||
//
|
||||
|
||||
// The various roles supported by this sketch
|
||||
typedef enum { role_rx = 1, role_tx1, role_end } role_e;
|
||||
|
||||
// The debug-friendly names of those roles
|
||||
const char* role_friendly_name[] = { "invalid", "Receive", "Transmit"};
|
||||
|
||||
// Which role is assumed by each of the possible hardware addresses
|
||||
const role_e role_map[2] = { role_rx, role_tx1 };
|
||||
|
||||
// The role of the current running sketch
|
||||
role_e role;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
//
|
||||
// Address & Role
|
||||
//
|
||||
|
||||
// set up the address pin
|
||||
pinMode(addr_pin, INPUT);
|
||||
digitalWrite(addr_pin,HIGH);
|
||||
delay(20); // Just to get a solid reading on the addr pin
|
||||
|
||||
// read the address pin, establish our address and role
|
||||
node_address = digitalRead(addr_pin) ? 0 : 1;
|
||||
role = role_map[node_address];
|
||||
|
||||
//
|
||||
// Print preamble
|
||||
//
|
||||
|
||||
Serial.begin(9600);
|
||||
printf_begin();
|
||||
printf("\n\rRF24 pingpair example\n\r");
|
||||
printf("ADDRESS: %x\n\r",node_address);
|
||||
printf("ROLE: %s\n\r",role_friendly_name[role]);
|
||||
|
||||
//
|
||||
// Setup and configure rf radio
|
||||
//
|
||||
|
||||
radio.begin();
|
||||
|
||||
// Set channel (optional)
|
||||
radio.setChannel(1);
|
||||
|
||||
// Set size of payload (optional, but recommended)
|
||||
// The library uses a fixed-size payload, so if you don't set one, it will pick
|
||||
// one for you!
|
||||
radio.setPayloadSize(sizeof(unsigned long));
|
||||
|
||||
//
|
||||
// Open pipes to other nodes for communication (required)
|
||||
//
|
||||
|
||||
// This simple sketch opens two pipes for these two nodes to communicate
|
||||
// back and forth.
|
||||
|
||||
// We will open 'our' pipe for writing
|
||||
radio.openWritingPipe(pipes[node_address]);
|
||||
|
||||
// We open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
|
||||
int other_node_address;
|
||||
if (node_address == 0)
|
||||
other_node_address = 1;
|
||||
else
|
||||
other_node_address = 0;
|
||||
radio.openReadingPipe(1,pipes[other_node_address]);
|
||||
|
||||
//
|
||||
// Start listening
|
||||
//
|
||||
|
||||
radio.startListening();
|
||||
|
||||
//
|
||||
// Dump the configuration of the rf unit for debugging
|
||||
//
|
||||
|
||||
radio.print_details();
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
//
|
||||
// Transmitter role. Repeatedly send the current time
|
||||
//
|
||||
|
||||
if (role == role_tx1)
|
||||
{
|
||||
// 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 );
|
||||
|
||||
// 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 > 250 )
|
||||
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 );
|
||||
|
||||
// Spew it
|
||||
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
|
||||
}
|
||||
|
||||
// Try again 1s later
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
//
|
||||
// Receiver role. Receive each packet, dump it out, and send it back to the transmitter
|
||||
//
|
||||
|
||||
if ( role == role_rx )
|
||||
{
|
||||
// if there is data ready
|
||||
if ( radio.available() )
|
||||
{
|
||||
// Dump the payloads until we've gotten everything
|
||||
unsigned long got_time;
|
||||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
// Fetch the payload, and see if this was the last one.
|
||||
done = radio.read( &got_time );
|
||||
|
||||
// Spew it
|
||||
printf("Got payload %lu...",got_time);
|
||||
}
|
||||
|
||||
// First, stop listening so we can talk
|
||||
radio.stopListening();
|
||||
|
||||
// Send the final one back.
|
||||
radio.write( &got_time );
|
||||
printf("Sent response.\n\r");
|
||||
|
||||
// Now, resume listening so we catch the next packets.
|
||||
radio.startListening();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright (C) 2011 James Coliz, Jr. <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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file printf.h
|
||||
*
|
||||
* Setup necessary to direct stdout to the Arduino Serial library, which
|
||||
* enables 'printf'
|
||||
*/
|
||||
|
||||
#ifndef __PRINTF_H__
|
||||
#define __PRINTF_H__
|
||||
|
||||
#include "WProgram.h"
|
||||
|
||||
int serial_putc( char c, FILE *t )
|
||||
{
|
||||
Serial.write( c );
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
fdevopen( &serial_putc, 0 );
|
||||
}
|
||||
|
||||
#endif // __PRINTF_H__
|
|
@ -0,0 +1,13 @@
|
|||
RF24 KEYWORD1
|
||||
begin KEYWORD2
|
||||
setChannel KEYWORD2
|
||||
setPayloadSize KEYWORD2
|
||||
getPayloadSize KEYWORD2
|
||||
print_details KEYWORD2
|
||||
startListening KEYWORD2
|
||||
stopListening KEYWORD2
|
||||
write KEYWORD2
|
||||
available KEYWORD2
|
||||
read KEYWORD2
|
||||
openWritingPipe KEYWORD2
|
||||
openReadingPipe KEYWORD2
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Memory Map */
|
||||
#define CONFIG 0x00
|
||||
#define EN_AA 0x01
|
||||
#define EN_RXADDR 0x02
|
||||
#define SETUP_AW 0x03
|
||||
#define SETUP_RETR 0x04
|
||||
#define RF_CH 0x05
|
||||
#define RF_SETUP 0x06
|
||||
#define STATUS 0x07
|
||||
#define OBSERVE_TX 0x08
|
||||
#define CD 0x09
|
||||
#define RX_ADDR_P0 0x0A
|
||||
#define RX_ADDR_P1 0x0B
|
||||
#define RX_ADDR_P2 0x0C
|
||||
#define RX_ADDR_P3 0x0D
|
||||
#define RX_ADDR_P4 0x0E
|
||||
#define RX_ADDR_P5 0x0F
|
||||
#define TX_ADDR 0x10
|
||||
#define RX_PW_P0 0x11
|
||||
#define RX_PW_P1 0x12
|
||||
#define RX_PW_P2 0x13
|
||||
#define RX_PW_P3 0x14
|
||||
#define RX_PW_P4 0x15
|
||||
#define RX_PW_P5 0x16
|
||||
#define FIFO_STATUS 0x17
|
||||
|
||||
/* Bit Mnemonics */
|
||||
#define MASK_RX_DR 6
|
||||
#define MASK_TX_DS 5
|
||||
#define MASK_MAX_RT 4
|
||||
#define EN_CRC 3
|
||||
#define CRCO 2
|
||||
#define PWR_UP 1
|
||||
#define PRIM_RX 0
|
||||
#define ENAA_P5 5
|
||||
#define ENAA_P4 4
|
||||
#define ENAA_P3 3
|
||||
#define ENAA_P2 2
|
||||
#define ENAA_P1 1
|
||||
#define ENAA_P0 0
|
||||
#define ERX_P5 5
|
||||
#define ERX_P4 4
|
||||
#define ERX_P3 3
|
||||
#define ERX_P2 2
|
||||
#define ERX_P1 1
|
||||
#define ERX_P0 0
|
||||
#define AW 0
|
||||
#define ARD 4
|
||||
#define ARC 0
|
||||
#define PLL_LOCK 4
|
||||
#define RF_DR 3
|
||||
#define RF_PWR 1
|
||||
#define LNA_HCURR 0
|
||||
#define RX_DR 6
|
||||
#define TX_DS 5
|
||||
#define MAX_RT 4
|
||||
#define RX_P_NO 1
|
||||
#define TX_FULL 0
|
||||
#define PLOS_CNT 4
|
||||
#define ARC_CNT 0
|
||||
#define TX_REUSE 6
|
||||
#define FIFO_FULL 5
|
||||
#define TX_EMPTY 4
|
||||
#define RX_FULL 1
|
||||
#define RX_EMPTY 0
|
||||
|
||||
/* Instruction Mnemonics */
|
||||
#define R_REGISTER 0x00
|
||||
#define W_REGISTER 0x20
|
||||
#define REGISTER_MASK 0x1F
|
||||
#define R_RX_PAYLOAD 0x61
|
||||
#define W_TX_PAYLOAD 0xA0
|
||||
#define FLUSH_TX 0xE1
|
||||
#define FLUSH_RX 0xE2
|
||||
#define REUSE_TX_PL 0xE3
|
||||
#define NOP 0xFF
|
Loading…
Reference in New Issue