NFR24L01模块

一、引脚定义

CE:使能控制,当CE=0,芯片处于待机模式,当CE=1时,芯片处于工作模式(发射模式、接收模式),只有当CE=0时才能切换模式,CE=1不能切换工作模式。(根据程序接A2)。

CSN:SPI片选功能,相当于SPI的CS,在给芯片写入命令时,需要先将CSN置0。(根据代码接A4)。

SCK:SPI通信的时钟线。(根据程序接A5)

MOSI:(Master Out Slave In的简写),主机输出从机输入,对于STM32来说是输出,对于NFR24L01来说是输入。(根据程序接A7)

MISO:主机输入从机输出,对于STM32来说是输入,对于NFR24L01来说是输出,STM32通过这个引脚可以读取接收到的数据。(根据程序接A6)

IRQ:中断引脚,当接收到数据或者应答信号后,IRQ会置0。(根据程序接A2)

二、工作模式

1、掉电模式:无论在哪种工作模式,只要将寄存器的PWR_UP置0,都会切换成掉电模式。

2、待机模式:PWR_UP置1,同时将CE引脚置0,接收模式或者发送模式就会切换成待机模式。

3、发送模式:CE=1且PRIM_RX=0,从待机模式切换成发射模式。

4、接收模式:CE=0且PRIM_RX=1,待机模式切换成接收模式。

