NRF24L01是一款工作在2.4-2.5GHz世界通用ISM频段的单片收发芯片, 使用4线SPI通讯端口,通讯速率最高可达8Mbps,适合与各种MCU连接,编程简单;输出功率、频道选择和协议的设置可以通过SPI接口设置极低的电流消耗,当工作在发射模式下发射功率为6dBm时电流消耗为9.0mA接受模式为12.3mA掉电模式和待机模式下电流消耗模式更低。
一、模块来源
采购链接:
NRF24L01+ 无线发射接收模块 2.4G数传收发通信模块 改进功率加强
资料下载链接:
https://pan.baidu.com/s/1CUQ3SOdnmD8xSXMdR4YopA
资料提取码:1234
二、规格参数
工作电压:1.9~3.6V
供电电流:900 ~ 12.3mA
最大数据传输率:2000 Kbps
控制方式:SPI
管脚数量:8 Pin(2.54mm间距排针)
以上信息见厂家资料文件
三、移植过程
我们的目标是将例程移植至开发板上【实现无线的数据传输的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
1、查看资料
接收方式
NRF24L01的接收端是靠IRQ引脚进行判断,当IRQ为高电平时,说明接收到了数据,IRQ为1则是正在等待数据。因此可以根据IRQ引脚来决定接收的方式。这里提供轮询方式和中断方式。
轮询方式接收
采用轮询方式会阻碍其他任务的运行,因接收数据要时时刻刻判断IRQ引脚是否为高电平,会一直占用MCU的时间。为了解决因为没有接收到数据就卡死问题以及防止错过数据没有接收问题,在等待数据的过程中,加入了超时判断,当一定的时间内没有接收到数据,则结束等待接收,去运行其他任务。
中断方式接收
采用中断方式接收数据,是通过将IRQ引脚设置为外部中断功能。 当检测到IRQ引脚有变化时,则接收数据。根据24L01的要求,当接收完数据后,必须清除接收的FIFO。
2、引脚选择
引脚说明
想要使用硬件SPI驱动,需要确定使用的引脚是否有SPI外设功能。可以通过数据手册进行查看。
当前使用的是硬件SPI接口,而NRF24L01我们需要与它发送数据也需要接收数据,故使用的是4线的SPI,使用到了时钟线SCK、主机输出从机输入线MOSI、主机输入从机输出线MISO和软件控制的片选线NSS。所以除了这些引脚需要使用硬件SPI功能的引脚外,其他引脚都可以使用开发板上其他的GPIO。
这里选择使用PA4/PA5/PA6的SPI复用功能
3、移植至工程
接下来我们配置 SYSCONFIG
- 双击 empty.syscfg 文件,打开它。
- 在 empty.syscfg 文件界面点击 Tools,然后点击 SYSCONFIG 工具。
- 点击 ADD 添加SPI配置
- 添加配置SPI【根据下方图片进行添加】
- 添加GPIO配置
添加CSN:
添加CE:
添加IRQ + 外部中断:
- 点击保存
WARNING
出现只要出现下面的框就一定要选择:Yes to All
- 然后点击编译(可能会报错,我们不用管!)
- 然后我们所有设定的引脚和功能就会在 ti_msp_dl_config.h 中定义。因为这个文件我们包含进了 board.h 所以我们只需要引用 board.h 即可。【这里的 board.h 就充当了芯片头文件的作用】
移植步骤中的导入.c和.h文件与传感器章节的【DHT11温湿度传感器】相同,只是将.c和.h文件更改为drv_spi.c、drv_spi.h、NRF24L01.c和NRF24L01.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件drv_spi.c中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-05-30 LCKFB-LP first version
*/
#include "drv_spi.h"
#include <stdio.h>
/** 硬件SPI */
#define SPI_WAIT_TIMEOUT ((uint16_t)0xFFFF)
/**
* @brief :SPI初始化(硬件)
* @param :无
* @note :无
* @retval:无
*/
void drv_spi_init( void )
{
}
/**
* @brief :SPI收发一个字节
* @param :
* @TxByte: 发送的数据字节
* @note :非堵塞式,一旦等待超时,函数会自动退出
* @retval:接收到的字节
*/
uint8_t drv_spi_read_write_byte( uint8_t TxByte )
{
uint8_t l_Data = 0;
uint16_t timeOut = 1000;
//发送数据
DL_SPI_transmitData8(SPI_INST, TxByte);
//等待SPI总线空闲
while(DL_SPI_isBusy(SPI_INST))
{
if(timeOut <= 0)
{
printf("TransmitData TIMEOUT!! : %d\r\n",__LINE__);
break;
}
timeOut--;
delay_us(2);
}
l_Data = DL_SPI_receiveData8(SPI_INST);//读取接收数据
timeOut = 500;
//等待SPI总线空闲
while(DL_SPI_isBusy(SPI_INST))
{
if(timeOut <= 0)
{
printf("ReceiveData TIMEOUT!! : %d\r\n",__LINE__);
break;
}
timeOut--;
delay_us(2);
}
return l_Data; //返回
}
/**
* @brief :SPI收发字符串
* @param :
* @ReadBuffer: 接收数据缓冲区地址
* @WriteBuffer:发送字节缓冲区地址
* @Length:字节长度
* @note :非堵塞式,一旦等待超时,函数会自动退出
* @retval:无
*/
void drv_spi_read_write_string( uint8_t* ReadBuffer, uint8_t* WriteBuffer, uint16_t Length )
{
spi_set_nss_low( );//拉低片选
while( Length-- )
{
*ReadBuffer = drv_spi_read_write_byte( *WriteBuffer ); //收发数据
ReadBuffer++;
WriteBuffer++; //读写地址加1
}
spi_set_nss_high( );//拉高片选
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
在文件drv_spi.h中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-05-30 LCKFB-LP first version
*/
#ifndef __DRV_SPI_H__
#define __DRV_SPI_H__
#include "board.h"
#define spi_set_nss_high( ) DL_GPIO_setPins(GPIO_PORT, GPIO_CS_PIN)
#define spi_set_nss_low( ) DL_GPIO_clearPins(GPIO_PORT, GPIO_CS_PIN)
void drv_spi_init( void );
uint8_t drv_spi_read_write_byte( uint8_t TxByte );
void drv_spi_read_write_string( uint8_t* ReadBuffer, uint8_t* WriteBuffer, uint16_t Length );
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在文件NRF24L01.c中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-05-30 LCKFB-LP first version
*/
#include "NRF24L01.h"
#include "stdio.h"
const char *g_ErrorString = "RF24L01 is not find !...";
void drv_delay_500Ms( unsigned int ms)
{
while(ms--)
{
delay_ms(500);
}
}
/**
* @brief :NRF24L01读寄存器
* @param :
@Addr:寄存器地址
* @note :地址在设备中有效
* @retval:读取的数据
*/
uint8_t NRF24L01_Read_Reg( uint8_t RegAddr )
{
uint8_t btmp;
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( NRF_READ_REG | RegAddr ); //读命令 地址
btmp = drv_spi_read_write_byte( 0xFF ); //读数据
RF24L01_SET_CS_HIGH( ); //取消片选
return btmp;
}
/**
* @brief :NRF24L01读指定长度的数据
* @param :
* @reg:地址
* @pBuf:数据存放地址
* @len:数据长度
* @note :数据长度不超过255,地址在设备中有效
* @retval:读取状态
*/
void NRF24L01_Read_Buf( uint8_t RegAddr, uint8_t *pBuf, uint8_t len )
{
uint8_t btmp;
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( NRF_READ_REG | RegAddr ); //读命令 地址
for( btmp = 0; btmp < len; btmp ++ )
{
*( pBuf + btmp ) = drv_spi_read_write_byte( 0xFF ); //读数据
}
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :NRF24L01写寄存器
* @param :无
* @note :地址在设备中有效
* @retval:读写状态
*/
void NRF24L01_Write_Reg( uint8_t RegAddr, uint8_t Value )
{
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( NRF_WRITE_REG | RegAddr ); //写命令 地址
drv_spi_read_write_byte( Value ); //写数据
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :NRF24L01写指定长度的数据
* @param :
* @reg:地址
* @pBuf:写入的数据地址
* @len:数据长度
* @note :数据长度不超过255,地址在设备中有效
* @retval:写状态
*/
void NRF24L01_Write_Buf( uint8_t RegAddr, uint8_t *pBuf, uint8_t len )
{
uint8_t i;
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( NRF_WRITE_REG | RegAddr ); //写命令 地址
for( i = 0; i < len; i ++ )
{
drv_spi_read_write_byte( *( pBuf + i ) ); //写数据
}
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :清空TX缓冲区
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Flush_Tx_Fifo ( void )
{
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( FLUSH_TX ); //清TX FIFO命令
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :清空RX缓冲区
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Flush_Rx_Fifo( void )
{
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( FLUSH_RX ); //清RX FIFO命令
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :重新使用上一包数据
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Reuse_Tx_Payload( void )
{
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( REUSE_TX_PL ); //重新使用上一包命令
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :NRF24L01空操作
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Nop( void )
{
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( NOP ); //空操作命令
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :NRF24L01读状态寄存器
* @param :无
* @note :无
* @retval:RF24L01状态
*/
uint8_t NRF24L01_Read_Status_Register( void )
{
uint8_t Status;
RF24L01_SET_CS_LOW( ); //片选
Status = drv_spi_read_write_byte( NRF_READ_REG + STATUS ); //读状态寄存器
RF24L01_SET_CS_HIGH( ); //取消片选
return Status;
}
/**
* @brief :NRF24L01清中断
* @param :
@IRQ_Source:中断源
* @note :无
* @retval:清除后状态寄存器的值
*/
uint8_t NRF24L01_Clear_IRQ_Flag( uint8_t IRQ_Source )
{
uint8_t btmp = 0;
IRQ_Source &= ( 1 << RX_DR ) | ( 1 << TX_DS ) | ( 1 << MAX_RT ); //中断标志处理
btmp = NRF24L01_Read_Status_Register( ); //读状态寄存器
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( NRF_WRITE_REG + STATUS ); //写状态寄存器命令
drv_spi_read_write_byte( IRQ_Source | btmp ); //清相应中断标志
RF24L01_SET_CS_HIGH( ); //取消片选
return ( NRF24L01_Read_Status_Register( )); //返回状态寄存器状态
}
/**
* @brief :读RF24L01中断状态
* @param :无
* @note :无
* @retval:中断状态
*/
uint8_t RF24L01_Read_IRQ_Status( void )
{
return ( NRF24L01_Read_Status_Register( ) & (( 1 << RX_DR ) | ( 1 << TX_DS ) | ( 1 << MAX_RT ))); //返回中断状态
}
/**
* @brief :读FIFO中数据宽度
* @param :无
* @note :无
* @retval:数据宽度
*/
uint8_t NRF24L01_Read_Top_Fifo_Width( void )
{
uint8_t btmp;
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( R_RX_PL_WID ); //读FIFO中数据宽度命令
btmp = drv_spi_read_write_byte( 0xFF ); //读数据
RF24L01_SET_CS_HIGH( ); //取消片选
return btmp;
}
/**
* @brief :读接收到的数据
* @param :无
* @note :无
* @retval:
@pRxBuf:数据存放地址首地址
*/
uint8_t NRF24L01_Read_Rx_Payload( uint8_t *pRxBuf )
{
uint8_t Width, PipeNum;
PipeNum = ( NRF24L01_Read_Reg( STATUS ) >> 1 ) & 0x07; //读接收状态
Width = NRF24L01_Read_Top_Fifo_Width( ); //读接收数据个数
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( RD_RX_PLOAD ); //读有效数据命令
for( PipeNum = 0; PipeNum < Width; PipeNum ++ )
{
*( pRxBuf + PipeNum ) = drv_spi_read_write_byte( 0xFF ); //读数据
}
RF24L01_SET_CS_HIGH( ); //取消片选
NRF24L01_Flush_Rx_Fifo( ); //清空RX FIFO
return Width;
}
/**
* @brief :发送数据(带应答)
* @param :
* @pTxBuf:发送数据地址
* @len:长度
* @note :一次不超过32个字节
* @retval:无
*/
void NRF24L01_Write_Tx_Payload_Ack( uint8_t *pTxBuf, uint8_t len )
{
uint8_t btmp;
uint8_t length = ( len > 32 ) ? 32 : len; //数据长达大约32 则只发送32个
NRF24L01_Flush_Tx_Fifo( ); //清TX FIFO
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( WR_TX_PLOAD ); //发送命令
for( btmp = 0; btmp < length; btmp ++ )
{
drv_spi_read_write_byte( *( pTxBuf + btmp ) ); //发送数据
}
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :发送数据(不带应答)
* @param :
* @pTxBuf:发送数据地址
* @len:长度
* @note :一次不超过32个字节
* @retval:无
*/
void NRF24L01_Write_Tx_Payload_NoAck( uint8_t *pTxBuf, uint8_t len )
{
if( len > 32 || len == 0 )
{
return ; //数据长度大于32 或者等于0 不执行
}
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( WR_TX_PLOAD_NACK ); //发送命令
while( len-- )
{
drv_spi_read_write_byte( *pTxBuf ); //发送数据
pTxBuf++;
}
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :在接收模式下向TX FIFO写数据(带ACK)
* @param :
* @pData:数据地址
* @len:长度
* @note :一次不超过32个字节
* @retval:无
*/
void NRF24L01_Write_Tx_Payload_InAck( uint8_t *pData, uint8_t len )
{
uint8_t btmp;
len = ( len > 32 ) ? 32 : len; //数据长度大于32个则只写32个字节
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( W_ACK_PLOAD ); //命令
for( btmp = 0; btmp < len; btmp ++ )
{
drv_spi_read_write_byte( *( pData + btmp ) ); //写数据
}
RF24L01_SET_CS_HIGH( ); //取消片选
}
/**
* @brief :设置发送地址
* @param :
* @pAddr:地址存放地址
* @len:长度
* @note :无
* @retval:无
*/
void NRF24L01_Set_TxAddr( uint8_t *pAddr, uint8_t len )
{
len = ( len > 5 ) ? 5 : len; //地址不能大于5个字节
NRF24L01_Write_Buf( TX_ADDR, pAddr, len ); //写地址
}
/**
* @brief :设置接收通道地址
* @param :
* @PipeNum:通道
* @pAddr:地址存肥着地址
* @Len:长度
* @note :通道不大于5 地址长度不大于5个字节
* @retval:无
*/
void NRF24L01_Set_RxAddr( uint8_t PipeNum, uint8_t *pAddr, uint8_t Len )
{
Len = ( Len > 5 ) ? 5 : Len;
PipeNum = ( PipeNum > 5 ) ? 5 : PipeNum; //通道不大于5 地址长度不大于5个字节
NRF24L01_Write_Buf( RX_ADDR_P0 + PipeNum, pAddr, Len ); //写入地址
}
/**
* @brief :设置通信速度
* @param :
* @Speed:速度
* @note :无
* @retval:无
*/
void NRF24L01_Set_Speed( nRf24l01SpeedType Speed )
{
uint8_t btmp = 0;
btmp = NRF24L01_Read_Reg( RF_SETUP );
btmp &= ~( ( 1<<5 ) | ( 1<<3 ) );
if( Speed == SPEED_250K ) //250K
{
btmp |= ( 1<<5 );
}
else if( Speed == SPEED_1M ) //1M
{
btmp &= ~( ( 1<<5 ) | ( 1<<3 ) );
}
else if( Speed == SPEED_2M ) //2M
{
btmp |= ( 1<<3 );
}
NRF24L01_Write_Reg( RF_SETUP, btmp );
}
/**
* @brief :设置功率
* @param :
* @Speed:速度
* @note :无
* @retval:无
*/
void NRF24L01_Set_Power( nRf24l01PowerType Power )
{
uint8_t btmp;
btmp = NRF24L01_Read_Reg( RF_SETUP ) & ~0x07;
switch( Power )
{
case POWER_F18DBM:
btmp |= PWR_18DB;
break;
case POWER_F12DBM:
btmp |= PWR_12DB;
break;
case POWER_F6DBM:
btmp |= PWR_6DB;
break;
case POWER_0DBM:
btmp |= PWR_0DB;
break;
default:
break;
}
NRF24L01_Write_Reg( RF_SETUP, btmp );
}
/**
* @brief :设置频率
* @param :
* @FreqPoint:频率设置参数
* @note :值不大于127
* @retval:无
*/
void RF24LL01_Write_Hopping_Point( uint8_t FreqPoint )
{
NRF24L01_Write_Reg( RF_CH, FreqPoint & 0x7F );
}
/**
* @brief :NRF24L01检测
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_check( void )
{
uint8_t i;
uint8_t error = 0;
uint8_t buf[5]={ 0XA5, 0XA5, 0XA5, 0XA5, 0XA5 };
uint8_t read_buf[ 5 ] = { 0 };
while( 1 )
{
NRF24L01_Write_Buf( TX_ADDR, buf, 5 ); //写入5个字节的地址
NRF24L01_Read_Buf( TX_ADDR, read_buf, 5 ); //读出写入的地址
for( i = 0; i < 5; i++ )
{
if( buf[ i ] != read_buf[ i ] )
{
break;
}
}
if( 5 == i )
{
break;
}
else
{
error++;
if( error >= 3 )
{
break;
}
//测试错误
printf("NRF24L01 ERROR FILE:NRF24L01.C LINE = %d\r\n",__LINE__);
}
drv_delay_500Ms( 2 );
}
printf("Successful configuration\r\n");
}
/**
* @brief :设置模式
* @param :
* @Mode:模式发送模式或接收模式
* @note :无
* @retval:无
*/
void RF24L01_Set_Mode( nRf24l01ModeType Mode )
{
uint8_t controlreg = 0;
controlreg = NRF24L01_Read_Reg( CONFIG );
if( Mode == MODE_TX )
{
controlreg &= ~( 1<< PRIM_RX );
}
else
{
if( Mode == MODE_RX )
{
controlreg |= ( 1<< PRIM_RX );
}
}
NRF24L01_Write_Reg( CONFIG, controlreg );
}
/**
* @brief :NRF24L01发送一次数据
* @param :
* @txbuf:待发送数据首地址
* @Length:发送数据长度
* @note :无
* @retval:
* MAX_TX:达到最大重发次数
* TX_OK:发送完成
* 0xFF:其他原因
*/
uint8_t NRF24L01_TxPacket( uint8_t *txbuf, uint8_t Length )
{
uint8_t l_Status = 0;
uint16_t l_MsTimes = 0;
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( FLUSH_TX );
RF24L01_SET_CS_HIGH( );
RF24L01_SET_CE_LOW( );
NRF24L01_Write_Buf( WR_TX_PLOAD, txbuf, Length ); //写数据到TX BUF 32字节 TX_PLOAD_WIDTH
RF24L01_SET_CE_HIGH( ); //启动发送
while( 0 != RF24L01_GET_IRQ_STATUS( ))
{
delay_ms( 5 );
// printf("error-1\r\n");
if( 500 == l_MsTimes++ ) //500ms还没有发送成功,重新初始化设备
{
NRF24L01_Gpio_Init_transmit( );
RF24L01_Init( );
RF24L01_Set_Mode( MODE_TX );
break;
}
}
l_Status = NRF24L01_Read_Reg(STATUS); //读状态寄存器
NRF24L01_Write_Reg( STATUS, l_Status ); //清除TX_DS或MAX_RT中断标志
if( l_Status & MAX_TX ) //达到最大重发次数
{
NRF24L01_Write_Reg( FLUSH_TX,0xff ); //清除TX FIFO寄存器
return MAX_TX;
}
if( l_Status & TX_OK ) //发送完成
{
return TX_OK;
}
return 0xFF; //其他原因发送失败
}
void key_gpio_config(void)
{
}
/**
* @brief :RF24L01引脚初始化
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Gpio_Init_receive( void )
{
NVIC_EnableIRQ(GPIO_INT_IRQN);//开启按键引脚的GPIOA端口中断
RF24L01_SET_CE_LOW( );
RF24L01_SET_CS_HIGH( );
}
/************************************************
函数名称 : BSP_KEY_EXTI_IRQHandler
功 能 : 中断处理函数
参 数 : 无
返 回 值 : 无
作 者 : LCEDA
*************************************************/
extern uint8_t g_RF24L01RxBuffer[30];
void Buff_Clear(void)
{
for(int i = 0; i < 30; i++)
{
g_RF24L01RxBuffer[i] = 0;
}
}
void GROUP1_IRQHandler(void)//Group1的中断服务函数
{
//读取Group1的中断寄存器并清除中断标志位
switch( DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1) )
{
case GPIO_INT_IIDX:
if(RF24L01_GET_IRQ_STATUS() == 0) // IRQ为低电平
{
NRF24L01_RxPacket(g_RF24L01RxBuffer); //接收数据
//printf("data = %s",g_RF24L01RxBuffer );//输出数据
RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( FLUSH_RX );//清除RX FIFO寄存器
RF24L01_SET_CS_HIGH( );
}
else// IRQ为高电平
{
}
break;
}
}
/**
* @brief :NRF24L01接收数据
* @param :
* @rxbuf:接收数据存放地址
* @note :无
* @retval:接收的数据个数
*/
uint8_t NRF24L01_RxPacket( uint8_t *rxbuf )
{
uint8_t l_Status = 0, l_RxLength = 0;
l_Status = NRF24L01_Read_Reg( STATUS ); //读状态寄存器
NRF24L01_Write_Reg( STATUS,l_Status ); //清中断标志
if( l_Status & RX_OK) //接收到数据
{
l_RxLength = NRF24L01_Read_Reg( R_RX_PL_WID ); //读取接收到的数据个数
NRF24L01_Read_Buf( RD_RX_PLOAD,rxbuf,l_RxLength ); //接收到数据
NRF24L01_Write_Reg( FLUSH_RX,0xff ); //清除RX FIFO
return l_RxLength;
}
return 0; //没有收到数据
}
/**
* @brief :RF24L01引脚初始化
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Gpio_Init_transmit( void )
{
NVIC_EnableIRQ(GPIO_INT_IRQN);//开启按键引脚的GPIOA端口中断
RF24L01_SET_CE_LOW( );
RF24L01_SET_CS_HIGH( );
}
/**
* @brief :RF24L01模块初始化
* @param :无
* @note :无
* @retval:无
*/
void RF24L01_Init( void )
{
uint8_t addr[5] = {INIT_ADDR};
RF24L01_SET_CE_HIGH( );
NRF24L01_Clear_IRQ_Flag( IRQ_ALL );
#if DYNAMIC_PACKET == 1
NRF24L01_Write_Reg( DYNPD, ( 1 << 0 ) ); //使能通道1动态数据长度
NRF24L01_Write_Reg( FEATRUE, 0x07 );
NRF24L01_Read_Reg( DYNPD );
NRF24L01_Read_Reg( FEATRUE );
#elif DYNAMIC_PACKET == 0
L01_WriteSingleReg( L01REG_RX_PW_P0, FIXED_PACKET_LEN ); //固定数据长度
#endif //DYNAMIC_PACKET
NRF24L01_Write_Reg( CONFIG, /*( 1<<MASK_RX_DR ) |*/ //接收中断*/
( 1 << EN_CRC ) | //使能CRC 1个字节
( 1 << PWR_UP ) ); //开启设备
NRF24L01_Write_Reg( EN_AA, ( 1 << ENAA_P0 ) ); //通道0自动应答
NRF24L01_Write_Reg( EN_RXADDR, ( 1 << ERX_P0 ) ); //通道0接收
NRF24L01_Write_Reg( SETUP_AW, AW_5BYTES ); //地址宽度 5个字节
NRF24L01_Write_Reg( SETUP_RETR, ARD_4000US |
( REPEAT_CNT & 0x0F ) ); //重复等待时间 250us
NRF24L01_Write_Reg( RF_CH, 00 ); //初始化通道
NRF24L01_Write_Reg( RF_SETUP, 0x26 );
NRF24L01_Set_TxAddr( &addr[0], 5 ); //设置TX地址
NRF24L01_Set_RxAddr( 0, &addr[0], 5 ); //设置RX地址
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
在文件NRF24L01.h中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-05-30 LCKFB-LP first version
*/
#ifndef __NRF24L01_H__
#define __NRF24L01_H__
#include "drv_spi.h"
/** 配置和选项定义 */
#define DYNAMIC_PACKET 1 //1:动态数据包, 0:固定
#define FIXED_PACKET_LEN 32 //包长度
#define REPEAT_CNT 15 //重复次数
#define INIT_ADDR 0x34,0x43,0x10,0x10,0x01
/** 口线操作函数定义 */
#define RF24L01_SET_CE_HIGH( ) DL_GPIO_setPins(GPIO_PORT, GPIO_CE_PIN)
#define RF24L01_SET_CE_LOW( ) DL_GPIO_clearPins(GPIO_PORT, GPIO_CE_PIN)
#define RF24L01_SET_CS_HIGH( ) spi_set_nss_high( )
#define RF24L01_SET_CS_LOW( ) spi_set_nss_low( )
#define RF24L01_GET_IRQ_STATUS( ) ( ( ( DL_GPIO_readPins(GPIO_PORT,GPIO_IRQ_PIN) & GPIO_IRQ_PIN ) > 0 ) ? 1 : 0 ) //IRQ状态
typedef enum ModeType
{
MODE_TX = 0,
MODE_RX
}nRf24l01ModeType;
typedef enum SpeedType
{
SPEED_250K = 0,
SPEED_1M,
SPEED_2M
}nRf24l01SpeedType;
typedef enum PowerType
{
POWER_F18DBM = 0,
POWER_F12DBM,
POWER_F6DBM,
POWER_0DBM
}nRf24l01PowerType;
/** NRF24L01定义 */
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//寄存器操作命令
#define NRF_READ_REG 0x00 //读配置寄存器,低5位为寄存器地址
#define NRF_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 R_RX_PL_WID 0x60
#define NOP 0xFF //空操作,可以用来读状态寄存器
#define W_ACK_PLOAD 0xA8
#define WR_TX_PLOAD_NACK 0xB0
//SPI(NRF24L01)寄存器地址
#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 //设置地址宽度(所有数据通道) bit0~1: 00,3字节 01,4字节, 02,5字节
#define SETUP_RETR 0x04 //建立自动重发;bit0~3:自动重发计数器;bit4~7:自动重发延时 250*x+86us
#define RF_CH 0x05 //RF通道,bit0~6工作通道频率
#define RF_SETUP 0x06 //RF寄存器,bit3:传输速率( 0:1M 1:2M);bit1~2:发射功率;bit0:噪声放大器增益
#define STATUS 0x07 //状态寄存器;bit0:TX FIFO满标志;bit1~3:接收数据通道号(最大:6);bit4:达到最多次重发次数
//bit5:数据发送完成中断;bit6:接收数据中断
#define MAX_TX 0x10 //达到最大发送次数中断
#define TX_OK 0x20 //TX发送完成中断
#define RX_OK 0x40 //接收到数据中断
#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 NRF_FIFO_STATUS 0x17 //FIFO状态寄存器;bit0:RX FIFO寄存器空标志;bit1:RX FIFO满标志;bit2~3保留
//bit4:TX FIFO 空标志;bit5:TX FIFO满标志;bit6:1,循环发送上一数据包.0,不循环
#define DYNPD 0x1C
#define FEATRUE 0x1D
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//位定义
#define MASK_RX_DR 6
#define MASK_TX_DS 5
#define MASK_MAX_RT 4
#define EN_CRC 3
#define CRCO 2
#define PWR_UP 1
#define PRIM_RX 0
#define ENAA_P5 5
#define ENAA_P4 4
#define ENAA_P3 3
#define ENAA_P2 2
#define ENAA_P1 1
#define ENAA_P0 0
#define ERX_P5 5
#define ERX_P4 4
#define ERX_P3 3
#define ERX_P2 2
#define ERX_P1 1
#define ERX_P0 0
#define AW_RERSERVED 0x0
#define AW_3BYTES 0x1
#define AW_4BYTES 0x2
#define AW_5BYTES 0x3
#define ARD_250US (0x00<<4)
#define ARD_500US (0x01<<4)
#define ARD_750US (0x02<<4)
#define ARD_1000US (0x03<<4)
#define ARD_2000US (0x07<<4)
#define ARD_4000US (0x0F<<4)
#define ARC_DISABLE 0x00
#define ARC_15 0x0F
#define CONT_WAVE 7
#define RF_DR_LOW 5
#define PLL_LOCK 4
#define RF_DR_HIGH 3
//bit2-bit1:
#define PWR_18DB (0x00<<1)
#define PWR_12DB (0x01<<1)
#define PWR_6DB (0x02<<1)
#define PWR_0DB (0x03<<1)
#define RX_DR 6
#define TX_DS 5
#define MAX_RT 4
//for bit3-bit1,
#define TX_FULL_0 0
#define RPD 0
#define TX_REUSE 6
#define TX_FULL_1 5
#define TX_EMPTY 4
//bit3-bit2, reserved, only '00'
#define RX_FULL 1
#define RX_EMPTY 0
#define DPL_P5 5
#define DPL_P4 4
#define DPL_P3 3
#define DPL_P2 2
#define DPL_P1 1
#define DPL_P0 0
#define EN_DPL 2
#define EN_ACK_PAY 1
#define EN_DYN_ACK 0
#define IRQ_ALL ( (1<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT) )
uint8_t NRF24L01_Read_Reg( uint8_t RegAddr );
void NRF24L01_Read_Buf( uint8_t RegAddr, uint8_t *pBuf, uint8_t len );
void NRF24L01_Write_Reg( uint8_t RegAddr, uint8_t Value );
void NRF24L01_Write_Buf( uint8_t RegAddr, uint8_t *pBuf, uint8_t len );
void NRF24L01_Flush_Tx_Fifo ( void );
void NRF24L01_Flush_Rx_Fifo( void );
void NRF24L01_Reuse_Tx_Payload( void );
void NRF24L01_Nop( void );
uint8_t NRF24L01_Read_Status_Register( void );
uint8_t NRF24L01_Clear_IRQ_Flag( uint8_t IRQ_Source );
uint8_t RF24L01_Read_IRQ_Status( void );
uint8_t NRF24L01_Read_Top_Fifo_Width( void );
uint8_t NRF24L01_Read_Rx_Payload( uint8_t *pRxBuf );
void NRF24L01_Write_Tx_Payload_Ack( uint8_t *pTxBuf, uint8_t len );
void NRF24L01_Write_Tx_Payload_NoAck( uint8_t *pTxBuf, uint8_t len );
void NRF24L01_Write_Tx_Payload_InAck( uint8_t *pData, uint8_t len );
void NRF24L01_Set_TxAddr( uint8_t *pAddr, uint8_t len );
void NRF24L01_Set_RxAddr( uint8_t PipeNum, uint8_t *pAddr, uint8_t Len );
void NRF24L01_Set_Speed( nRf24l01SpeedType Speed );
void NRF24L01_Set_Power( nRf24l01PowerType Power );
void RF24LL01_Write_Hopping_Point( uint8_t FreqPoint );
void RF24L01_Set_Mode( nRf24l01ModeType Mode );
void NRF24L01_check( void );
uint8_t NRF24L01_TxPacket( uint8_t *txbuf, uint8_t Length );
uint8_t NRF24L01_RxPacket( uint8_t *rxbuf );
void NRF24L01_Gpio_Init_transmit( void );
void NRF24L01_Gpio_Init_receive( void );
void RF24L01_Init( void );
void Buff_Clear(void);
void Rocker_Mode(void);
char Get_NRF24L01_ConnectFlag(void);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
四、移植验证
将发送端代码烧入开发板,接收端代码烧入另一个开发板。
在empty.c中输入代码如下:
#include "board.h"
#include <stdio.h>
#include "NRF24L01.h"
#include "drv_spi.h"
#define RECEIVING_MODE 1 // 1:接收模式 0:发送模式
uint8_t g_RF24L01RxBuffer[30];
int main(void)
{
//开发板初始化
board_init();
//SPI初始化
drv_spi_init( );
#if RECEIVING_MODE
NRF24L01_Gpio_Init_receive( );
//检测nRF24L01
NRF24L01_check( );
//NRF初始化
RF24L01_Init( );
RF24L01_Set_Mode( MODE_RX );//NRF接收模式 .
printf("MODE_RX\r\n");
while(1)
{
if( 0 != g_RF24L01RxBuffer[0])
{
printf("Data = %s\r\n",g_RF24L01RxBuffer);
Buff_Clear();
}
// 必须要延时,不能无止境读取!!!
delay_ms(50);
}
#else
NRF24L01_Gpio_Init_transmit( );
//检测nRF24L01
NRF24L01_check( );
//NRF初始化
RF24L01_Init( );
RF24L01_Set_Mode( MODE_TX );//NRF发送模式 .
printf("MODE_TX\r\n");
while(1)
{
NRF24L01_TxPacket((uint8_t*)"hello LCKFB!\r\n",13);//NRF发送数据
printf("Send\r\n");
delay_ms(100);
}
#endif
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
上电效果:一个开发板烧录接收模式的代码,一个开发板烧录发送模式的代码。
代码下载
链接在开发板介绍
章节的离线资料下载!!