打印
[其他ST产品]

stm32驱动NRF24L01_原理+代码解析

[复制链接]
楼主: 自动化陈稳
手机看帖
扫描二维码
随时随地手机跟帖
41
自动化陈稳|  楼主 | 2023-7-8 16:46 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
这里调用指针实际上缩短了运行时间

使用特权

评论回复
42
自动化陈稳|  楼主 | 2023-7-8 16:50 | 只看该作者
*NRF24L01_Write_Buf
//在指定位置写指定长度的数据
//reg:寄存器(位置)
//*pBuf:数据指针
//len:数据长度
//返回值,此次读到的状态寄存器值
u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len)
{
        u8 status,u8_ctr;            
        NRF24L01_CSN = 0;          //使能SPI传输
          status = SPI1_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值
          for(u8_ctr=0; u8_ctr<len; u8_ctr++)SPI1_ReadWriteByte(*pBuf++); //写入数据         
          NRF24L01_CSN = 1;       //关闭SPI传输
          return status;          //返回读到的状态值
}                       

使用特权

评论回复
43
自动化陈稳|  楼主 | 2023-7-8 16:50 | 只看该作者
*NRF24L01_TxPacket
//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:发送完成状况
u8 NRF24L01_TxPacket(u8 *txbuf)
{
        u8 sta;
        SPI1_SetSpeed(SPI_BaudRatePrescaler_8);//spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)   
        NRF24L01_CE=0;
          NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
        NRF24L01_CE=1;//启动发送          
        while(NRF24L01_IRQ!=0);//等待发送完成
        sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值          
        NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
        if(sta&MAX_TX)//达到最大重发次数
        {
                NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器
                return MAX_TX;
        }
        if(sta&TX_OK)//发送完成
        {
                return TX_OK;
        }
        return 0xff;//其他原因发送失败
}

使用特权

评论回复
44
自动化陈稳|  楼主 | 2023-7-8 16:51 | 只看该作者
先把CE置低进入待机模式1,前面说过写寄存器要处于掉电或待机模式

在Enhanced ShockBurstTM发送模式下,置CE为高,至少10us,将使能发送过程。

while(NRF24L01_IRQ!=0);//等待发送完成

前面提过IRQ在三种情况下变为低电平,其中有“Tx FIFO 发完并且收到ACK(使能ACK情况下)”

也就是NRF24L01_IRQ=0时,发送完成。

使用特权

评论回复
45
Stahan| | 2023-7-8 16:51 | 只看该作者
为啥调用指针会缩短运行时间啊?

使用特权

评论回复
46
自动化陈稳|  楼主 | 2023-7-8 16:51 | 只看该作者
sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值     

发完后读STATUS的值,MAX_TX在.h中定义为0x10,TX_OK是0x20

使用特权

评论回复
47
自动化陈稳|  楼主 | 2023-7-8 16:51 | 只看该作者
照着 STATUS的图看上面的代码再结合宏定义,是不是
其实后面的函数都是一样的,这么看就行

使用特权

评论回复
48
自动化陈稳|  楼主 | 2023-7-8 16:51 | 只看该作者
*NRF24L01_RxPacket
//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:0,接收完成;其他,错误代码
u8 NRF24L01_RxPacket(u8 *rxbuf)
{
        u8 sta;                                                                              
        SPI1_SetSpeed(SPI_BaudRatePrescaler_8); //spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)   
        sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值             
        NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
        if(sta&RX_OK)//接收到数据
        {
                NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
                NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器
                return 0;
        }          
        return 1;//没收到任何数据
}                                            

使用特权

