RFM70 Arduino Shield
RFM70 ist ein billiger (3.5 bis 4 Euro) Sender/Empfänger, der im 2.4GHz Band arbeitet
http://www.hoperf.com/rf_fsk/rfm70.htm
Features:
2400-2483.5 MHz ISM band operation
Support 1 and 2 Mbps air data rate
Programmable output power
(-40dBm to 5dBm)Low power consumption
Variable payload length from 1 to 32bytes
Automatic packet processing
6 data pipes for 1:6 star networks
1.9V to 3.6V power supply
Control Signals up to 5V4-pin SPI interface with maximum 8 MHz
clock rateDIP-8pin and SMD-8pin Package
Beispielcode (Original auf http://www.ise.pw.edu.pl/~wzab/wireless_guitar_system/index.html)

Sender
/* Arduino Duemilanove kner 2011
ein kleines erstes Testprogramm
*/
extern "C" void __cxa_pure_virtual(void); //for C++ defines
void __cxa_pure_virtual(void) {};
#include "../../libraries/Arduino328p/WProgram.h" //import main Arduino header file
#include "../../libraries/Arduino328p/Spi.h" //import Arduino Spi function
#include "../../libraries/Arduino328p/rfm70.h"
#include <avr/io.h>
#define ACTIVATE 0x50
#define SWITCH_BANK 0x53
#define READ_REGISTER 000A AAAA
#define READ_STATUS_REGISTER 7
#define NOP 0xFF
#define FLUSH_TX 0b11100001
const PROGMEM uint8_t cmd_activate[]={0x50,0x73};
const PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
const static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
const static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
const static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
const static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};
const static PROGMEM uint8_t adr0[]={0x21,'K','N'}; //
//static PROGMEM uint8_t adr1[]={SET_NUMBER,'W','G'};
void SendString(uint8_t* s,uint8_t size);
int main(){
uint16_t dataNr=0;
init();
rfm70_hw_setup();
set_ce(0);
Serial.begin(9600);
Serial.println("RFM70 Transmitter Kner 2011");
delay(100);
//switch RFM70 to Standby; all SPI Registers available
Spi.mode(1<<SPR0); // set SPI clock to system clock / 16
Spi.transfer(FLUSH_TX);
Serial.println("Kennung:");
switch_cfg(1);
uint8_t readBuffer[4];
read_reg_pbuf(8,readBuffer,sizeof(readBuffer)); //read ID from RFM70[8]
SendString(readBuffer,4);
switch_cfg(0);
Serial.println("start init");
rfm70_init(0);
Serial.println("end init");
uint8_t status = read_reg(29);
Serial.print(status,HEX);
_delay_ms(500);
set_ce(1);
uint8_t b1=read_reg(0x07);
write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
uint8_t b2=read_reg(0x07);
if ((b1 ^ b2) != 0x80){
Serial.println("Umschalten der Registerbank funktioniert nicht");
exit(1);
}
rfm70_init(0x50); //channel = 0x50
switch_to_tx_mode();
while(1){
b1=read_reg(0x07);
if(b1 & 0x10) {
//Maximum number of retransmissions occured!
//set_ce(0);
write_reg(0x07,0x10); //clear maximum-number-of-retransmits-interrupt
//set_ce(1); //retry transfer!
Serial.println("Max. Anzahl von Retransmits");
}
if((b1 & 0x01) == 0) { //TX Fifo not full
Spi.setSS(0);
Spi.transfer(0xa0); //Start of the packet!
for (uint8_t i=0; i<32; i++){
Spi.transfer(dataNr%256);
dataNr++;
}
Spi.setSS(1); //end of Data
}
else {
Serial.print("Tx Fifo full DataNr:");
Serial.println(dataNr,DEC);
}
}
}
void SendString(uint8_t* s,uint8_t size){
for( int i=0; i<size; i++){
Serial.print(s[i], HEX);
}
}
Empfänger
/* Arduino Duemilanove kner 2011
RFM70 Modul Receiver
*/
extern "C" void __cxa_pure_virtual(void); //for C++ defines
void __cxa_pure_virtual(void) {};
#include "../../libraries/Arduino328p/WProgram.h" //import main Arduino header file
#include "../../libraries/Arduino328p/Spi.h" //import Arduino Spi function
#include "../../libraries/Arduino328p/rfm70.h"
#include <avr/io.h>
#define ACTIVATE 0x50
#define SWITCH_BANK 0x53
#define READ_REGISTER 000A AAAA
#define READ_STATUS_REGISTER 7
#define NOP 0xFF
#define FLUSH_TX 0b11100001
const PROGMEM uint8_t cmd_activate[]={0x50,0x73};
const PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
const static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
const static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
const static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
const static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};
const static PROGMEM uint8_t adr0[]={0x21,'K','N'}; //
//static PROGMEM uint8_t adr1[]={SET_NUMBER,'W','G'};
void SendString(uint8_t* s,uint8_t size);
ISR(INT0_vect, ISR_BLOCK)
{
Serial.println("juhuu, endlich ein Interrupt");
//Disable the INT0 interrupt
EIMSK &= ~(1<<INT0);
EIFR = (1<<INTF0);
while(1) { //get all packets: reading all bytes from rx fifo stops this loop
write_reg(0x7,0x40); //clear rx interrupt flag
if((read_reg(0x17) & 0x01) == 1) { //only one more byte in buffer
break;
}
Spi.setSS(0);
Spi.transfer(0x61); //read rx payload
for (uint8_t i=0; i<32; i++){
uint8_t pkt=Spi.transfer(0x00); //read packet number
Serial.println(pkt,HEX);
}
Spi.setSS(1);
}
EIMSK |= (1<<INT0); //enable again
}
int main(){
init();
EIMSK |= (1<<INT0); //allow Interrupt
//PD2 ist Input (INT0); no Pullup needed
rfm70_hw_setup(); //CE=OUTPUT
set_ce(0);
Serial.begin(9600);
Serial.println("RFM70 Receiver Kner 2011");
delay(100);
//switch RFM70 to Standby; all SPI Registers available
Spi.mode(1<<SPR0); // set SPI clock to system clock / 16
Spi.transfer(FLUSH_TX);
Serial.println("Kennung:");
switch_cfg(1);
uint8_t readBuffer[4];
read_reg_pbuf(8,readBuffer,sizeof(readBuffer)); //read ID from RFM70[8]
SendString(readBuffer,4);
switch_cfg(0);
Serial.println("start init");
rfm70_init(0);
Serial.println("end init");
uint8_t status = read_reg(29);
Serial.print(status,HEX);
_delay_ms(500);
set_ce(0);
_delay_us(10);
write_pcmd(cmd_flush_tx,sizeof(cmd_flush_tx));
write_pcmd(cmd_flush_rx,sizeof(cmd_flush_rx));
write_reg(7,0x70); //cancel all possible interrupts
set_ce(1);
uint8_t b1=read_reg(0x07);
write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
uint8_t b2=read_reg(0x07);
if ((b1 ^ b2) != 0x80){
Serial.println("Umschalten der Registerbank funktioniert nicht");
exit(1);
}
rfm70_init(0x50); //channel = 0x50
switch_to_rx_mode();
sei();
while(1){
}
}
void SendString(uint8_t* s,uint8_t size){
for( int i=0; i<size; i++){
Serial.print(s[i], HEX);
}
}
rfm70.cpp Bibliothek
/* FREEWARE
Original: Wojciech M. Zabolotny wzab<at>ise.pw.edu.pl)
kner 2011
*/
#include "rfm70.h"
#include "Spi.h"
#ifdef PROGMEM
#undef PROGMEM
#define PROGMEM __attribute__((section(".progmem.data")))
#endif
static PROGMEM uint8_t cmd_activate[]={0x50,0x73};
static PROGMEM uint8_t cmd_tog1[]={0xd9 | 0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!
static PROGMEM uint8_t cmd_tog2[]={0xd9 & ~0x06, 0x9e, 0x86, 0x0b};
static PROGMEM uint8_t cmd_flush_rx[]={0xe2,0x00};
static PROGMEM uint8_t cmd_flush_tx[]={0xe1,0x00};
static PROGMEM uint8_t cmd_switch_cfg[]={0x50,0x53};
static PROGMEM uint8_t adr0[]={0x21,'K','N'}; //
//static PROGMEM uint8_t adr1[]={SET_NUMBER,'W','G'};
static PROGMEM uint8_t set1[][4]={
{0x40, 0x4b, 0x01, 0xe2},//0
{0xc0, 0x4b, 0x00, 0x00},
{0xd0, 0xfc, 0x8c, 0x02},//2
{0x99, 0x00, 0x39, 0x41},
{0xd9, 0x9e, 0x86, 0x0b},//4 #?? d9 oder f9? POWER
{0x24, 0x06, 0x7f, 0xa6},
{0x00, 0x00, 0x00, 0x00},//6
{0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00},//8
{0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00},//10
{0x00, 0x00, 0x00, 0x00},
{0x00, 0x12, 0x73, 0x00},//12
{0x36, 0xB4, 0x80, 0x00},
};
static PROGMEM uint8_t set1_14[]={0x41,0x20,0x08,0x04,0x81,0x20,0xCF,0xF7,0xFE,0xFF,0xFF};
static PROGMEM uint8_t set0[][2]={
{0,0x3F}, //mask RX_DR\TX_DS\MAX_RT (we do not use IRQ!),Enable CRC ,2byte,POWER UP,PRX
{1,0x01}, //Enable AACK only in pipe 0! Was:{1,0x3F}, //Enable auto acknowledgement data pipe5\4\3\2\1\0
{2,0x01}, //Enable only RX pipe 0 //Enable RX Addresses pipe5\4\3\2\1\0
{3,0x01}, //RX/TX address field width 3 bytes
{4,0x0f}, //up to 15 retransmissions 250#,A5#(Bs delay! Was: {4,0xff}, //auto retransmission dalay (4000us),auto retransmission count(15)
{5,0x17}, // ?????? (5,0x17), #32 channel
{6,0x3f}, //6,0x17), #air data rate-1M,out power 0dbm,setup LNA gain
{7,0x07}, //
{8,0x00}, //
{9,0x00}, //
{12,0xc3},// only LSB Receive address data pipe 2, MSB bytes is equal to RX_ADDR_P1[39:8]
{13,0xc4},// only LSB Receive address data pipe 3, MSB bytes is equal to RX_ADDR_P1[39:8]
{14,0xc5},// only LSB Receive address data pipe 4, MSB bytes is equal to RX_ADDR_P1[39:8]
{15,0xc6},// only LSB Receive address data pipe 5, MSB bytes is equal to RX_ADDR_P1[39:8]
{17,0x20},// Number of bytes in RX payload in data pipe0(32 byte)
{18,0x20},// Number of bytes in RX payload in data pipe1(32 byte)
{19,0x20},// Number of bytes in RX payload in data pipe2(32 byte)
{20,0x20},// Number of bytes in RX payload in data pipe3(32 byte)
{21,0x20},// Number of bytes in RX payload in data pipe4(32 byte)
{22,0x20},// Number of bytes in RX payload in data pipe5(32 byte)
{23,0x00},// fifo status
{28,0x00},// No dynamic payload length! {28,0x3F},// Enable dynamic payload length data pipe5\4\3\2\1\0
{29,0x07},// Enables Dynamic Payload Length,Enables Payload with ACK,Enables the W_TX_PAYLOAD_NOACK command
};
void write_pcmd(const uint8_t * cmd, uint8_t len)
{
Spi.setSS(1);
Spi.setSS(0);
while(len--) {
Spi.transfer(pgm_read_byte(cmd++));
};
Spi.setSS(1);
}
void write_reg(uint8_t reg, uint8_t val)
{
Spi.setSS(1);
Spi.setSS(0);
Spi.transfer(reg | 0x20);
Spi.transfer(val);
Spi.setSS(1);
}
__attribute__ ((always_inline))
uint8_t read_reg(uint8_t reg)
{
uint8_t res;
Spi.setSS(0);
Spi.transfer(reg);
res=Spi.transfer(0);
Spi.setSS(1);
return res;
}
void switch_cfg(uint8_t cnum)
{
uint8_t tmp = read_reg(0x07) & 0x80;
if(cnum) {
if(!tmp)
write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
} else {
if(tmp)
write_pcmd(cmd_switch_cfg,sizeof(cmd_switch_cfg));
}
}
void switch_to_rx_mode(void)
{
uint8_t val;
write_pcmd(cmd_flush_rx,sizeof(cmd_flush_rx));
val = read_reg(0x07);
write_reg(0x07,val);
set_ce(0);
val=read_reg(0x00);
val |= 0x01;
write_reg(0x00,val);
set_ce(1);
}
void switch_to_tx_mode(void)
{
uint8_t val;
write_pcmd(cmd_flush_tx,sizeof(cmd_flush_tx));
set_ce(0);
val=read_reg(0x00);
val &= ~0x01;
write_reg(0x00,val);
set_ce(1);
}
void set_channel(uint8_t cnum)
{
write_reg(5, cnum);
}
void write_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len)
{
Spi.setSS(1);
Spi.setSS(0);
Spi.transfer(reg | 0x20);
while(len--)
Spi.transfer(pgm_read_byte(buf++));
Spi.setSS(1);
}
void read_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len)
//len Byte von Register reg lesen
{
Spi.setSS(1);
Spi.setSS(0);
Spi.transfer(reg);
while(len--){
*buf=Spi.transfer(0);
buf++;
}
Spi.setSS(1);
}
uint8_t send_packet(uint8_t * data, uint8_t len)
{
uint8_t status;
switch_to_tx_mode();
status = read_reg(0x17); //FIFO_STATUS
if (status & 0x20) return 0xff; //Error?
Spi.setSS(0);
Spi.transfer(0xb0);
while(len--) {
Spi.transfer(*(data++));
}
Spi.setSS(1);
return 0;
}
void rfm70_init(uint8_t channel)
{
uint8_t i;
switch_cfg(0);
for(i=0;i<20;i++) {
write_reg(pgm_read_byte(&set0[i][0]),pgm_read_byte(&set0[i][1]));
}
write_reg_pbuf(10,adr0,sizeof(adr0)); //PIPE 0 read address
//write_reg_pbuf(11,adr1,sizeof(adr1)); // PIPE 1 not used!
write_reg_pbuf(16,adr0,sizeof(adr0));
set_channel(channel);
if(!read_reg(29))
write_pcmd(cmd_activate,sizeof(cmd_activate));
write_reg(pgm_read_byte(&set0[22][0]),pgm_read_byte(&set0[22][1]));
write_reg(pgm_read_byte(&set0[21][0]),pgm_read_byte(&set0[21][1]));
switch_cfg(1);
for(i=0;i<14;i++) {
write_reg_pbuf(i,set1[i],sizeof(set1[i]));
}
write_reg_pbuf(14,set1_14,sizeof(set1_14));
write_reg_pbuf(4,cmd_tog1,sizeof(cmd_tog1));
write_reg_pbuf(4,cmd_tog2,sizeof(cmd_tog2));
//delay 50 ms
_delay_ms(50);
switch_cfg(0);
switch_to_rx_mode();
}
rfm70.h
#ifndef _RFM70_H_
#define _RFM70_H_
/* Includes: */
#include <ctype.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "Spi.h"
#define PORT_CE PORTD
#define DDR_CE DDRD
#define PIN_CE 3
static inline void set_ce(uint8_t val)
{
if(val)
PORT_CE |= (1<<PIN_CE);
else
PORT_CE &= ~(1<<PIN_CE);
}
static inline void rfm70_hw_setup(void)
{
DDR_CE |= (1<<PIN_CE);
}
void switch_cfg(uint8_t cnum); // switch to Register Bank cnum
void write_reg(uint8_t reg, uint8_t val);
uint8_t read_reg(uint8_t reg);
void write_pcmd(const uint8_t * cmd, uint8_t len); //Kommando und Parameter schreiben
void write_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len); // auf Register reg die Daten in buf schreiben
void read_reg_pbuf(uint8_t reg, uint8_t * buf, uint8_t len);
void rfm70_init(uint8_t channel);
void switch_to_tx_mode(void);
void switch_to_rx_mode(void);
void show_error(uint8_t msg);
void set_channel(uint8_t cnum);
#endif








