nrf24L01编程心得1

合集下载

nrf24le1学习笔记

nrf24le1学习笔记

1、写卡时,需要将两根绿色的线进行短接,否则写卡失败!!!除此之外,当写卡烧录完写程序后,配置完读卡参数之后,需要重新上电,并且还需要重新关闭串口再打开串口。

否则不能写卡另外,注意卡片电池,如果电池电源太低,也不能写卡。

写卡器刚烧录完程序后,当配置完读卡器配置后,需要重新关闭和打开串口,再进行写卡器配置(或者软件重开),否则无法写卡。

2、所有的内存在没有写之前都是FF3、RC振荡器:在振荡电路中的频率选择部分可以只用电阻和电容构成。

这种只用电阻和电容构成的振荡器称为RC振荡器。

晶振:只要在晶体板极上施加交变电压,就会使晶片产生机械变形振动,此现象即所谓逆压电效应。

当外加电压频率等于晶体谐振器的固有频率时,就会发生压电谐振,从而导致机械变形的振幅突然增大。

4、温度系统:温度系数表征标称值受温度变化影响的程度,单位是ppm/°C。

如电阻的阻值,基准电压源的电压值等。

温度系数通常非常小,采用百万分比(ppm)表示更容易。

5、编程总结:1、nrf24le1芯片使用时,有一个寄存器,是用于控制端口操作的,如果关闭此端口则不能正确操作此端口。

OPMCON = 0x02;则表示关闭了端口,在使用端口时,应该重新打开端口。

如OPMCON = 0x00;2、nrf24le1芯片,当使用它与C8051F120进行SLAVE SPI通信时,如果已经完数据,而要从已写完的数据中,再读取出来,则需要一定的延时!3、两块单片机使用SPI通信时,如果配置的晶振频率过高,有可能使得程序在while循环等待过程中接收不到另一发起人单片机的程序,从而出现单片机死机的现象。

4、使用nrf24le1时,在使用二维数组,不能将二维数组的地址传递给一个数a,再把a传递给b而就直接交二维数组传递给b5、关于return和break:使用return时是跳出此子函数,回到调用该子函数的后面。

而使用break时是跳出该循环体。

6. 关于卡片睡眠醒来操作内存:当卡片醒来,若是要操作内存,则必须将系统时钟重新配置:CLKCTRL=0;delay_nms(30);(延时是为了等待时钟响应)。

24L01详细经验之谈

24L01详细经验之谈
3、注意spi通信中,可以一次读取或写入多个字节,顺序为低字节在前,高字节在后,每个字节是高位在前,低位在后。
4、参考SPI时序图,可见,上升沿写入1个bit,下降沿读入一个bit。
5、该SPI通信函数只涉及一个字节的读写,没有涉及CS信号线。
SPI_RW_Reg()函数应用举例,一次写入多个字节
/*************************************************************************/
24L01被设置为接收模式后,可通过6个不同的数据通道(data pipe)接收数据。每个数据通道都有一个唯一的地址但是各数据通道的频率是相同的。这意味着可以有6个被配置成发送状态的nRF24L01可以和一个配置成接收状态的nRF24L01通信,并且接收方可以区分。
数据通道0有一个唯一的40bit的可设置的地址。其余的通道1到通道5则地址前32位相同,而后8位不同。所有的数据通道都可以实现Enhanced ShockBurst模式。
#define RX_ADDR_P1 0x0B //频道1接收数据地址
#define RX_ADDR_P2 0x0C//频道2接收数据地址
#define RX_ADDR_P3 0x0D //频道3接收数据地址
#define RX_ADDR_P4 0x0E //频道4接收数据地址
#define RX_ADDR_P5 0x0F//频道5接收数据地址
/*****************************模拟SPI时序****************************/
ucharSPI_RW(uchar ch)
{
ucharbit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++)

NRF24L01之我的学习体会

NRF24L01之我的学习体会

本程序存在的问题:反应不够灵敏,当在按键1和按键2之间切换的时候,对方的灯闪烁会有一定的延时,另外本程序没有消除按键的抖动。