评论回复
49
自动化陈稳|  楼主 | 2023-7-8 16:51 | 只看该作者
*NRF24L01_RX_Mode和NRF24L01_TX_Mode
//该函数初始化NRF24L01到RX模式
//设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
//当CE变高后,即进入RX模式,并可以接收数据了                  
void NRF24L01_RX_Mode(void)
{
        NRF24L01_CE=0;          
          NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
          
          NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);            //使能通道0的自动应答   
          NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);        //使能通道0的接收地址           
          NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);                    //设置RF通信频率                  
          NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度             
          NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);       
    //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
   
          NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);               
    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式

          NRF24L01_CE = 1; //CE为高,进入接收模式
}                                                 
//该函数初始化NRF24L01到TX模式
//设置TX地址,写TX数据宽度,设置RX自动应答的地址,填充TX发送数据,选择RF频道,波特率和LNA HCURR
//PWR_UP,CRC使能
//当CE变高后,即进入RX模式,并可以接收数据了                  
//CE为高大于10us,则启动发送.         
void NRF24L01_TX_Mode(void)
{                                                                                                                 
        NRF24L01_CE=0;            
          NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址
          NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
   //设置TX节点地址,主要为了使能ACK          

          NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答   
          NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
          NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
    //设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次

          NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40
          NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  
    //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
   
          NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);   
    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断

        NRF24L01_CE=1;//CE为高,10us后启动发送
}

使用特权

评论回复
50
自动化陈稳|  楼主 | 2023-7-8 16:52 | 只看该作者
单纯从发送一次数据需要调用的函数钻一次我认为体验感会比较好

初始化部分略过,这是个完整的发送流程,包括显示之类的。

使用特权

评论回复
51
自动化陈稳|  楼主 | 2023-7-8 16:52 | 只看该作者
从原子给的例程开始吧 (LCD什么的就不解释了)

NRF24L01_TX_Mode();

初始化为发送模式



使用特权

评论回复
52
自动化陈稳|  楼主 | 2023-7-8 16:52 | 只看该作者
第194行,CE置低,进入待机模式1

第195行,给TX_ADDR写5字节宽度的地址,这是.c里的

const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址

使用特权

评论回复
53
自动化陈稳|  楼主 | 2023-7-8 16:53 | 只看该作者
第196行,给RX_ADDR_P0写5字节宽度的地址,前面提过有三个地址是一样的

第198行,赋值寄存器EN_AA 0x01,使能通道0的ACK

使用特权

评论回复
54
自动化陈稳|  楼主 | 2023-7-8 16:53 | 只看该作者
第200行,赋值SETUP_RETR 0x1a(0001 1010),重发10次,延时86+250*2微秒

使用特权

评论回复
55
自动化陈稳|  楼主 | 2023-7-8 16:53 | 只看该作者
第201行,射频频率设置寄存器(RF_CH,0X05)

频率计算公式:2400+RF_CH  (Mhz),给的40,也就是2440MHz

使用特权

评论回复
56
自动化陈稳|  楼主 | 2023-7-8 16:53 | 只看该作者
第202行,赋值RF_SETUP 0x0f(0000 1111)

使用特权

评论回复
57
自动化陈稳|  楼主 | 2023-7-8 16:54 | 只看该作者
第203行,CONFIG寄存器0x0e(0000 1110),打开了三个中断


使用特权

评论回复
58
自动化陈稳|  楼主 | 2023-7-8 16:54 | 只看该作者
第204行,CE置高

在Enhanced ShockBurstTM发送模式下,置CE为高,至少10us,将使能发送过程。

使用特权

评论回复
59
自动化陈稳|  楼主 | 2023-7-8 16:55 | 只看该作者

使用特权

评论回复
60
自动化陈稳|  楼主 | 2023-7-8 16:55 | 只看该作者
也就是说过了NRF24L01_TX_Mode();大概10us后,发送将开始,接下来算的是发送内容

进入while(1)到

if(NRF24L01_TxPacket(tmp_buf)==TX_OK)

这句主要的点就是它把发送内容的首地址传进去了,因为NRF24L01_TxPacket返回的值与它从STATUS寄存器里读出的值有关系

设置SPI的速度;置CE为低,进入待机模式1;写发送内容;CE再置高启动发送;前面提到过IRQ的状态;读STATUS的值;根据STATUS的值返回不同内容,返TX_OK就是发完了的标志,可以继续发了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则