调试备忘录-nRF24L01P的使用(教程 + 源码)
目录--点击可快速直达
MCU:KEAZ64A
MDK:CodeWarrior 11.0
写在前面
因为最近在重写之前项目的代码,以提升系统的稳定性和代码的可读性,所以重新选择了一块nRF24L01P,进行调试。
以下算是一些调试的备忘录吧,如有问题可以通过私信或者邮箱联系我。
什么是nRF24L01P?
nRF24L01P是一颗工作在 2.4GHz ISM 频段,专为低功耗无线场合设计,集成嵌入式 ARQ基带协议引擎的无线收发器芯片。
工作频率范围为 2400MHz-2525MHz,共有 126 个 1MHz带宽的信道。
简单来说,就是一块基于民用频段的无线通信芯片,可以用于无线鼠标、无线键盘、遥控器、工业传感器等应用。
后面我要使用的模块是在某宝上买的泽耀的nRF24L01P无线通信模块,以下的一些图片也是截取自它家的产品资料。
nRF24L01P模块的简单介绍
nRF24L01P模块一共有八个引脚,其中4个SPI引脚,一共工作模式切换引脚和一个终端引脚。
推荐与MCU的连接图
nRF24L01P的工作模式
nRF24L01P使用SPI进行通讯,可以通过SPI设置nRF24L01P的寄存器来改变nRF24L01P的工作模式。
如图所示,nRF24L01P的工作模式有如上几种,我们主要使用的就是接收模式、发射模式以及在两者之间过渡的待机模式II。
通过改变CONFIG寄存器中的PRIM_RX的值和模块引脚CE的高低电平,就可以切换工作模式了。
工作模式之间切换是有延时的,如果不加延时,可能导致未知的问题。一定要按照芯片手册中的资料来增加延时。
nRF24L01P模块的初始化简易配置
(一对一模式,使用接收通道0,禁止自动重发)
寄存器 | 位名 | 推荐值 | 备注 |
---|---|---|---|
TX_ADDR | None | 0x34 0x43 0x10 0x10 0x01 | 发射地址 |
RX_ADDR_P0 | None | 0x34 0x43 0x10 0x10 0x01 | 接收通道0地址 |
EN_AA | None | 0 | 禁止自动应答 |
SETUP_RETR | None | 0 | 禁止自动重发 |
EN_RXADDR | ERX_P0 | 0x01 | 使能通道0 |
RF_CH | None | 40 | 设置通道频率 |
RX_PW_P0 | None | 0x05 | 设置P0通道的数据宽度 |
RF_SETUP | None | 0x07 | 设置发射功率以及数据传输数率 |
CONFIG | None | 0x3e | 禁止发射中断,使能发射模式 |
注:
1.配置寄存器时,一定要按照SPI的指令格式进行配置。如下图。
nRF24L01P模块调试的一些小技巧
1.刚开始调试的时候一定要选择一个模块为发射模式,一个模块为接收模式。发射的开启发射中断,接收的开启接收中断。这样就可以用过在中断中加入显示(例如LED)开观察是否发射成功或者接收成功。
2.刚开启中断的时候一定要记得清除中断标志位,中断标志位有两个,一个是模块的中断标志位,一个是MCU的中断标志位。
3.对于发射模式,切换发射模式的时候,最好把发射地址(TX_ADDR)也重新写一遍,因为我在调试的时候发现,如果不重写一遍地址,就会出问题。当然,这个可能是模块的BUG,因人而异把。
4.如果有问题,记得使用示波器查看SPI引脚、CE和IRQ的运行情况。
5.写入寄存器的时候记得拉低CE引脚。
6.如果还是有未知的问题,可以试试延长一下操作IO的时间。
附上源码
软件模拟的SPI通信,方便移植。
/**
******************************************************************************
* @file drv_spi.c
* @author xxx
* @version V1.0
* @date 2020-1-04
* @brief SPI配置C文件
******************************************************************************
*/
#include "common.h"
/*
* PTB2->SCK PTF0->CE
* PTB3->MOSI PTE2->MISO
* PTD2->CSN IRQ->PTA6
*
* PTE0->SCK PTG3->CE
* PTE1->MOSI PTE2->MISO
* PTE3->CSN IRQ->PTC7
*/
void spi_set_clk_low( )
{
//GPIO_Set_IO_Value(PORT_B,GPIO_PIN_2,OUTPUT_LOW);
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_0,OUTPUT_LOW);
}
void spi_set_clk_high( )
{
//GPIO_Set_IO_Value(PORT_B,GPIO_PIN_2,OUTPUT_HIGH);
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_0,OUTPUT_HIGH);
}
void spi_set_mosi_low( )
{
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_1,OUTPUT_LOW);
}
void spi_set_mosi_hight( )
{
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_1,OUTPUT_HIGH);
}
unsigned char spi_get_miso( )
{
return GPIO_Get_IO_Value(PORT_E,GPIO_PIN_2);
}
void spi_set_nss_low( )
{
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_3,OUTPUT_LOW);
}
void spi_set_nss_high( )
{
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_3,OUTPUT_HIGH);
}
/** 软件SPI */
/**
* @brief :SPI初始化(软件)
* @param :无
* @note :无
* @retval:无
*/
void drv_spi_init( void )
{
/*GPIO_Init_IO(PORT_B,GPIO_PIN_2,OUTPUT);
GPIO_Init_IO(PORT_B,GPIO_PIN_3,OUTPUT);
GPIO_Init_IO(PORT_E,GPIO_PIN_2,INPUT);
GPIO_Init_IO(PORT_D,GPIO_PIN_2,OUTPUT);*/
GPIO_Init_IO(PORT_E,GPIO_PIN_0,OUTPUT);
GPIO_Init_IO(PORT_E,GPIO_PIN_3,OUTPUT);
GPIO_Init_IO(PORT_E,GPIO_PIN_2,INPUT);
GPIO_Init_IO(PORT_E,GPIO_PIN_1,OUTPUT);
}
/**
* @brief :SPI收发一个字节
* @param :
* @TxByte: 发送的数据字节
* @note :非堵塞式,一旦等待超时,函数会自动退出
* @retval:接收到的字节
*/
uint8_t drv_spi_read_write_byte( uint8_t TxByte )
{
uint8_t i = 0, Data = 0;
spi_set_clk_low( );
for( i = 0; i < 8; i++ ) //一个字节8byte需要循环8次
{
/** 发送 */
if( 0x80 == ( TxByte & 0x80 ))
{
spi_set_mosi_hight( ); //如果即将要发送的位为 1 则置高IO引脚
}
else
{
spi_set_mosi_low( ); //如果即将要发送的位为 0 则置低IO引脚
}
TxByte <<= 1; //数据左移一位,先发送的是最高位
spi_set_clk_high( ); //时钟线置高
asm ("nop; nop");
asm ("nop; nop");
/** 接收 */
Data <<= 1; //接收数据左移一位,先接收到的是最高位
if( 1 == spi_get_miso( ))
{
Data |= 0x01; //如果接收时IO引脚为高则认为接收到 1
}
spi_set_clk_low( ); //时钟线置低
asm ("nop; nop");
asm ("nop; nop");
}
return 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( ); //片选拉高
}
/** 软件SPI */
RF24L01的驱动函数,主要调用NRF24L01_Gpio_Init()
RF24L01_Init()
NRF24L01_check()
RF24L01_Set_Mode()
NRF24L01_TxPacket()
这几个函数就够用了。
/**
******************************************************************************
* @file dev_RF24L01.c
* @author xxx
* @version V1.0.0
* @date 2020-1-03
* @brief NRF24L01配置C文件
******************************************************************************
*/
#include "common.h"
const char *g_ErrorString = "RF24L01 is not find !...";
/*
* PTB2->SCK PTF0->CE
* PTB3->MOSI PTE2->MISO
* PTD2->CSN IRQ->PTA6
*
* PTE0->SCK PTG3->CE
* PTE1->MOSI PTE2->MISO
* PTE3->CSN IRQ->PTC7
*/
void RF24L01_SET_CS_LOW()
{
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_3,OUTPUT_LOW);
}
void RF24L01_SET_CS_HIGH()
{
GPIO_Set_IO_Value(PORT_E,GPIO_PIN_3,OUTPUT_HIGH);
}
void RF24L01_SET_CE_LOW()
{
GPIO_Set_IO_Value(PORT_G,GPIO_PIN_3,OUTPUT_LOW);
}
void RF24L01_SET_CE_HIGH()
{
GPIO_Set_IO_Value(PORT_G,GPIO_PIN_3,OUTPUT_HIGH);
}
unsigned char RF24L01_GET_IRQ_STATUS()
{
return GPIO_Get_IO_Value(PORT_C,GPIO_PIN_7);
}
/**
* @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 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
{
//drv_uart_tx_bytes( (uint8_t *)g_ErrorString, 26 );
}
//Delay_1ms( 4 * 500 );
Delay_1ms( 4 * 5 );
}
}
/**
* @brief :设置模式
* @param :
* @Mode:模式发送模式或接收模式
* @note :无
* @retval:无
*/
void RF24L01_Set_Mode( nRf24l01ModeType Mode )
{
uint8_t controlreg = 0;
RF24L01_SET_CE_LOW( );
controlreg = NRF24L01_Read_Reg( CONFIG );
if( Mode == MODE_TX )
{
controlreg &= ~( 1<< PRIM_RX );
}
else
{
if( Mode == MODE_RX )
{
uint8_t addr[5] = {INIT_ADDR};
NRF24L01_Set_RxAddr( 0, &addr[0], 5 );
controlreg |= ( 1<< PRIM_RX );
controlreg &= ~( 1<< MASK_RX_DR );
}
}
NRF24L01_Write_Reg( CONFIG, controlreg );
RF24L01_SET_CE_HIGH( );
Delay_1us(130);
}
/**
* @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;
uint8_t addr[5] = {INIT_ADDR};
RF24L01_SET_CE_LOW( );
NRF24L01_Set_TxAddr( &addr[0], 5 ); //设置TX地址
NRF24L01_Write_Buf( WR_TX_PLOAD, txbuf, Length ); //写数据到TX BUF 32字节 TX_PLOAD_WIDTH.
RF24L01_SET_CE_HIGH( );
Delay_1us(130);
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寄存器
drv_spi_read_write_byte( FLUSH_TX );
return MAX_TX;
}
if( l_Status & TX_OK ) //发送完成
{
return TX_OK;
}
return 0xFF; //其他原因发送失败
}
/**
* @brief :NRF24L01接收数据
* @param :
* @rxbuf:接收数据存放地址
* @note :无
* @retval:接收的数据个数
*/
uint8_t NRF24L01_RxPacket( uint8_t *rxbuf )
{
uint8_t l_Status = 0, l_RxLength = 0, l_100MsTimes = 0;
l_Status = NRF24L01_Read_Reg( STATUS ); //读状态寄存器
NRF24L01_Write_Reg( STATUS,l_Status ); //清中断标志
/*RF24L01_SET_CS_LOW( ); //片选
drv_spi_read_write_byte( FLUSH_RX );
RF24L01_SET_CS_HIGH( );*/
//while( 0 != RF24L01_GET_IRQ_STATUS( ))
/*{
Delay_1ms( 100 );
if( 30 == l_100MsTimes++ ) //3s没接收过数据,重新初始化模块
{
NRF24L01_Gpio_Init( );
RF24L01_Init( );
RF24L01_Set_Mode( MODE_RX );
//break;
}
}
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引脚初始化
* PTB2->SCK PTF0->CE
* PTB3->MOSI PTE2->MISO
* PTD2->CSN IRQ->PTA6
*
* PTE0->SCK PTG3->CE
* PTE1->MOSI PTE2->MISO
* PTE3->CSN IRQ->PTC7
* @param :无
* @note :无
* @retval:无
*/
void NRF24L01_Gpio_Init( void )
{
GPIO_Init_IO(PORT_C,GPIO_PIN_7,INPUT);
GPIO_Init_IO(PORT_G,GPIO_PIN_3,OUTPUT);
KBI_Init(PORT_C,GPIO_PIN_7,FALLING);
}
/**
* @brief :RF24L01模块初始化
* @param :无
* @note :无
* @retval:无
*/
void RF24L01_Init( void )
{
uint8_t addr[5] = {INIT_ADDR};
RF24L01_SET_CE_LOW( );
NRF24L01_Write_Reg( RX_PW_P0, 8 );
NRF24L01_Write_Reg( CONFIG, 0x7e ); //接收中断
NRF24L01_Write_Reg( EN_AA, ( 0 ) ); //禁止通道0自动应答
NRF24L01_Write_Reg( EN_RXADDR, ( 1 ) ); //通道0接收
NRF24L01_Write_Reg( SETUP_AW, AW_5BYTES ); //地址宽度 5个字节
NRF24L01_Write_Reg( SETUP_RETR, 0x0a ); //重复等待时间 250us
NRF24L01_Write_Reg( RF_CH, 40 ); //初始化通道
NRF24L01_Write_Reg( RF_SETUP, 0x07 );
NRF24L01_Set_TxAddr( &addr[0], 5 ); //设置TX地址
NRF24L01_Set_RxAddr( 0, &addr[0], 5 ); //设置RX地址
RF24L01_SET_CE_HIGH( );
Delay_1ms(1);
}
IRQ接收中断处理函数
void KBI0_IRQHandler()
{
uint8_t l_Status = 0, l_RxLength = 0, l_100MsTimes = 0;
unsigned char rxbuf[8];
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
GPIO_Toggle_IO_Value(PORT_C,GPIO_PIN_0);
return l_RxLength;
}
KBI0_SC |= KBI_SC_KBACK_MASK; // clear interrupt flag
}
调试备忘录-nRF24L01P的使用(教程 + 源码)的更多相关文章
- Eclipse开发环境debug模式调试断点从jar跳到源码
Eclipse开发环境debug模式调试断点从jar跳到源码 说明:本案例使用jsch-0.1.54.jar和源码做test,项目分成两个,一个是jsch的源码,另一个是测试案例 一.下载JSch.的 ...
- 调试 .NET Framework 源代码、.DotNetCore源码
调试 .NET Framework 源代码..DotNetCore源码 如何调试 .NET Framework 源代码 在 Visual Studio 调试器中指定符号 (.pdb) 和源文件 .NE ...
- 手把手教你调试SpringBoot启动 IoC容器初始化源码,spring如何解决循环依赖
授人以鱼不如授人以渔,首先声明这篇文章并没有过多的总结和结论,主要内容是教大家如何一步一步自己手动debug调试源码,然后总结spring如何解决的循环依赖,最后,操作很简单,有手就行. 本次调试 是 ...
- 如何调试最新的asp.net mvc源码
vs2013调试 一.源码当前为5.2.0.0,按下面改为5.0.0.1 二./web.config 版本为5.0.0.0 改为5.0.0.1 三.vs2013 x86 本机工具命令提示 sn.exe ...
- 实时滚动图表绘制方法: LightningChart教程 + 源码下载
LightningChart图形控件彻底发挥了GPU加速和性能优化的最大效应,能够实时呈现超过10亿数据点的庞大数据,为大家提供先进与快速的图表库.这里的实时图实现的比较简单,大家先试一下这个效果,熟 ...
- unity3d俄罗斯方块源码教程+源码和程序下载
小时候,大家都应玩过或听说过<俄罗斯方块>,它是红白机,掌机等一些电子设备中最常见的一款游戏.而随着时代的发展,信息的进步,游戏画面从简单的黑白方块到彩色方块,游戏的玩法机制从最简单的消方 ...
- Android 视频 教程 源码 电子书 网址
资源名称 资源地址 下载量 好评率8天快速掌握Android视频教程67集(附源码)http://down.51cto.com/zt/2197 32157Android开发入门之实战技巧和源码 htt ...
- [参考资料] 80个Python经典资料(教程+源码+工具)汇总
AD : 2018重磅地面课程<机器读心术之语音识别前沿实战特训营>,迈向人工智能新高度 [专题推荐]Python系列英文原版电子书 http://down.51cto.com/zt/10 ...
- 80个Python经典资料(教程+源码+工具)汇总——下载目录 ...
原文转自:http://bbs.51cto.com/thread-935214-1.html 大家好,51CTO下载中心根据资料的热度和好评度收集了80个Python资料,分享给Python开发的同学 ...
随机推荐
- 通过PHP工具箱-站点域名管理(创建本地虚拟主机)
工具:php程序员工具箱(网上很多请自己搜索下载) 1.点击其它选项菜单 -> 选择站点域名管理.如下图 2.进入站点域名管理.如下图(初始的时候,站点为空) 3.设置站点管理.如下图 网站域名 ...
- SpringBoot2 整合FreeMarker模板,完成页面静态化处理
本文源码:GitHub·点这里 || GitEE·点这里 一.页面静态化 1.动静态页面 静态页面 即静态网页,指已经装载好内容HTML页面,无需经过请求服务器数据和编译过程,直接加载到客户浏览器上显 ...
- android手机号和密码输入框的一个范例
https://blog.csdn.net/androidmsky/article/details/49870823
- 一个简单的Android小实例分享,包含recycleView与recyclerView嵌套
先上图: 1.首页 2.第二页 3.第三页 项目目录: 代码不多,本人太懒,就不贴了 项目地址:
- c语言大小写转化函数(包括字母和字符串)
本憨憨忘了好几次了,这次一定记住他们! 首先大小写相差32.转换的话自己写函数也是可以写出来的. 1.字母 如果是字母转的话,用toupper(),tolower() 头文件是<ctype.h& ...
- 第九章 Lambda&方法引用
9.1.Lambda表达式 9.1.1.标准格式 (形式参数) -> {代码块} 9.1.2.使用前提 有一个接口并且接口中有且仅有一个抽象方法 9.1.3.常见应用 9.1.3.1.无参无返回 ...
- Python File seek() 方法
概述 seek() 方法用于移动文件读取指针到指定位置.高佣联盟 www.cgewang.com 语法 seek() 方法语法如下: fileObject.seek(offset[, whence]) ...
- MediaDevices对象
mediaDevices 是 Navigator对象的一个 只读属性,返回一个 MediaDevices 对象,该对象可提供对相机和麦克风等媒体输入设备的连接访问,也包括屏幕共享. 语法 const ...
- CF掉分日记 6.6 6.8
---恢复内容开始--- 写的效果依旧不好 还没写完前四题比赛就结束了 而且这些普及组的题目 我大多还是缺少简单算法的灵性 总是把问题搞复杂化. 6.5 A 第一道题非常水 简单分析发现是一个快速幂的 ...
- luogu P2183 [国家集训队]礼物
LINK:礼物 n个物品 m个人 每个人要分得wi 个物品 每个物品互异 分给每个人的物品不分顺序 求方案数. \(n,p\leq 1e9 m\leq 5\) 方案数 那显然是 第一个人拿了w1件物品 ...