对部分函数的解释:uint SPI_RW(uint dat)最基本的函数,完成GPIO模拟SPI 的功能。

将输出字节(MOSI)从MSB 循环输出,同时将输入字节(MISO)从LSB 循环移入。

上升沿读入,下降沿输出。

(从SCK被初始化为低电平可以判断出)uchar SPI_Read(uchar reg); //从reg寄存器读一字节读取寄存器值的函数:基本思路就是通过READ_REG命令(也就是0x00+寄存器地址),把寄存器中的值读出来。

对于函数来说也就是把reg 寄存器的值读到reg_val 中去。

uint SPI_RW_Reg(uchar reg, uchar value); //写数据value到reg寄存器寄存器访问函数:用来设置24L01 的寄存器的值。

基本思路就是通过WRITE_REG命令(也就是0x20+寄存器地址)把要设定的值写到相应的寄存器地址里面去,并读取返回值。

对于函数来说也就是把value值写到reg 寄存器中。

需要注意的是,访问NRF24L01 之前首先要enable 芯片(CSN=0;),访问完了以后再disable芯片(CSN=1;)。

uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);//从reg寄存器读出bytes个字节,通常用来//读取接收通道数据或接收/发送地址接收缓冲区访问函数:主要用来在接收时读取FIFO 缓冲区中的值。

基本思路就是通过READ_REG命令把数据从接收FIFO(RD_RX_PLOAD)中读出并存到数组里面去。

uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);//把pBuf缓存中的数据写入到nRF24L01通常用来写入发发射缓冲区访问函数:主要用来把数组里的数放到发射FIFO缓冲区中。

nrf24l01使用与调试经验总结(包括一收多发)

nrf24l01使用与调试经验总结(包括一收多发)

nrf24l01使用与调试经验总结(包括一收多发--1主机最多6从机)----------------------------------------------------------------------------------------------------------------------------主要特性工作在2.4GHz ISM 频段调制方式:GFSK/FSK数据速率:2Mbps/1Mbps/250Kbps超低关断功耗:<0.7uA超低待机功耗:<15uA快速启动时间:<130uS内部集成高PSRR LDO宽电源电压范围:1.9-3.6V数字IO 电压: 3.3V/5V低成本晶振:16MHz±60ppm接收灵敏度:<-83dBm @2MHz最高发射功率:7dBm接收电流(2Mbps):<15mA发射电流(2Mbps):<12mA(0dBm)10MHz 四线SPI 模块内部集成智能ARQ 基带协议引擎收发数据硬件中断输出支持1bit RSSI 输出极少外围器件,降低系统应用成本QFN20 封装或COB 封装注意:C代表了命令,S表示寄存器值,D表示数据写数据:SPI写命令+寄存器地址----->SPI写入数据读数据:SPI写寄存器地址(可以使用读命令+寄存器地址)----->SPI读取数据不论是读取或者写入数据,甚至是读/写len长度的数据都要先写寄存器地址;总的来说时候就三个模式:1.待机模式(待机模式+掉电省电模式)2.发送模式3.接受模式具体各个模式介绍参考数据手册。

----------------------------------------------------------------------------------------------------------------nrf发送数据是以包来发送。

关于NRF24l01的调试

关于NRF24l01的调试

NRF24l01的调试过程与方法小结心得体会:最近老板给了几块nrf24l01模块我,初次上手难免走了许多的弯路,经过近一周的时间的不断调试,模块之间终于可以相互收发数据了。

这样下来终于松了一口气。

其间的各种辛苦与艰辛难于言表。

上网大致看了一下,网上基于51的调试比较多,但是我们实验室用的是DSP2812,由于nrf24l01是SPI接口,2812上刚好有SPI的接口,这样貌似给使用带来了方便,但是51之类的芯片虽然没有SPI口,但是例程也最多,关于他的讨论比较多。