三、主要命令

  • 每次通讯由两部分内容组成:指令格式+数据
  • 下图为指令格式(命令+寄存器地址)
  • 四、重要的寄存器

  • 4.1  Config寄存器

  • PWR_UP和PRIM_RX用来配置工作模式,这在工作模式中已经讲过

  • 4.2 自动应答寄存器

  • 在后面的代码部分,由于用的是通道0,所以配置成0x01。

  • 4.3 状态寄存器

  • 4.4  6个接收通道地址

  • NFR24L01有6个接收通道和一个发送通道。

  • 4.5  发送地址

  • 必须要跟接收通道地址配置成相同

  • 4.6 工作频率寄存器

  • 工作频率的设置范围是0~128,计算公式如下:

  • F0的最高频率为:2400+128MHz/1024 = 2.52GHz,跟手册上的范围一致。

  • 五、数据帧的发送和接收流

  • 5.1 发送地址和接收地址的配置,一定要配置成一样的,地址宽度通常为5个字节,这里为了展示方便,就画了一个字节的地址,代码里用了5个字节的0xF0。

    5.2  TX_FIFO里的数据是0x66,这是要发送的数据。

    5.3  CONFIG配置的意思(发送数据、接收数据、达到最大重复发送次数都会产生中断,使用16位CRC校验,左边是发送模式,右边是接收模式

    5.4  STATUS配置中的3个1表示RX_FIFO为空。

    5.5  EN_AA配置表示开启了通道0的应答。

    5.6 发送端:当配置好相应的寄存器后,将TX_FIFO里的数据发送出去,同时置IQR=0,告诉MCU数据已经发送出去,同时置STATUS寄存器中的TX_DS为1,同时,NFR24L01从发射模式变为接收模式,用来接收应答信号,接收到应答信号后又会变成发送模式,这中间模式的切换都要在CE=0时切换。

    5.7  接收端:当配置好相应的寄存器后,接收从发送端发送过来的数据,这时,RX_FIFO的数据就会变成0x66,同时,NFR24L01从接收模式切换为发送模式,发送应答信号,接收到数据后也会将IRQ置为0,告诉MCU已经接收到信号,可以将数据搬运走。状态寄存器STATUS中的RX_DS置1。状态寄存器中的标志位需要重新写入1(而不是写0,这是手册中的规定),才能变成0。

  • 六、代码

  • MySPI.c
  • #include "stm32f10x.h"                  // Device header
    
    /* 引脚定义 */
    #define SPI_CLK     GPIO_Pin_5
    #define SPI_MISO    GPIO_Pin_6   //主机输入、从机输出
    #define SPI_MOSI    GPIO_Pin_7
          
    //void MySPI_W_CS(uint8_t BitValue)
    //{
    //	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
    //}
    
    void MySPI_Init()
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    // 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //这里一定要初始化为推挽输出
    //	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    // 	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //这里一定要初始化为复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin = SPI_CLK | SPI_MOSI;    //SCK和MOSI要配置成复用推挽输出
     	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin = SPI_MISO;
     	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	SPI_InitTypeDef SPI_InitStructure;
    	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;    //选择波特率
    	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;     //第一个变化沿采样数据
    	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;      //默认低电平,Low和1Edge配合起来就是模式0
    	SPI_InitStructure.SPI_CRCPolynomial = 7;      //CRC校验位,给默认值
    	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;     //发送数据的位数,一般选择8位
    	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    //双线全双工模式
    	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;    //高位先行
    	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;        //SMT32作为主机
    	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;           //SS通过软件模拟的方式来实现
    	SPI_Init(SPI1,&SPI_InitStructure);
    	
    	SPI_Cmd(SPI1,ENABLE);
    	
    //	MySPI_W_CS(1);
    }

    MySPI.h

  • #ifndef __MYSPI_H
    #define __MYSPI_H
    
    void MySPI_Init(void);
    //void MySPI_Start(void);
    //void MySPI_Stop(void);
    uint8_t MySPI_SwapData(uint8_t ByteSend);
    
    #endif

    NFR24L01.c

  • void NFR24L01_Init()
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //上拉输入模式
    	GPIO_InitStructure.GPIO_Pin = NFR24L01_IRQ;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出模式
    	GPIO_InitStructure.GPIO_Pin = NFR24L01_CE | NFR24L01_CS;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	GPIO_SetBits(GPIOA,NFR24L01_CE | NFR24L01_CS | NFR24L01_IRQ);
    	
    	MySPI_Init();
    }
    
    void NFR24L01_Write_CS(uint8_t BitValue)   //控制从设备是否被选中
    {
    	GPIO_WriteBit(GPIOA, NFR24L01_CS, (BitAction)BitValue);
    }
    
    void NFR24L01_Write_CE(uint8_t BitValue)   //使能,当写入0则为空闲模式,当写入1则为发射或接收模式
    {
    	GPIO_WriteBit(GPIOA, NFR24L01_CE, (BitAction)BitValue);
    }
    
    uint8_t NFR24L01_Read_IQR()   //当读到0时说明发送成功或接收成功
    {
    	return GPIO_ReadInputDataBit(GPIOA,NFR24L01_IRQ);
    }
    
    uint8_t NFR24L01_Write(uint8_t Command,uint8_t Data)
    {
    	uint8_t status;
    	NFR24L01_Write_CS(0);   //start
    	status = MySPI_SwapData(Command);    // 发送命令
    	MySPI_SwapData(Data);    //发送数据
    	NFR24L01_Write_CS(1);   //stop
    	return status;
    }
    
    uint8_t NFR24L01_Read(uint8_t Command)
    {
    	uint8_t Data;
    	NFR24L01_Write_CS(0);   //start
    	MySPI_SwapData(Command);    // 发送命令
    	Data = MySPI_SwapData(0xFF);    //交换数据
    	NFR24L01_Write_CS(1);   //stop
    	return Data;
    }
    
    uint8_t NFR24L01_Write_Buffer(uint8_t Command,uint8_t *buf,uint8_t length)
    {
    	uint8_t status,i;
    	NFR24L01_Write_CS(0);   //start
    	
    	status = MySPI_SwapData(Command);   //写命令
    	for(i=0;i<length;i++)
    	{
    		MySPI_SwapData(buf[i]);    //写数据
    	}
    	
    	NFR24L01_Write_CS(1);   //stop
    	return status;
    }
    
    uint8_t NFR24L01_Read_Buffer(uint8_t Command,uint8_t *buf,uint8_t length)
    {
    	uint8_t status,i;
    	NFR24L01_Write_CS(0);   //start
    	
    	status = MySPI_SwapData(Command);
    	for(i=0;i<length;i++)
    	{
    		buf[i] = MySPI_SwapData(0xFF);
    	}
    	
    	NFR24L01_Write_CS(1);   //stop
    	return status;
    }
    
    void NFR24L01_Set_Mode(uint8_t Mode)
    {
    	NFR24L01_Write_CE(0);  //在配置之前都要将CE置0,否则无法更改配置
    	NFR24L01_Write_Buffer(SPI_WRITE_REG+TX_ADDR,T_Addr,5);   //写TX节点地址
    	NFR24L01_Write_Buffer(SPI_WRITE_REG+RX_ADDR_P0,R_Addr,5);   //写RX通道0的地址
    	NFR24L01_Write(SPI_WRITE_REG+EN_AA,0x01);      //开启通道0的自动应答
    	NFR24L01_Write(SPI_WRITE_REG+EN_RXADDR,0x01);    //开启通道0的接收地址
    	NFR24L01_Write(SPI_WRITE_REG+SETUP_RETR,0x25);   //设置自动重发间隔时间:750us+86us ;最大自动重发次数:5次
    	NFR24L01_Write(SPI_WRITE_REG+RF_CH,0x00);        //配置频率
    	NFR24L01_Write(SPI_WRITE_REG+RX_PW_P0,32);       //配置通道0的接收字节宽度
    	NFR24L01_Write(SPI_WRITE_REG+CONFIG,Mode);       //配置成发送模式
    	NFR24L01_Write_CE(1);
    }
    
    
    uint8_t NFR24L01_Send(uint8_t *buf)
    {
    	uint8_t state;
    	
    	NFR24L01_Write_CE(0);
    	NFR24L01_Write_Buffer(WR_TX_PLOAD,buf,32);
    	NFR24L01_Write_CE(1);  //配置成发送模式
    	
    	while(NFR24L01_Read_IQR() == SET);   //等待发送发送完成,发送完成后会产生中断信号,IQR由1变成0
    	state = NFR24L01_Read(SPI_READ_REG+STATUS);   //读取状态寄存器
    	NFR24L01_Write(SPI_WRITE_REG+STATUS,state);
    	
    	if(state & MAX_TX)   //如果达到最多重发次数
    	{
    		NFR24L01_Write(FLUSH_TX,0xFF);
    		return MAX_TX;
    	}
    	if(state & TX_OK)
    	{
    		return TX_OK;
    	}
    	return 0xFF;  //发送失败
    }
    
    uint8_t NFR24L01_Receive(uint8_t *buf)
    {
    	uint8_t state;
    	
    	NFR24L01_Write_CE(1);
    	while(NFR24L01_IRQ == SET);
    	NFR24L01_Write_CE(0);   //等待接收数据
    	
    	state = NFR24L01_Read(SPI_READ_REG+STATUS);
    	NFR24L01_Write(SPI_WRITE_REG+STATUS,state);   //清楚标记位
    	
    	if(state & RX_OK)
    	{
    		NFR24L01_Read_Buffer(RD_RX_PLOAD,buf,32);
    		NFR24L01_Write(FLUSH_RX,0xFF);
    		return RX_OK;
    	}
    	return 0;   //接收失败
    }

    NFR24L01.h

  • #ifndef __NFR24L01_H
    #define __NFR24L01_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    /* 引脚定义 */
    #define NFR24L01_CE      GPIO_Pin_3    //CE引脚,使能控制
    #define NFR24L01_CS      GPIO_Pin_4    //片选引脚
    #define NFR24L01_IRQ     GPIO_Pin_2   //中断引脚
    
    /* NFR24L01寄存器命令 */
    #define SPI_READ_REG    0x00  //读配置寄存器,低5位为寄存器地址
    #define SPI_WRITE_REG   0x20  //写配置寄存器,低5位为寄存器地址
    #define RD_RX_PLOAD     0x61  //读RX有效数据(低字节先出),1~32字节
    #define WR_TX_PLOAD     0xA0  //写TX有效数据,1~32字节
    #define FLUSH_TX        0xE1  //清除TX FIFO寄存器.发射模式下用
    #define FLUSH_RX        0xE2  //清除RX FIFO寄存器.接收模式下用
    #define REUSE_TX_PL     0xE3  //重新使用上一包数据,CE为高,数据包被不断发送
    #define RD_RX_PL_WID    0x60  //读RX有效数据(高字节先出),1~32字节
    #define W_ACK_PLOAD     0xA0  //发送寄存器,写入数据可发送出去
    #define W_TX_PLOAD_NACK 0xB0  //发送寄存器,写入数据可发送出去,但不应答
    #define RF_NOP          0xFF  //空操作,可以用来读状态寄存器
    
    /* 寄存器地址 */
    #define CONFIG          0x00  //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能;
                                  //bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能
    #define EN_AA           0x01  //使能自动应答功能  bit0~5,对应通道0~5
    #define EN_RXADDR       0x02  //接收地址允许,bit0~5,对应通道0~5
    #define SETUP_AW        0x03  //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节;
    #define SETUP_RETR      0x04  //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us
    #define RF_CH           0x05  //RF通道,bit6:0,工作通道频率;
    #define RF_SETUP        0x06  //RF寄存器;bit5,bit3:传输速率(00:1Mbps,01:2Mbps,10:250Kbps);bit2:1,发射功率;bit0:低噪声放大器增益
    #define STATUS          0x07  //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发
                                  //bit5:数据发送完成中断;bit6:接收数据中断;
    #define OBSERVE_TX      0x08  //发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器
    #define CD              0x09  //载波检测寄存器,bit0,载波检测;
    #define RX_ADDR_P0      0x0A  //数据通道0接收地址,最大长度5个字节,低字节在前
    #define RX_ADDR_P1      0x0B  //数据通道1接收地址,最大长度5个字节,低字节在前
    #define RX_ADDR_P2      0x0C  //数据通道2接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
    #define RX_ADDR_P3      0x0D  //数据通道3接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
    #define RX_ADDR_P4      0x0E  //数据通道4接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
    #define RX_ADDR_P5      0x0F  //数据通道5接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
    #define TX_ADDR         0x10  //发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等
    #define RX_PW_P0        0x11  //接收数据通道0有效数据宽度(1~32字节),设置为0则非法
    #define RX_PW_P1        0x12  //接收数据通道1有效数据宽度(1~32字节),设置为0则非法
    #define RX_PW_P2        0x13  //接收数据通道2有效数据宽度(1~32字节),设置为0则非法
    #define RX_PW_P3        0x14  //接收数据通道3有效数据宽度(1~32字节),设置为0则非法
    #define RX_PW_P4        0x15  //接收数据通道4有效数据宽度(1~32字节),设置为0则非法
    #define RX_PW_P5        0x16  //接收数据通道5有效数据宽度(1~32字节),设置为0则非法
    #define FIFO_STATUS     0x17  //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留
                                  //bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环;
    
    /* 无线收发中断标志 */
    #define MAX_TX  	    0x10    //达到最大发送次数中断
    #define TX_OK       	0x20    //TX发送完成中断
    #define RX_OK   	    0x40    //接收到数据中断
    
    void NFR24L01_Init(void);
    uint8_t NFR24L01_Write_Buffer(uint8_t Command,uint8_t *buf,uint8_t length);
    uint8_t NFR24L01_Read_Buffer(uint8_t Command,uint8_t *buf,uint8_t length);
    void NFR24L01_Set_Mode(uint8_t Mode);
    uint8_t NFR24L01_Send(uint8_t *buf);
    uint8_t NFR24L01_Receive(uint8_t *buf);
    uint8_t NFR24L01_Write(uint8_t Command,uint8_t Data);
    uint8_t NFR24L01_Read(uint8_t Command);
    uint8_t NFR24L01_Read_IQR(void);
    
    #endif
    

    发送端main.c

  • #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "NFR24L01.h"
    
    uint8_t data_buffer[32] = {0xA5,0x66,0x99,0xFF,0x54,0x32};
    
    int main()
    {
    	OLED_Init();
    	NFR24L01_Init();
    	NFR24L01_Set_Mode(0x0E);
    	OLED_ShowString(1,1,"Init OK");
    	
    	while(1)
    	{
    
    		
    		NFR24L01_Send(data_buffer);
    	}
    }

    接收端main.c

  • #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "NFR24L01.h"
    
    uint8_t data[32] = {0};
    
    int main()
    {
    	OLED_Init();
    	NFR24L01_Init();
    	NFR24L01_Set_Mode(0x0F);
    	OLED_ShowString(1,1,"Init OK");
    	
    	while(1)
    	{
    		if(NFR24L01_Read_IQR() == 0)
    		{
    			NFR24L01_Receive(data);
    		}
    		OLED_ShowHexNum(2,1,data[0],2);
    		OLED_ShowHexNum(2,4,data[1],2);
    		OLED_ShowHexNum(2,7,data[2],2);
    		OLED_ShowHexNum(3,1,data[3],2);
    		OLED_ShowHexNum(3,4,data[4],2);
    		OLED_ShowHexNum(3,7,data[5],2);
    		OLED_ShowHexNum(4,1,data[6],2);
    		OLED_ShowHexNum(4,4,data[7],2);
    		OLED_ShowHexNum(4,7,data[8],2);
    	}
    }

  • 55
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值