一、电路引脚图
1、引脚说明:
2、引脚标号:
找到1号引脚,与原理图对号入座。
3、cubemx初始化配置:
5、驱动文件
配置spi,并构建发送与接收函数接口
.h
#define TX_ADR_WIDTH 5 //发射地址宽度
#define TX_PLOAD_WIDTH 32 //发射数据通道有效数据宽度0~32Byte
#define RX_ADR_WIDTH 5
#define RX_PLOAD_WIDTH 32
#define CHANAL 40 //频道选择
// SPI(nRF24L01) commands , NRF的SPI命令宏定义,详见NRF功能使用文档
#define NRF_READ_REG 0x00 // Define read command to register
#define NRF_WRITE_REG 0x20 // Define write command to register
#define RD_RX_PLOAD 0x61 // Define RX payload register address
#define WR_TX_PLOAD 0xA0 // Define TX payload register address
#define FLUSH_TX 0xE1 // Define flush TX register command
#define FLUSH_RX 0xE2 // Define flush RX register command
#define REUSE_TX_PL 0xE3 // Define reuse TX payload register command
#define NOP 0xFF // Define No Operation, might be used to read status register
// SPI(nRF24L01) registers(addresses) ,NRF24L01 相关寄存器地址的宏定义
#define CONFIG 0x00 // 'Config' register address
#define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR 0x02 // 'Enabled RX addresses' register address
#define SETUP_AW 0x03 // 'Setup address width' register address
#define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address
#define RF_CH 0x05 // 'RF channel' register address
#define RF_SETUP 0x06 // 'RF setup' register address
#define STATUS 0x07 // 'Status' register address
#define OBSERVE_TX 0x08 // 'Observe TX' register address
#define CD 0x09 // 'Carrier Detect' register address
#define RX_ADDR_P0 0x0A // 'RX address pipe0' register address
#define RX_ADDR_P1 0x0B // 'RX address pipe1' register address
#define RX_ADDR_P2 0x0C // 'RX address pipe2' register address
#define RX_ADDR_P3 0x0D // 'RX address pipe3' register address
#define RX_ADDR_P4 0x0E // 'RX address pipe4' register address
#define RX_ADDR_P5 0x0F // 'RX address pipe5' register address
#define TX_ADDR 0x10 // 'TX address' register address
#define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address
#define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address
#define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address
#define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address
#define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address
#define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17 // 'FIFO Status Register' register address
#define MAX_RT 0x10 //达到最大重发次数中断标志位
#define TX_DS 0x20 //发送完成中断标志位 //
#define RX_DR 0x40 //接收到数据中断标志位
uint8_t SPI_NRF_WriteBuf(uint8_t reg ,uint8_t *pBuf,uint8_t bytes);
uint8_t SPI_NRF_ReadBuf(uint8_t reg,uint8_t *pBuf,uint8_t bytes);
uint8_t SPI_NRF_ReadReg(uint8_t reg);
uint8_t SPI_NRF_WriteReg(uint8_t reg,uint8_t dat);
extern uint8_t RX_BUF[RX_PLOAD_WIDTH]; //接收数据缓存
extern uint8_t TX_BUF[TX_PLOAD_WIDTH]; //发射数据缓存
extern uint8_t TX_ADDRESS[TX_ADR_WIDTH]; // 定义一个静态发送地址
extern uint8_t RX_ADDRESS[RX_ADR_WIDTH];
void NRF_RX_Mode(void);
void NRF_TX_Mode(void);
uint8_t NRF_Check(void);
uint8_t NRF_Tx_Dat(uint8_t *txbuf);
uint8_t NRF_Rx_Dat(uint8_t *rxbuf);
.c
uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint8_t byte)
{
uint8_t d_read,d_send=byte;
if(HAL_SPI_TransmitReceive(hspi,&d_send,&d_read,1,0xFF)!=HAL_OK)
{
d_read=0xFF;
}
return d_read;
}
/**
* @brief 用于向NRF特定的寄存器写入数据
* @param
* @arg reg:NRF的命令+寄存器地址
* @arg dat:将要向寄存器写入的数据
* @retval NRF的status寄存器的状态
*/
uint8_t SPI_NRF_WriteReg(uint8_t reg,uint8_t dat)
{
uint8_t status;
CS_L();
status =SPIx_ReadWriteByte(&hspi1,reg);
SPIx_ReadWriteByte(&hspi1,dat);
CS_H();
return status;
}
/**
* @brief 用于从NRF特定的寄存器读出数据
* @param
* @arg reg:NRF的命令+寄存器地址
* @retval 寄存器中的数据
*/
uint8_t SPI_NRF_ReadReg(uint8_t reg)
{
uint8_t val;
CS_L();
SPIx_ReadWriteByte(&hspi1,reg);
val=SPIx_ReadWriteByte(&hspi1,0xff);
CS_H();
return val;
}
/**
* @brief 用于向NRF的寄存器中写入一串数据
* @param
* @arg reg : NRF的命令+寄存器地址
* @arg pBuf:用于存储将被读出的寄存器数据的数组,外部定义
* @arg bytes: pBuf的数据长度
* @retval NRF的status寄存器的状态
*/
uint8_t SPI_NRF_ReadBuf(uint8_t reg,uint8_t *pBuf,uint8_t bytes)
{
uint8_t status,u8_ctr;
CS_L(); //使能SPI传输
status=SPIx_ReadWriteByte(&hspi1,reg);
//发送寄存器值(位置),并读取状态值
for(u8_ctr=0;u8_ctr<bytes;u8_ctr++)//读出数据
pBuf[u8_ctr]=SPIx_ReadWriteByte(&hspi1,0xff);
CS_H(); //关闭SPI传输
return status; //返回读到的状态值
}
/**
* @brief 用于向NRF的寄存器中写入一串数据
* @param
* @arg reg : NRF的命令+寄存器地址
* @arg pBuf:存储了将要写入写寄存器数据的数组,外部定义
* @arg bytes: pBuf的数据长度
* @retval NRF的status寄存器的状态
*/
uint8_t SPI_NRF_WriteBuf(uint8_t reg ,uint8_t *pBuf,uint8_t bytes)
{
uint8_t status,u8_ctr;
CS_L(); //使能SPI传输
status= SPIx_ReadWriteByte(&hspi1,reg);
//发送寄存器值(位置),并读取状态值
for(u8_ctr=0; u8_ctr<bytes; u8_ctr++)
{
SPIx_ReadWriteByte(&hspi1,(*pBuf++)); //写入数据
}
CS_H(); //关闭SPI传输
return status; //返回读到的状态值
}
uint8_t RX_BUF[RX_PLOAD_WIDTH]; //接收数据缓存
uint8_t TX_BUF[TX_PLOAD_WIDTH]; //发射数据缓存
uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01}; // 定义一个静态发送地址
uint8_t RX_ADDRESS[RX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
/**
* @brief 配置并进入接收模式
* @param 无
* @retval 无
*/
void NRF_RX_Mode(void)
{
CE_L();
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址,在配置时有RX_ADDR_P0~RX_ADDR_P5个通道,每个通道的RX_ADDRESS都一样根据需求自己设定
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01); //使能通道0的自动应答 ,b‘0 ,0 0 0 1’ ,为0通道
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的接收地址
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL); //设置RF通信频率
SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG, 0x0f); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
/*CE拉高,进入接收模式*/
CE_H();
HAL_Delay(1);
}
/**
* @brief 配置发送模式
* @param 无
* @retval 无
*/
void NRF_TX_Mode(void)
{
CE_L();
SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH); //写TX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01); //使能通道0的自动应答
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址
SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL); //设置RF通道为CHANAL
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG,0x0e); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发射模式,开启所有中断
/*CE拉高,进入发送模式*/
CE_H();
HAL_Delay(1);
// HAL_Delay(0xffff); //CE要拉高一段时间才进入发送模式
}
/**
* @brief 主要用于NRF与MCU是否正常连接
* @param 无
* @retval SUCCESS/ERROR 连接正常/连接失败
*/
static uint8_t buf[5]={0xC2,0xC2,0xC2,0xC2,0xC2};
uint8_t buf1[5]={0};
uint8_t NRF_Check(void)
{
uint8_t buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
uint8_t i;
SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.
memset(buf,0,5);
SPI_NRF_ReadBuf(TX_ADDR,buf,5); //读出写入的地址
for(i=0;i<5;i++)if(buf[i]!=0XA5)break;
if(i!=5)return 1;//检测24L01错误
return 0; //检测到24L01
}
/**
* @brief 用于向NRF的发送缓冲区中写入数据
* @param
* @arg txBuf:存储了将要发送的数据的数组,外部定义
* @retval 发送结果,成功返回TXDS,失败返回MAXRT或ERROR
*/
uint8_t NRF_Tx_Dat(uint8_t *txbuf)
{
uint8_t state;
CE_L();
SPI_NRF_WriteBuf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF 32个字节
CE_H();//启动发送
while(READ_IRQ()!=0);//等待发送完成
state=SPI_NRF_ReadReg(STATUS); //读取状态寄存器的值
SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
if(state&MAX_RT)//达到最大重发次数
{
SPI_NRF_WriteReg(FLUSH_TX,0xff);//清除TX FIFO寄存器
printf("state&(MAX_RT) %0x \n ",state&(MAX_RT) );
printf("state %0x \n",state);
return MAX_RT;
}
if(state&TX_DS)//发送完成
{
return TX_DS;
}
return 0xff;//其他原因发送失败
}
/**
* @brief 用于从NRF的接收缓冲区中读出数据
* @param
* @arg rxBuf :用于接收该数据的数组,外部定义
* @retval
* @arg 接收结果
*/
uint8_t NRF_Rx_Dat(uint8_t *rxbuf)
{
uint8_t state;
/*等待接收中断*/
state=SPI_NRF_ReadReg(STATUS); //读取状态寄存器的值
SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
if(state&RX_DR)//接收到数据
{
SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
SPI_NRF_WriteReg(FLUSH_RX,0xff);//清除RX FIFO寄存器
return 0;
}
return 1;//没收到任何数据
}
自测调用
/*检测 NRF 模块与 MCU 的连接*/
void Self_Test(void)
{
/*判断连接状态*/
if(NRF_Check() == SUCCESS)
printf("\r\n NRF1与MCU连接成功! \r\n");
else
printf("\r\n NRF1与MCU连接失败,请重新检查接线。\r\n");
NRF_RX_Mode(); // NRF1 进入接收模式
while(1)
{
/* 等待 NRF1 接收数据 */
/* 判断接收状态 */
if(NRF_Rx_Dat(rxbuf) == 0)
{
printf("\r\n NRF1 接收数据为: \r\n");
// for(i=0;i<32;i++)
// {
// printf(" %d ",rxbuf[i]);
// }
printf("\n %s ",rxbuf);
}
/* NRF1 发送数据 */
if ( get_date(rs_buf) == 1) // 获取发送数据,开始送数据
{
/* 发送数据 */
NRF_TX_Mode();
status = NRF_Tx_Dat(rs_buf);
/* 发送数据的状态 */
if(status == TX_DS)
{
printf("\r\nNRF1 发送数据成功\r\n");
}
else
{
printf("\r\nNRF1 发送数据失败 %d\r\n", status);
}
memset(rs_buf,0,u_size);
//再次开启接收,并等候接收。
printf("\r\nNRF1 进入接收模式\r\n");
NRF_RX_Mode();
}
}