最开始我的想法也比较混乱,想直接用SPI来调试,把底层函数稍微修改了一下,发现并没有结果,这个东西就像一个黑匣子一样,即看不见也摸不着,后来我慢慢改变了思路。

既然网上基于IO口模拟的SPI的例程最多,我决定另外走一条路,先用2812的IO 口模拟SPI再用自带的SPI口去调试。

这样一来我就有了两条可以走的路。

第一条:底层SPI时序用IO口模拟去写。

第二条:底层直接用2812的SPI去操作。

虽然这样一来,路好走了一点,有各类的程序可以参考,但是这样带来最大的一个问题,这也是后来我才发现的,nrf24l01的最大读写速率是有限制的,2812在150M运行时很显然是太大了一点,由于nrf24l01对时序的要求很高,端口的读写速率和时序都有严格的要求,所以我们才看到,在网上一般是15M左右的单片机来模拟IO口,没有谁用150M的DSP来模拟IO口的,当然既然确定了这样的方法后来也发现了问题,我还是继续走下去了。

很重要的一点是系统的时钟频率。

当然时序的要求也很高,这也就是为什么,网上说这个模块不好调试的原因,既然是调试,当然我们既然是调试,肯定有一个思路和方法。

那么方法是什么呢?开始的时候我是一股脑将发送和接收的程序都写进去,然后啥现象也没有,然后就傻眼了。

在网上看了看,于是有了一点思路。

方法是将发送和接收的调试分开来调试,以读取nrf24l01内部的寄存器为手段,先调试发送方,发送方调试没有问题以后,让发送方不断的发送数据,然后再来调试接收方,直到接收方也没有问题,再接着望下面去做。

个人学习

个人学习
uchar SPI_Read(uchar reg)
{
uchar reg_val;
CSN = 0;
SPI_RW(reg);
#define WRITE_REG 0x20 //写寄存器指令
#define RD_RX_PLOAD 0x61 //读取接收数据指令
#define WR_TX_PLOAD 0xA0 //写待发数据指令
#define FLUSH_TX 0xE1 //冲洗发送FIFO指令
#define FLUSH_RX 0xE2 //冲洗接收FIFO指令
void init_NRF24L01(void)
{
inerDelay_us(100);
CE=0;
CSN=1;
SCK=0;
SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); //写本地地址
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); //写接收端地址
}
/****************************************************************************************************
/*函数:uint SPI_RW(uint uchar)
/*功能:NRF24L01的SPI写时序
#define TX_ADR_WIDTH 5 //接收地址宽度,一般设置为5不要动它
#define RX_ADR_WIDTH 5 //接收地址宽度,一般设置为5不要动它
#define TX_PLOAD_WIDTH 1 //接收数据的数据宽度(最大为32字节),这里我设置为最小的1字节,方便调试

nrf24l01是适合初学入门的无线模块

nrf24l01是适合初学入门的无线模块

24l01的多机通信采用频分多子的方法,只需要在接受端对不同的通道配置地址即可。

发送端使用相应的地址作为本机地址。

接受数据时通过读取STATUS 中相关位即可得知接收的是哪个通道的数据。

以下仅给出多对一的通信代码。

至于一对多,以及多对多等情况读者可以自行研究了。

只给出相关部分,其他部分请参考前两篇文章------------------------------------------------------------------------------------------接受端uint const ADDRESS0[ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //频道0接收地址uint const ADDRESS1[ADR_WIDTH]= {0xc4,0xc3,0xc2,0xc1,0xc0}; //频道1接收地址uchar who=0xff;//**************************************************************** ************************/*NRF24L01初始化//**************************************************************** ***********************/void init_NRF24L01(void){us(100);CE=0; // chip enableCSN=1; // Spi disableSCK=0; // Spi clock line init high//SPI_Write_Buf(WRITE_REG + TX_ADDR,ADDRESS0, ADR_WIDTH); //写本地地址SPI_Write_Buf(WRITE_REG + RX_ADDR_P0,ADDRESS0,ADR_WIDTH); //频道0地址SPI_Write_Buf(WRITE_REG + RX_ADDR_P1,ADDRESS1,ADR_WIDTH); //频道1地址SPI_RW_Reg(WRITE_REG + EN_AA, 0x03); //频道0、1自动应答SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x03); //允许频道0、1SPI_RW_Reg(WRITE_REG + RF_CH, 0); //设置信道工作为2.4GHZ,收发必须一致SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //0接收数据长度SPI_RW_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH); //1接收数据长度SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB}/***************************************************************** *************************************//*函数:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)/*功能:数据读取后放如rx_buf接收缓冲区中/***************************************************************** *************************************/unsigned char nRF24L01_RxPacket(unsigned char* rx_buf){unsigned char revale=0;sta=SPI_Read(STATUS); //读取状态寄存其来判断数据接收状况if(RX_DR) //判断是否接收到数据{CE = 0;SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);revale =1;who=sta&0x0e;who|=0xf0; //通道0:who==0xf0;通道1:who==0xf2}SPI_RW_Reg(WRITE_REG+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志CSN=0;SPI_RW(FLUSH_RX);CSN=1;return revale;}void main(void){uchar i;uchar RxBuf[TX_PLOAD_WIDTH];init_NRF24L01() ;StartUART();ms(6000);while(1){//如果接收到数据,发往PCSetRX_Mode();if(nRF24L01_RxPacket(RxBuf)){R_S_Byte(who);ms(100);for(i=0;i<TX_PLOAD_WIDTH;i++){R_S_Byte(RxBuf[i]);ms(100);}}}}-------------------------------------------1----------------------------------------------------发送uint constADDRESS0[ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};其余与双工通信相同-------------------------------------------2----------------------------------------------------发送uint constADDRESS1[ADR_WIDTH]= {0xc4,0xc3,0xc2,0xc1,0xc0}; //频道1接收地址其余与双工通信相同以上就是简要的代码。

