标题：nRF905
概述
  nRF905[1]是单片射频收发芯片，工作于433MHz的ISM频段，芯片内置频率合成器、功率放大器、晶体振荡器和调制器等功能模块，输出功率和通信频道可通过程序进行配置。芯片能耗非常低，以10dBm 的功率发射时，工作电流仅有 30mA，接收时工作电流只有 12.5mA，多种低功率工作模式，待机模式下电流仅为12.5μA，节能设计更方便。其 ShockBurst技术可在通讯时自动生成前导码和CRC校验位。nRF905适用于多种无线通信的场合，如无线数据传输系统、报警及安全系统、家庭自动化、遥感监测、无线门禁系统等。
应用领域
● 超低功耗无线收发器 　● 无线传感网络
● 家庭和楼宇自动化
● 无线报警安全系统
●无线数据传输系统
●报警及安全系统
●家庭自动化
●遥感监测
●无线门禁系统
●无线鼠标
●遥控开锁
●遥控玩具
性能参数
◆422.4～473.5MHz工作频段[2]
◆512个通讯频道，满足多点通讯、分组、跳频等应用需求，通道切换时间≤6us
◆发射功率可设置为：10dBm、6dBm、-2dBm和-10dBm
◆通过SPI接口与MCU连接
◆支持50kbps传输速率
◆ShockBurst传输模式，自动生成前导码和CRC校验码
◆工作电压范围：1.9V～3.6V，待机模式下电流仅为12.5μA
◆工作温度范围：-40℃～+85℃
工作模式
nRF905采用Nordic公司的VLSI ShockBurst技术。ShockBurst技术使nRF905能够提供高速的数据传输，而不需要昂贵的高速MCU来进行数据处理/时钟覆盖。通过将与RF协议有关的高速信号处理放到芯片内，nRF905提供给应用的微控制器一个SPI接口，速率由微控制器自己设定的接口速度决定。nRF905通过ShockBurst工作模式在RF以最大速率进行连接时降低数字应用部分的速度来降低在应用中的平均电流消耗。在ShockBurst RX模式中，地址匹配AM和数据准备就绪DR信号通知MCU一个有效的地址和数据包已经各自接收完成。在ShockBurst TX模式中，nRF905自动产生前导码和CRC校验码，数据准备就绪DR信号通知MCU数据传输已经完成。总之，这意味着降低MCU的存储器需求也就是说降低MCU成本，又同时缩短软件开发时间。
1）、典型ShockBurst TX模式：
①、当应用MCU有遥控数据节点时，接收节点的地址TX-address和有效数据TX-payload通过SPI接口传送给nRF905应用协议或MCU设置接口速度；
②、MCU设置TRX_CE、TX_EN为高来激活nRF905 ShockBurst传输；
③、nRF905 ShockBurst：
 无线系统自动上电
 数据包完成（加前导码和CRC校验码）
 数据包发送（100kbps，GFSK，曼切斯特编码）