nRF24L01学习经验

nRF24L01学习经验

nRF24L01学习经验nRF24L01+nRF24L01+这个无线收发模块目前已经大致学习完毕,实现的功能以及各项参数:1~32字节数据的无线传输;5m的有效收发距离,1m的无遗漏收发距离;距离在5m内和5m外转变时,超出距离数据传输会自动中断,进入范围自动继续;实验中数据不丢失,无错误。

可用于短距离的数据传输和交互。

在通信模块的学习中,主要分为以下3个部分1、通过SPI配置nRF24L01+的寄存器因为nRF24L01+的寄存器配置只支持SPI总线,从无线板与MCU的连线情况看,单片机自带的SPI总线接口与无线板接口不匹配,所以要模拟一个SPI总线来进行控制,查找了一些SPI的总线描述,感觉SPI较I2C的时序更为简单,模拟SPI的过程中,遇到过一个问题,将所需要的函数全都写好,感觉时序也没有任何问题,可是寄存器就是写不进去,这个问题困扰了很久,感觉是时序的问题,但是函数中却找不出来,后来发现是模拟时钟的高低电平写反了。

Void SCK_H(void) {PORTB &= ~(1 << SCK);}Void SCK_L(void) {PORTB |= (1 << SCK);}这个问题导致时序错误而无法写入,而且纠错中不容易发现。