④、如果AUTO_RETRAN被设置为高nRF905将连续地发送数据包直到TRX_CE被设置为低；
⑤、当TRX_CE被设置为低时，nRF905结束数据传输并自动进入standby模式。
2）、典型ShockBurst RX模式
①、通过设置TRX_CE高，TX_EN低来选择ShockBurst模式；
②、650us以后，nRF905监测空中的信息；
③、当nRF905发现和接收频率相同的载波时，载波检测CD被置高；
④、当nRF905接收到有效的地址时，地址匹配AM被置高；
⑤、当nRF905接收到有效的数据包（CRC校验正确）时，nRF905去掉前导码、地址和CRC位，数据准备就绪（DR）被置高；
⑥、MCU设置TRX_CE低，进入standby模式低电流模式；
⑦、MCU可以以合适的速率通过SPI接口读出有效数据；
⑧、当所有的有效数据被读出后，nRF905将AM和DR置低；
⑨、nRF905将准备进入ShockBurst RX、ShockBurst TX或Powerdown模式。
3）、掉电模式
在掉电模式中，nRF905被禁止，电流消耗最小，典型值低于2.5uA。当进入这种模式时，nRF905是不活动的状态。这时候平均电流消耗最小，电池使用寿命最长。在掉电模式中，配置字的内容保持不变。
4）、STANDBY模式
Standby模式在保持电流消耗最小的同时保证最短的ShockBurstRX、ShockBurstTX的启动时间。当进入这种模式时，一部分晶体振荡器是活动的。电流消耗取决于晶体振荡器频率，如：当频率为4MHZ时，IDD=12uA；当频率为20MHZ 时，IDD=46uA。如果uPCLK（Pin3）被使能，电流消耗将增加。并且取决于负载电容和频率。在此模式中，配置字的内容保持不变。
器件配置
nRF905的所有配置都通过SPI接口进行。SPI接口由5个寄存器组成，一条SPI指令用来决定进行什么操作。SPI接口只有在掉电模式和Standby模式是激活的。
1）、状态寄存器（Status-Register）
寄存器包含数据就绪DR和地址匹配AM状态。
2）、RF配置寄存器（RF-Configuration Register）
寄存器包含收发器的频率、输出功率等配置信息。
3）、发送地址（TX-Address）
寄存器包含目标器件地址，字节长度由配置寄存器设置。
4）、发送有效数据（TX-Payload）
寄存器包含发送的有效ShockBurst数据包数据，字节长度由配置寄存器设置。
5）、接收有效数据（RX-Payload）
寄存器包含接收到的有效ShockBurst数据包数据，字节长度由配置寄存器设置。在寄存器中的有效数据由数据准备就绪DR指示。
接口
1）、模式控制接口：
该接口由 PWR 、TRX_CE、TX_EN组成控制由nRF905组成的高频头的四种工作模式：掉电和 SPI 编程模式；待机和SPI编程模式 ；发射模式；接收模式。
2）、SPI接口：
SPI 接口由 CSN、SCK、MOSI以及MISO组成。在配置模式下单片机通过SPI接口配置高频头的工作参数；在发射/接收模式下单片机SPI接口发送和接收数据。
3）、状态输出接口：
提供载波检测输出CD，地址匹配输出AM，数据就绪输出DR。
外围的RF信息
1）、晶体规格
为了实现晶体振荡器低功耗和快速启动时间的解决方案,推荐使用低值晶体负载电容。指定CL=12pF是可以接受的。但是，也可能增大到16pF。指定一个晶体并行相等电容,Co=1.5pF也是很好的，但这样一来会增加晶体自身成本。典型的设定晶体电容Co=1.5pF，指定Co_max=7.0pF。
2）、外部参考时钟
一个外部参考时钟如MCU时钟，可以用来代替晶体震荡器。这个时钟信号应该直接连接到XC1引脚，XC2引脚为高阻态。当使用外部时钟代替晶体时钟工作时，始终必须工作在Standby模式以降低电流消耗。如果器件被设置成Standby模式而没有使用外部时钟或晶体时钟，则电流消耗最大可达1mA。
3）、微处理器输出时钟
在默认情况下，微处理器提供输出时钟。在Standby模式下提供输出时钟将增加电流消耗。在Standby模式电流消耗取决于频率和外部晶体负载、输出时钟的频率和提供输出时钟的电容负载。
4）、天线输出
ANT1和ANT2输出脚给天线提供稳定的RF输出。这两个脚必须有连接到VDD_PA的直流通路，通过RF扼流圈，或者通过天线双极的中心点。在ANT1和ANT2之间的负载阻抗应该在200-700Ω范围内，通过简单的匹配网络或RF变压器（不平衡变压器）可以获得较低的阻抗（例如50Ω）。
NRF905 无线传输c程序
发送部分
/****************************
//写发射数据命令:20H
//读发射数据命令:21H
//写发射地址命令:22H
//读发射地址命令:23H //读接收数据命令:24H
******************************/
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit TXEN = P2^7; //配置口定义5`6`7//
sbit TRX_CE = P2^6;
sbit PWR = P2^5;
sbit MISO = P2^2; //SPI口定义0`1`2`3//
sbit MOSI = P2^3;
sbit SCK = P2^1;
sbit CSN = P2^0;
sbit DR = P2^4; //状态输出口4//
sbit led=P1^0;
/************//*RF寄存器配置*//************* 
// 0x00, //配置命令//
// 0x6C, //CH_NO,配置频段在433.2MHZ
// 0x0E, //输出功率为10db,不重发，节电为正常模式
// 0x44, //地址宽度设置，为4字节
// 0x03,0x03, //接收发送有效数据长度为3字节
// 0xE7,0xE7,0xE7,0xE7,//接收地址,16位CRC校验，外部时钟信号使能，16M晶振//UP_CLK输出1MHZ频率
// 0xDE, //CRC充许
//******************************/
/*uchar code RFConf[11]={0x00,0x6c,0x0e,0x44,0x03,0x03,
0xe7,0xe7,0xe7,0xe7,0xde};
*/
uchar RFConf[11]=
{
0x00, //配置命令//
0x4c, //CH_NO,配置频段在423MHZ
0x0C, //输出功率为10db,不重发，节电为正常模式
0x44, //地址宽度设置，为4字节
0x02,0x02, //接收发送有效数据长度为32字节
0xCC,0xCC,0xCC,0xCC, //接收地址
0x58, //CRC充许，8位CRC校验，外部时钟信号不使能，16M晶振
};
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void SpiWrite(uchar date) //用SPI口写数据至NRF905内//
{
uchar i;
for(i=0;i<8;i++)
{
delay(1);
SCK=0;
MOSI=(date&0x80);
date<<=1 ; 
delay(1);
SCK=1; 
delay(1);
SCK=0;
}
SCK=0;
}
void TxPacket(void)
{
// TXEN=1;
CSN=0;
SpiWrite(0x22); //写发送地址,后面跟4字节地址//
SpiWrite(0xcc);
SpiWrite(0xcc);
SpiWrite(0xcc);
SpiWrite(0xcc);
CSN=1;
delay(1);
CSN=0;
SpiWrite(0x20); //写发送数据命令,后面跟三字节数据//
SpiWrite(0x01);
SpiWrite(0x02);
// SpiWrite(0x04);
CSN=1;
delay(1);
TRX_CE=1; 
TXEN=1; //CE,EN同时为1,为发送模式
delay(1); //等带发送完成// 
led=~led;
// while(!DR); //在非屏蔽状态下，只能发射一次
TRX_CE=0;
//led=~led; //加上led后，对接收产生了一定的影响，
//while(!DR); //有时多接收一次的数据
}
void Ini_System(void)
{ //初始化配置寄存器//
uchar i;
// delay(1);
CSN=1;
SCK=0;
DR=0;
PWR=1; //进入掉电模式
TRX_CE=0;
TXEN=0;
delay(1);
CSN=0; //进入SIP模式
for(i=0;i<11;i++)
{
SpiWrite(RFConf[i]); //设置配置寄存器
}
CSN=1; //关闭SPI，进入发射状态
// PWR=1;
}
void main(void)
{
led=1;
Ini_System(); //设置配置，并进入发射模式 
// PWR=1; //进入掉电模式
while(1)
{
TxPacket(); //发送数据
led=~led;
DR=0;
}
}
接收部分
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
bit lcdbit;
sbit TXEN = P2^7; //配置口定义7`6`5//
sbit TRX_CE = P2^6;
sbit PWR = P2^5;
sbit MISO = P2^2; //SPI口定义0`1`2`3//
sbit MOSI = P2^3;
sbit SCK = P2^1;
sbit CSN = P2^0;
sbit DR = P2^4; //状态输出口4//
sbit led=P1^0;
/************//*RF寄存器配置*//************* 
// 0x00, //配置命令//
// 0x6C, //CH_NO,配置频段在433.2MHZ
// 0x0E, //输出功率为10db,不重发，节电为正常模式
// 0x44, //地址宽度设置，为4字节
// 0x03,0x03, //接收发送有效数据长度为3字节
// 0xE7,0xE7,0xE7,0xE7,//接收地址,16位CRC校验，外部时钟信号使能，16M晶振//UP_CLK输出1MHZ频率
// 0xDE, //CRC充许
//******************************/
/*uchar code RFConf[11]={0x00,0x6c,0x0e,0x44,0x03,0x03,
0xe7,0xe7,0xe7,0xe7,0xde};
*/
uchar RFConf[11]={ //配置命令//
0x00,0x4c,0x0c,0x44,0x02,0x02,
0xcc,0xcc,0xcc,0xcc,0x58 //CRC充许，8位CRC校验，外部时钟信号不使能，16M晶振 
};
uchar TxRxBuffer[2];
uchar date;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void SpiWrite(unsigned char date) //用SPI口写数据至NRF905内//
{
uchar i;
for(i=0;i<8;i++)
{
delay(1);
SCK=0;
MOSI=(date&0x80);
date<<=1 ; 
delay(1);
SCK=1; 
delay(1);
SCK=0;
}
SCK=0;
}
unsigned char SpiRead(void) //from 905 read data//
{
uchar i;
for(i=0;i<8;i++)
{
date<<=1 ;
SCK=0;
delay(1);
date|=MISO;
SCK=1 ;
delay(1);
}
SCK=0;
return(date);
}
void RxPacket(void) //接收数据包//
{
uchar i;
//while(DR)
for (i = 0 ;i < 2 ;i++)
{
//led=~led;
TxRxBuffer[i] = SpiRead();
//i++;
}
}
void Wait_Rec_Packet(void) //等待接收数据包//
{ 
// uchar temp; 
// PWR=1;
TXEN=0; //接收模式
TRX_CE=1;
delay(2);
while(!DR)
{ delay(10);
// if(DR) //数据接收成功
{
led=~led;
TRX_CE=0; //如果数据准备好，则进入待机模式，以便SPI口操作
CSN=0;
delay(1);
SpiWrite(0x24); //读nRF905所接受到的数据
RxPacket(); //保存数据
CSN=1;
delay(10);
TRX_CE=1;
/*temp=TxRxBuffer[0]+TxRxBuffer[1]+TxRxBuffer[2];
if(temp==0x07)
{ 
lcdbit=!lcdbit; //lcdbit=0
}*/
break;
}
}
}
void Ini_System(void) //初始化配置寄存器//
{
uchar i;
//lcdbit=1;
CSN=1;
SCK=0;
DR=0;
PWR=1; //进入掉电模式
TRX_CE=0;
TXEN=0;
delay(1);
CSN=0; //进入SIP模式
for(i=0;i<11;i++)
{
SpiWrite(RFConf[i]); //设置配置寄存器
}
CSN=1; //关闭SPI，进入接收状态
PWR=1;
//TRX_CE=1;
//TXEN=0;
}
void main(void)
{
P0=0x00;
led=1;
Ini_System(); //设置配置，并进入接收模式 （收）
PWR=1; //进入掉电模式
while(1)
{ 
Wait_Rec_Packet(); //等待接收完成,保存完接收数据（保存数据+地址）
//CSN=0;
P0 = TxRxBuffer[0];
delay(600);
P0 = TxRxBuffer[1];
delay(600);
P0 = TxRxBuffer[2];
delay(600);
//CSN=1;
}
}
程序经本人测试后没太大问题，如要深入研究，本人附加详细资料，希望对您有所帮助。　
附加资料
基于nRF905 模块的AT89S 单片机无线收发系统设计
管脚 名称 管脚功能 说明
1 VCC 电源 电源+3.3～3.6V DC
2 TX_EN 数字输入 工作模式选择
3 TRX_CE 数字输入 使能芯片发射或接收
4 PWR_UP 数字输入 芯片上电
5 uCLK 时钟输出 (未使用)
6 CD 数字输出 载波检测
7 AM 数字输出 地址匹配
8 DR 数字输出 接收或发射数据完成
9 MISO SPI 接口 SPI 输出
10 MOSI SPI 接口 SPI 输入
11 SCK SPI 时钟 SPI 时钟
12 CSN SPI 使能 SPI 使能
13、14 GND 地 接地
下面为典型的 nRF905 模块数据发送流程[3]：
（1）当微控制器要发送数据时，将接收机的地址和发
送数据通过SPI 接口传输给nRF905 模块；
（2）微控制器设置TRX_CE 和TX_EN 管脚同时置为
高电平，启动发送端的nRF905 模块为发送模式；
（3）发送端的nRF905 模块发送过程处理：
a）射频寄存器开启；
b）数据打包（加字头和CRC 校验码）；
c）数据包发送；
d）当数据包发送结束，将数据发送完成管脚（DR 管脚）
置为高电平；
（4）如果AUTO_RETRAN 被设置为高，nRF905 模块
将连续地发送数据包，直到TRX_CE 被设置为低；
（5）TRX_CE 被设置为低时，nRF905 模块数据包发送
过程结束并回到待机模式。
AT89S 单片机控制nRF905 模块数据发送流程图如图3
所示。
下面为典型的 nRF905 模块数据接收流程[4]：
（1）微控制器控制TRX_CE 为高电平、TX_EN 为低电
平，nRF905 模块进入接收模式；
（2）650us 后，nRF905 模块监测空中的信息，等待接
收数据；
（3）当nRF905 模块检测到与接收频率相同的载波时，
设置载波检测管脚（CD 管脚）为高电平；
（4）当nRF905 模块接收到有效的地址时，设置地址匹
配管脚（AM 管脚）为高电平；
（5）当一个正确的数据包接收完毕后，nRF905 模块自
动去掉数据包的字头、地址和CRC 校验码，然后将数据接
受完成管脚置为高电平；
（6）微控制器将TRX_CE 设置为低电平；
（7）微控制器通过SPI 接口以一定的速率提取数据包
中的有效接收数据；
（8）当所有的有效数据接收完毕，微控制器控制nRF905
模块数据接收完成管脚（DR 管脚）和地址匹配管脚（AM
管脚）为低电平；
（9）nRF905 进入待机模式。
说明：（1）VCC电压范围为DC 3.3V～3.6V之间，不能超过3.6V否则会烧坏模块。
（2）模块
附加更加详细的收发程序，包括解释：
////////////////////////////////////////////整体参数////////////////////////////////////////////////////
//NewMsg-RF905-共有四种工作模式，其中有两种活动RX/TX模式和两种节电模式。
//活动模式
// ShockBurst RX
//ShockBurst TX
//节电模式
//掉电和SPI编程
//工作模式：
//┏━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━━┓
//┃PWR UP ┃ TRX CE ┃ TX_EN ┃工作模式 ┃
//┣━━━━╋━━━━╋━━━━╋━━━━━━━━━━━━━━━━┫
//┃0 ┃ x ┃ x ┃掉电和SPI编程 ┃
//┣━━━━╋━━━━╋━━━━╋━━━━━━━━━━━━━━━━┫
//┃1 ┃ 0 ┃ x ┃ Standby和SPI编程 ┃
//┣━━━━╋━━━━╋━━━━╋━━━━━━━━━━━━━━━━┫
//┃1 ┃ 1 ┃ O ┃ShockB urst RX ┃
//┣━━━━╋━━━━╋━━━━╋━━━━━━━━━━━━━━━━┫
//┃ 1 ┃ l ┃ 1 ┃ShockBurst T X ┃
//┗━━━━┻━━━━┻━━━━┻━━━━━━━━━━━━━━━━?
//ShockBurst TX发送流程:
//典型的RF905发送流程分以下几步：
//A．当微控制器有数据要发送时，通过SPI接口，按时序把接收机的地址和要发送的数据送传给RF905，
//SPI接口的速率在通信协议和器件配置时确定；
//B．微控制器置高TRX_CE和TX_EN，激发RF905的ShockBurs发送模式；
//C．RF905的ShockBurs tTMI发送：
//(1)射频寄存器自动开启；
//(2)数据打包（加字头和CRC校验码）；
//(3)发送数据包；
//(4)当数据发送完成，数据准备好引脚被置高；
//D．AUTO_REI'RAN被置高，RF905不断重发，直到TRX_CE被置低；
//E．当TRX-CE被置低，RF905发送过程完成，自动进入空闲模式。
//注意：ShockBurs tTM工作模式保证，一旦发送数据的过程开始，无
// 论TRX_EN和TX—EN引脚是高或低，发送过程都会被处理完。只有
// 在前一个数据包被发送完毕，RF905才能接受下一个发送数据包
//ShockBurst RX接收流程
// 接收流程
//A．当TRX_CE为高、TX_EN为低时，RF905进入ShockBurs tTM接收模式；
//B．650us后，RF905不断监测，等待接收数据；
//C．当RF905检测到同一频段的载波时，载波检测引脚被置高；
//D．当接收到一个相匹配的地址，AM引脚被置高；
//E．当一个正确的数据包接收完毕，RF905自动穆去字头、地址和CRC
// 校验位，然后把DR引脚置高
//F．微控制器把TRX_CE置低，nRF905进入空闲模式；
//G．微控制器通过SPI口，以一定的速率把数据穆到微控制器内；
//H．彼?械氖?萁邮胀瓯希琻RF905把DR引脚和AM引脚置低；
?
//当正在接收一个数据包时，TRX_CE或TX_EN引脚的状态发生改变，
//RF905立即把其工作模式改变，数据包则丢失。当微处理器接到AM
//引脚的信号之后， 其就知道RF905正在接收数据包，其可以决定是
//让RF905继续接收该数据包还是进入另一个工作模式。
///////节能模式
//RF905的节能模式包括关机模式和节能模式。
//在关机模式，RF905的工作电流最小，一般为2.SuA。进入关机模
//式后，RF905保持配置字中的内容，但不会接收或发送任何数据。空
//闲模式有利于减小工作电流，其从空闲模式到发送模式或接收模式的
//启动时间也比较短。在空阑模式下，RF905内部的部分晶体振荡器处
//于工作状态?
//五、配置NeWMsg-RF905模块
//所有配置字都是通过SPlI接口送给RF905。SIP接口的工作方式可
//通过SPlI指令进行设置。当RF905处于空闲模式或关机模式时，SPI
//按口可以保持在工作状?
//SPI寄存器配置
//SPI接口由5个内部寄存器组成。执行寄存器的回读模式来确认寄存器的内容。
//状态寄存器(Status-Register)
//寄存器包含数据就绪(DR)和地址匹配(AM)状态。
//RF配置寄存器(RF-Configuration Register)
//寄存器包含收发器的频率，输出功率等配置信息。
//发送地址(IX-Address)
//寄存器包含目标器件地址，字节长度由配置寄存器设置。
//发送有效数据( IX-Payload)
//寄存器包含发送的有效ShockBurst数据包数据，字节长度由配置寄存器设置。
//接收有效数据( IX-Payload)
//寄存器包含接收到的有效ShockBurst数据包数据，字节长度由配置寄存器设置。在寄存器中的有效数据由
//数据准备就绪(DR)指荆
//SPI指令设置
//用于SPI接口的有用命令见下表。当CSN为低时，SPI接口开始等待一条指令，任何一条新指令均由CSN
//的由高到低的转换开始。
//┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
//┃ SPI串行接口指令 ┃
//┣━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃指令名称 ┃指令格式 ┃操作 ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃W CONFIG ┃ OOOOAAAA ┃写配置寄存器。AAAA指出写操作的开始字节，字节数量取决于 ┃
//┃(WC) ┃ ┃AAAA指出的开始地址。 ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃R CONFIG ┃ OOOIAAAA ┃读配置寄存器。AAAA指出读操作的开始字节，字节数量取决于 ┃
//┃(RC) ┃ ┃AAAA指出的开始地址。 ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃W TX PAYLOA ┃ 00100000 ┃写TX有效数据：1-32字节。写操作全部从字节o开始。 ┃
//┃D ┃ ┃ ┃
//┃(WTP) ┃ ┃ ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃R TX PAYLOA ┃ 00100001 ┃读TX有效数据：1-32字节。读操作全部从字节o开始。 ┃
//┃D ┃ ┃ ┃
//┃(RTP) ┃ ┃ ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃W TX ADDRES ┃00100010 ┃写TX地址：1-4字节。写操作全部从字节o开始 ┃
//┃S ┃ ┃ ┃
//┃(WTA) ┃ ┃ ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃R TX ADDRES ┃0010001 1 ┃读TX地址：1-4字节。读操作全部从字节o开始。 ┃
//┃S ┃ ┃ ┃
//┃(RTA) ┃ ┃ ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃R RX PAYLOA ┃ 001 001 00 ┃读RX有效数据：1-32字节。读操作全部从字节o开始。 ┃
//┃D ┃ ┃ ┃
//┃(RRP) ┃ ┃ ┃
//┣━━━━━━╋━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
//┃CHANNEL CON ┃lOOOpphc ┃快速设置配置寄存器中CH NO，HFREQ_PLL和PA PWR的专用 ┃
//┃FIG ┃cccccccc ┃命令_ CH NO=ccccccccc: HFREQ_PLL=h: PA_PWR=pp ┃
//┃(CC) ┃ ┃ ┃
//┗━━━━━━┻━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━タ
#include <reg52.h>
//#include <ABSACC.h>
//#include <intrins.h>
//#include <stdio.h>
////----------------------------------------------------------------------------------------------------------------
#define uint unsigned int
#define uchar unsigned char
//----------------------------------------------------------------------------------------------------------------
#define BYTE_BIT00x01
#define BYTE_BIT1 0x02
#define BYTE_BIT2 0x04
#define BYTE_BIT3 0x08
#define BYTE_BIT4 0x10
#define BYTE_BIT5 0x20
#define BYTE_BIT6 0x40
#define BYTE_BIT70x80
//----------------------------------------------------------------------------------------------------------------
bdata unsigned char DATA_BUF;//可位寻址的片内RAN
#define DATA7((DATA_BUF&BYTE_BIT7) != 0)
#define DATA0 ((DATA_BUF&BYTE_BIT0) != 0)
sbitflag=DATA_BUF^7;
sbitflag1=DATA_BUF^0;
//------------------------------------ 发送数据缓冲区-------------------------------------------------
#define TxRxBuf_Len 4
unsigned char TxRxBuf[TxRxBuf_Len]={0x29,0x30,0x31,0x32,};
code TxAddress[4]={0xcc,0xcc,0xcc,0xcc};
char tf;
//----------------------------------------NRF905工作模式控制端口------------------------------------------------------
sbitTXEN=P2^4;//发射使能
sbitTRX_CE=P3^2;//发射接收使能
sbitPWR=P2^3;
//----------------------------------------LED显示端口---------------------------------------------------
sbit LED=P1^0;
//----------------------------------------NRF905 数据交换端口(SPI)---------------------------------------------------
sbitMISO=P2^6;//输出
sbitMOSI=P2^1;//输入
sbitSCK=P2^5;//时钟
sbitCSN=P2^0;//使能
//----------------------------------------nrf905状态端口---------------------------------------------------------
sbitAM=P2^7;
sbitDR=P3^3;
sbitCD=P2^2;
//---------------------------------------------------------------------------------------------------------------
//----------------------------------------按键端口-------------------------------------------------------
sbitKEY=P3^7;
//---------------------nrf905控制指令-------------------------------------------
#define WC0x00 //写配置寄存器
#define RC0x10 //读配置寄存器
#define WTP0x20 //向TX-Payload寄存器写入发送有效数据
#define RTP0x21 //向TX-Payload寄存器读取发送有效数据
#define WTA0x22 //向TX-Addtess寄存器写入发送地址
#define RTA0x23 //向TX-Addtess寄存器读取发送地址
#define RRP0x24 //从RX-Payload寄存器读取接收到的有效数据
//------------------------------------------NRF905寄存器配置------------------------------------------------
unsigned char idata RFConf[11]=
{
0x00, //配置命令//
0x4c, //CH_NO,配置频段在430MHZ字节0，配置频段
0x0c, //输出功率为10db,不重发，节电为正常模式 字节1，000 1100
0x44, //地址宽度设置，为4字节字节2，6:4 是TX地址宽度， 2：0是RX地址宽度
0x04,0x04, //接收发送有效数据长度为4字节字节3（RX），字节（TX）：可设置为1，2，4，8，16，32 字节，其中6，7 两位为空，写00，则4字节为:0000 0100 : 0x04 依次类推
0xCC,0xCC,0xCC,0xCC, //接收地址字节5到字节8
0x58, //CRC充许，8位CRC校验，外部时钟信号不使能，16M晶振 字节9，
};
//================================================延时===========================================================
void nrf905_Delay(int n)
{
uint i;
while(n--)
for(i=0;i<80;i++);
}
//=================================================SPI读函数=======================================================
//步骤一：MISO线准备好需要发送的数据位
//步骤二：SCK置高，主机读取MISO线上的数据
//步骤三:SCK置低，准备接收数据的下一位
// 以上步骤循环执行8次，通过SPI从器件上读取数据完成！
//数据传送时候。高位在前，低位在后。
unsigned char SpiRead(void)
{
unsigned char j;
for (j=0;j<8;j++)
{
DATA_BUF=DATA_BUF<<1;
SCK=1;
if (MISO)//读取最高位，保存至最末尾，通过左移位完成整个字节
{
DATA_BUF|=BYTE_BIT0;
}
else
{
DATA_BUF&=~BYTE_BIT0;
}
SCK=0;
}
return DATA_BUF;
}
//===========================================SPI写函数===============================================================
//步骤一：MOSI线准备好需要发送的数据位
//步骤二：SCK置高，器件读取MOSI线上的数据
//步骤三:SCK置低，准备发送数据的下一位
// 以上步骤循环执行8次，通过SPI从器件上发送数据完成！
//数据传送时候。低位在前，高位在后。
void SpiWrite(unsigned char send)
{
unsigned char i;
DATA_BUF=send;
for (i=0;i<8;i++)
{
if (DATA7)//总是发送最高位
{
MOSI=1;//SPI输入，主机写操作
}
else
{
MOSI=0;
}
SCK=1;
DATA_BUF=DATA_BUF<<1;
SCK=0;
}
}
//--------------------------------------初始化nRF905---------------------------------------------
void nRF905Init(void)
{
CSN=1;// Spi disable
SCK=0;// Spi clock line init low
DR=1;// Init DR for input
AM=1;// Init AM for input
CD=1;// Init CD for input
PWR=1;// nRF905 power on
TRX_CE=0;// Set nRF905 in standby mode
TXEN=0;// set radio in Rx mode
}
//-----------------------------------------------------初始化寄存器-----------------------------------------------
//步骤一:CSN置低电平，SPI接口开始等待第一条命令
//步骤二：调用SpiWrite函数，向nrf905发送WC指令，准备写入配置信息
//步骤三：反复调用SpiWrite函数，向器件配置寄存器写入配置信息
//步骤四：CSN置高电平，结束SPI通讯。即nrf905配置完成！
void Config905(void)
{
uchar i;
CSN=0;// CSN片选信号，SPI使能
//SpiWrite(WC);// 向905芯片写配置命令
for (i=0;i<11;i++)// 循环写入配置信息
{
SpiWrite(RFConf[i]); //RxTxConf保存预先设置好的配置信息
}
CSN=1;// 结束SPI数据传输
}
//-------------------------------发送数据打包---------------------------------------------------
//步骤一：通过SpiWrite函数发送WTP命令，准备写入TX有效数据
//步骤二：循环调用SpiWrite向TX-Payload寄存器写入有效数据（中间必须夹有CSN电平变化）
//步骤三：延时
//步骤四： 通过SpiWrite函数发送WTA命令，准备写入TX地址
//步骤五：循环调用SpiWrite向TX-Address寄存器写入TX地址
//步骤六：TRC_CE=1；开始发送数据，延时，nrf905数据发送完成，
//当nrf905接收到一条完成的信息时，会将DR引脚置高。
void TxPacket(uchar *TxRxBuf)
{
uchar i;
//Config905();
CSN=0;
SpiWrite(WTP);// Write payload command
for (i=0;i<4;i++)
{
SpiWrite(TxRxBuf[i]);// 写入32直接发送数据
}
CSN=1;
nrf905_Delay(1);// 关闭SPI，保存写入的数据
CSN=0;// SPI使能，保存写入的数据
SpiWrite(WTA);// 写数据至地址寄存器
for (i=0;i<4;i++)// 写入四字节地址 写入与对方地址一样的地址
{
SpiWrite(TxAddress[i]);
}
CSN=1;// 关闭SPI
TRX_CE=1;// 进入发送模式，启动射频发送
nrf905_Delay(1);//进入ShockBurst发送模式后，芯片保存数据 
TRX_CE=0;// 发送完成后返回ATANDBY模式 while (DR!=1);
}
//----------------------------------------------设置发送初始状态---------------------------------------------
void SetTxMode(void)
{
TRX_CE=0;
TXEN=1;
nrf905_Delay(1); // nrf905_Delay for mode change(>=650us)
}
//步骤一：TRX_ce=0；必须将次引脚置低，使905进入standby模式
//步骤二：发送RRP指令
//步骤三：循环调用SpiWrite函数，读取接收到的数据
//步骤四：等待DR和AM引脚复位为低电平
// AM 地址匹配，接收到有效地址，被置高
// DR 接收到有效数据包，并解码后，被置高，当所有有效数据被读取后，
// nrf905降AM和DR置低，最后需要注意的是，必须首先设置器件的
// 发送/接收模式才能保证有效的数据发生接收
//-----------------------------------------------设置nrf905进入接收模式---------------------------------------------------
void SetRxMode(void)
{
TXEN=0;
TRX_CE=1;
nrf905_Delay(1); // nrf905_Delay for mode change(>=650us)
}
//-------------------------------------判断数据接收状态-----------------------------------------------------
unsigned char CheckDR(void)//检查是否有新数据传入 Data Ready
{
DR=1; 
//通过对端口写1，可以使端口为输入状态，这51的 特性。不熟悉者可以参阅51相关书籍作证(将DR端口设置为输入状态。)
if (DR==1)
{
DR=0;
return 1;
}
else
{
return 0;
}
}
//----------------------------NRF905接收到数据后读取保存------------------------------------------------------------
void RxPacket(void)
{
uchar i;
nrf905_Delay(1);
//TRX_CE=0;// 设置905进入待机模式
nrf905_Delay(100);
TRX_CE=0;
CSN=0;// 使能SPI
nrf905_Delay(1);
SpiWrite(RRP); //准备读取接收到的数据
for (i = 0 ;i < 4 ;i++)
{ 
TxRxBuf[i]=SpiRead();// 通过SPI接口从905芯片读取数据 
}
CSN=1;//禁用SPI
nrf905_Delay(10);
TRX_CE=1;
}
//--------------------------------------------------------数据接收------------------------------------------------
void RX(void)
{
SetRxMode();
// while (CheckDR()==0); 为了实现双向通信，就不能一直处于接收等待状态，所以注释掉
nrf905_Delay(10);
RxPacket();
if(TxRxBuf[0]==0x29)
{
LED=0;
nrf905_Delay(300);
LED=1;
nrf905_Delay(300);//接收到数据 后闪烁
}
}
//-----------------------------------------------------------------------------------------------------------------
void main(void)
{
nRF905Init();
Config905();
LED=1;
while(1)
{
RX();
if(KEY ==0 )
{
while(KEY==0);
tf = 1 ;
TxRxBuf[0]=0x29;
}
if (tf==1)
{
SetTxMode();
TxPacket(TxRxBuf);// 发送命令数据
LED=0;
nrf905_Delay(300);
LED=1;
nrf905_Delay(300);//发送后LED闪烁
tf = 0;
}
}
}