SPI的读写过程如下(读一个字节,写一个字节等就不贴出了):void write_reg(unsigned char address, unsigned char temp){unsigned char status = 0;PORTB &= ~BIT(CSN); //使能SPIstatus = spi_rw(address);//前8位写入地址跟读取状态寄存器write(temp);//写入一个字节PORTB |= BIT(CSN);}unsigned char read_reg(unsigned char address){unsigned char dat = 0;unsigned char status = 0;PORTB &= ~BIT(CSN); //使能SPIstatus = spi_rw(address);//前8位写入地址跟读取状态寄存器dat = read();//读取一个字节PORTB |= BIT(CSN);return dat;}SPI调通之后配置寄存器就只需要了解寄存器的作用就行了,24L01的寄存器也不算多,配置过程也就是理解寄存器作用的过程了。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第一次使用无线通信的芯片,第一次接触SPI总线时序,第一次遇到芯片有问题,很多的第一次,所以最后成功了我觉得很有意义,收获了很多,有必要用寥寥数字来记录一下。

最开始老板给的是一个NRF401的芯片,后来网上一查,这玩意早停产了,不过发现其操作和硬件接口非常简单,编程应该也非常简单,于是乎三下两下的接好电路,编好程序,上电一跑,晕了!完全没反应,一开始还怀疑自己的程序或者硬件电路哪里错了,DEBUG,查资料搞了好几天,最后确定自己没有搞错。

于是乎,又把401拿掉,直接用2根导线把两块板子的串行口接好,然后奇迹出现了,如同我设想的那样运行。

好吧,终于可以确定这2块不知放了多少年布满飞尘的401是坏的了。

然后上网继续寻找替代品,淘宝上一搜人气最高的是NRF24L01,本来还想买905的,不过哥相信群众,于是买了2块NRF24L01回来。

这个芯片的接口是SPI的接口,的确让我郁闷了一阵,以前从来没接触过这个玩意,而且一般的单片机哪有SPI接口,身边的一块ARM 板倒是有不过只有一块啊,于是又硬着头皮去看如何用普通IO口模拟出SPI的时序来操作NRF24L01,等搞明白了芯片也寄到了,又是一阵捣鼓,接好线,相当多的线,编好程序,相对401来说很长的程序。

一上电,又晕了,还是没反应。

然后就是无止境的调试,修改程序,整整花了一周多时间后终于遇到了曙光啊!一个网上的高手帮我用他那边的示波器分析了一下我的程序波形,说没有问题啊,然后另一个高手告诉我应该怎样来一步一步地调试这些芯片,比如先给芯片寄存器写一个值然后马上读出来,看是否写操作正确,等等。

这个经验之谈真是犹如黑夜里的一盏明灯啊,让我豁然开朗,马上照高手指点的一搞,结果出来了。

2块NRF24L01的其中一块根本写不进去数据,完全是坏的,哎!人品啦!(我承认是我太傻太天真了,以为老板发货的时候都会先帮我检查一遍)马上和淘宝上的老板沟通了一下,让我把坏的寄过去他检查如果确实是他们的原因他们负责再给我寄一个过来,同时包邮费。

好吧,我又等,等了一周老板来电话了通知我确实是他们的问题给我寄了一块坏的芯片,并给我重新寄来了一块好的。

然后继续等啊等,又是一周,东西终于来了。

这次哥颤抖着以迅雷不及掩耳盗铃儿响叮当之势再一次接好线,下好以前写好的程序,谢天谢地谢亚龙啊,这次总算测试通过,两块芯片都是好的了。

今天自己又写了一个发送与接收单工通信的测试程序,跑了一下。

恩,效果不错,看到接收端不停得把收到的数据显示在电脑上时内牛满面啊!这其中也有个小插曲,一开始接收的数组被我定义在了code段,结果发送端都能正确收到接收的应答信号,但接收端就是不能把数据写进接收数组里面,程序编译也通过。

后来一想才明白CODE内的代码是下载到flash中的,是修改不了的。

最后改成data修饰,终于能正常运行了。

当初我曾请一个调出来的网友把他的程序借我参考下,但他说这是公司的商业机密,不能给,哎,为了以后的同仁少走弯路,我把我调好的测试程序放上来。

#include <reg52.h>#include <intrins.h>#define MODE 0 //MODE=1时为发送代码 MODE=0时为接收代码typedef unsigned char uchar;//****************************************IO端口定义***************************************sbit MISO =P2^3;sbit MOSI =P2^2;sbit SCK =P2^1;sbit CE =P2^5;sbit CSN =P2^0;sbit IRQ =P3^2;sbit led = P1^2;//****************************************************************************** ************uchar bdata sta; //状态标志sbit RX_DR =sta^6;sbit TX_DS =sta^5;sbit MAX_RT =sta^4;//*********************************************NRF24L01************************* ************#define TX_ADR_WIDTH 5 // 5 uints TX address width#define RX_ADR_WIDTH 5 // 5 uints RX address width#define TX_PLOAD_WIDTH 32 // 32 uints TX payload#define RX_PLOAD_WIDTH 32 // 32 uints TX payloaduchar const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址uchar const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //接收地址uchar code Tx_Buf[TX_PLOAD_WIDTH]={0xff,0xee,0x11,0x22,0x33,0xaa,0xbb,0x11,0x22,0x33,0xaa,0 xbb,0x11,0x22,0x33,0xaa,0xbb,0x11,0x22,0x33,0xaa,0xbb,0x11,0x22,0x33,0xaa,0xbb,0x11,0x22,0x33, 0xee,0xff};//发送数据uchar Rx_Buf[RX_PLOAD_WIDTH];//接收数据//***************************************NRF24L01寄存器指令*******************************************************#define READ_REG 0x00 // 读寄存器指令#define WRITE_REG 0x20 // 写寄存器指令#define RD_RX_PLOAD 0x61 // 读取接收数据指令#define WR_TX_PLOAD 0xA0 // 写待发数据指令#define FLUSH_TX 0xE1 // 冲洗发送 FIFO指令#define FLUSH_RX 0xE2 // 冲洗接收 FIFO指令#define REUSE_TX_PL 0xE3 // 定义重复装载数据指令#define NOP 0xFF // 保留//*************************************SPI(nRF24L01)寄存器地址****************************************************#define CONFIG 0x00 // 配置收发状态,CRC校验模式以及收发状态响应方式#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 // 频道0接收数据地址#define RX_ADDR_P1 0x0B // 频道1接收数据地址#define RX_ADDR_P2 0x0C // 频道2接收数据地址#define RX_ADDR_P3 0x0D // 频道3接收数据地址#define RX_ADDR_P4 0x0E // 频道4接收数据地址#define RX_ADDR_P5 0x0F // 频道5接收数据地址#define TX_ADDR 0x10 // 发送地址寄存器#define RX_PW_P0 0x11 // 接收频道0接收数据长度#define RX_PW_P1 0x12 // 接收频道0接收数据长度#define RX_PW_P2 0x13 // 接收频道0接收数据长度#define RX_PW_P3 0x14 // 接收频道0接收数据长度#define RX_PW_P4 0x15 // 接收频道0接收数据长度#define RX_PW_P5 0x16 // 接收频道0接收数据长度#define FIFO_STATUS 0x17 // FIFO栈入栈出状态寄存器设置/******************************************延时函数********************************************************///长延时void Delay(unsigned int s){unsigned int i,j;for(i=0;i<1000;i++)for(j=0;j<s;j++);}//短延时void delay_ms(unsigned int x){unsigned int i,j;i=0;for(i=0;i<x;i++){j=108;;while(j--);}}/************************************IO 口模拟SPI总线代码************************************************/uchar SPI_RW(uchar byte){uchar bit_ctr;for(bit_ctr=0;bit_ctr<8;bit_ctr++){MOSI=(byte&0x80);byte=(byte<<1);SCK=1;byte|=MISO;//led=MISO;Delay(150);SCK=0;}return(byte);}uchar SPI_RW_Reg (uchar reg,uchar value) // 向寄存器REG写一个字节,同时返回状态字节{uchar status;CSN=0;status=SPI_RW(reg);SPI_RW(value);CSN=1;return(status);}uchar SPI_Read (uchar reg ){uchar reg_val;CSN=0;SPI_RW(reg);reg_val=SPI_RW(0);CSN=1;return(reg_val);}uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar bytes){uchar status,byte_ctr;CSN = 0; // Set CSN low, init SPI tranactionstatus = SPI_RW(reg); // Select register to write to and read status byte for(byte_ctr=0; byte_ctr<bytes; byte_ctr++) // then write all byte in buffer(*pBuf)SPI_RW(*pBuf++);CSN = 1; // Set CSN high againreturn(status); // return nRF24L01 status byte}#if MODE/*******************************发*****送*****模*****式*****代*****码*************************************/void TX_Mode(void){CE=0;SPI_RW_Reg(FLUSH_TX,0x00);SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // Writes TX_Address to nRF24L01SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.AckSPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...1aSPI_RW_Reg(WRITE_REG + RF_CH, 40); // Select RF channel 40SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); // TX_PWR:0dBm, Datarate:1Mbps, LNA:HCURRSPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为2字节SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);CE=1;delay_ms(100);}void Transmit(unsigned char * tx_buf){CE=0; //StandBy I模式SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址SPI_RW_Reg(FLUSH_TX,0x00);SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // 装载数据SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ收发完成中断响应,16位CRC,主发送CE=1; //置高CE,激发数据发送delay_ms(150);}#else/*******************************接*****收*****模*****式*****代*****码*************************************/uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars){uchar status,uchar_ctr;CSN = 0; // Set CSN low, init SPI tranactionstatus = SPI_RW(reg); // Select register to write to and read status ucharfor(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)pBuf[uchar_ctr] = SPI_RW(0); //CSN = 1;return(status); // return nRF24L01 status uchar}/******************************************************************************* ***********************//*函数:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)/*功能:数据读取后放如rx_buf接收缓冲区中/******************************************************************************* ***********************/unsigned char nRF24L01_RxPacket(unsigned char* rx_buf){unsigned char revale=0;sta=SPI_Read(STATUS); // 读取状态寄存其来判断数据接收状况if(RX_DR) // 判断是否接收到数据{//CE = 0; //SPI使能SPI_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH);// read receive payload from RX_FIFO bufferrevale =1; //读取数据完成标志//Delay(100);}SPI_RW_Reg(WRITE_REG+STATUS,sta); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志return revale;}/******************************************************************************* *********************//*函数:void RX_Mode(void)/*功能:数据接收配置/******************************************************************************* *********************/void RX_Mode(void){CE=0;SPI_RW_Reg(FLUSH_RX,0x00);//SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // Writes TX_Address to nRF24L01SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.AckSPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0//SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...1a SPI_RW_Reg(WRITE_REG + RF_CH, 40); // Select RF channel 40SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为2字节SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); // TX_PWR:0dBm, Datarate:1Mbps, LNA:HCURRSPI_RW_Reg(WRITE_REG + CONFIG, 0x0F);CE=1;delay_ms(130);}//************************************串口初始化*********************************************************void StartUART( void ){ //波特率9600SCON = 0x50;TMOD = 0x20;TH1 = 0xFD;TL1 = 0xFD;PCON = 0x00;TR1 = 1;}//************************************通过串口将接收到数据发送给PC端**************************************void R_S_Byte(uchar R_Byte){SBUF = R_Byte;while( TI == 0 ); //查询法TI = 0;}#endif//************************************主函数************************************************************void main(){int i=0;CE=0;SCK=0;CSN=1;P1=0x00;#if MODE //发送模式代码TX_Mode();//SPI_RW_Reg(FLUSH_RX,0x00);while(1){Transmit(Tx_Buf);Delay(10);sta=SPI_Read(READ_REG + STATUS);if(TX_DS){P1=sta; //8位LED显示当前STATUS状态发送中断应使bit5 = 1 灯灭 Delay(100);SPI_RW_Reg(WRITE_REG + STATUS,sta);}if(MAX_RT) //如果是发送超时{P1=0x0f; //发送超时时 8位LED灯 bit4 = 1 灯灭Delay(150);SPI_RW_Reg(WRITE_REG + STATUS,sta);}}#else //接收模式代码StartUART();RX_Mode();Delay(0);//防止编译警告while(1){if(nRF24L01_RxPacket(Rx_Buf)){for(i=0;i<TX_PLOAD_WIDTH;i++)R_S_Byte(Rx_Buf[i]);}}#endif}。

相关文档
最新文档