标题:
NRF24L01使用问题 附单片机代码
[打印本页]
作者:
stm32_1
时间:
2022-3-9 21:53
标题:
NRF24L01使用问题 附单片机代码
NRF24L01使用出了问题,但找不到原因,发此帖向各位前辈请教一下
需求:采用NRF24L01作无线传输,接收端接收到特定数组,蜂鸣器就会响,当接收到数组不为此数组时,蜂鸣器关闭
问题:接收端不能正常工作
部分代码如下:
(一)NRF24L01配置
#include "bsp_spi_nrf.h"
u8 RX_BUF[RX_PLOAD_WIDTH]; //接收数据缓存
u8 TX_BUF[TX_PLOAD_WIDTH]; //发射数据缓存
u8 TX_ADDRESS[TX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01}; // 定义一个静态发送地址
u8 RX_ADDRESS[RX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
void Delay(__IO u32 nCount)
{
for(; nCount != 0; nCount--);
}
/*------------------------------------------------------------SPI的 I/O配置-------------------------------------------------------------------*/
void SPI_NRF_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA
|NRF_CSN_GPIO_CLK
|NRF_CE_GPIO_CLK
|NRF_IRQ_GPIO_CLK,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/*SCK,MISO,MOSI引脚(PA5,PA6,PA7)*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用功能
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*CSN引脚*/
GPIO_InitStructure.GPIO_Pin = NRF_CSN_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(NRF_CSN_GPIO_PORT, &GPIO_InitStructure);
/*CE引脚*/
GPIO_InitStructure.GPIO_Pin = NRF_CE_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(NRF_CE_GPIO_PORT, &GPIO_InitStructure);
/*IRQ引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; //上拉输入
GPIO_Init(NRF_IRQ_GPIO_PORT, &GPIO_InitStructure);
NRF_CSN_HIGH(); //拉高csn引脚,NRF进入空闲状态
/*配置SPI*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据大小8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟极性,空闲时为低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //第1个边沿有效,上升沿为采样时刻
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件产生
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //8分频,9MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);//使能SPI
}
/*----------------------------------------------------向NRF读/写一字节数据--------------------------------------------------------------*/
u8 SPI_NRF_RW(u8 dat)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //当SPI发送缓冲器非空时等待
SPI_I2S_SendData(SPI1, dat); //通过SPI发送一字节数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //当SPI接收缓冲器为空时等待
return SPI_I2S_ReceiveData(SPI1); //返回从SPI接收到的数据
}
/*---------------------------------------------------向NRF特定的寄存器写入数据----------------------------------------------------------------*/
//reg:NRF的命令+寄存器地址\
dat:将要向寄存器写入的数据\
status:NRF的status寄存器的状态
u8 SPI_NRF_WriteReg(u8 reg,u8 dat)
{
u8 status;
NRF_CE_LOW();
NRF_CSN_LOW(); //置低CSN,使能SPI传输
status = SPI_NRF_RW(reg); //发送命令及寄存器号
SPI_NRF_RW(dat); //向寄存器写入数据
NRF_CSN_HIGH(); //CSN拉高,完成
return(status); //返回状态寄存器的值
}
/*--------------------------------------------------从NRF特定的寄存器读出数据-----------------------------------------------------------------*/
//reg:NRF的命令+寄存器地址\
reg_val:寄存器中的数据
u8 SPI_NRF_ReadReg(u8 reg)
{
u8 reg_val;
NRF_CE_LOW();
NRF_CSN_LOW(); //置低CSN,使能SPI传输
SPI_NRF_RW(reg); //发送寄存器号
reg_val = SPI_NRF_RW(NOP); //读取寄存器的值
NRF_CSN_HIGH(); //CSN拉高,完成
return reg_val;
}
/*------------------------------------------------------向NRF的寄存器中写入一串数据----------------------------------------------------------*/
//reg : NRF的命令+寄存器地址\
pBuf:用于存储将被读出的寄存器数据的数组,外部定义\
bytes: pBuf的数据长度\
status:NRF的status寄存器的状态\
u8 SPI_NRF_ReadBuf(u8 reg,u8 *pBuf,u8 bytes)
{
u8 status, byte_cnt;
NRF_CE_LOW();
NRF_CSN_LOW(); //置低CSN,使能SPI传输
status = SPI_NRF_RW(reg); //发送寄存器号
for(byte_cnt=0;byte_cnt<bytes;byte_cnt++) //读取缓冲区数据
pBuf[byte_cnt] = SPI_NRF_RW(NOP);
NRF_CSN_HIGH(); //CSN拉高,完成
return status; //返回寄存器状态值
}
/*-----------------------------------------------------向NRF的寄存器中写入一串数据-------------------------------------------------------------*/
//reg : NRF的命令+寄存器地址\
pBuf:存储了将要写入写寄存器数据的数组,外部定义\
bytes: pBuf的数据长度\
status: NRF的status寄存器的状态
u8 SPI_NRF_WriteBuf(u8 reg ,u8 *pBuf,u8 bytes)
{
u8 status,byte_cnt;
NRF_CE_LOW();
NRF_CSN_LOW(); //置低CSN,使能SPI传输
status = SPI_NRF_RW(reg); //发送寄存器号
for(byte_cnt=0;byte_cnt<bytes;byte_cnt++) //向缓冲区写入数据
SPI_NRF_RW(*pBuf++);
NRF_CSN_HIGH(); //CSN拉高,完成
return (status); //返回NRF24L01的状态
}
/*----------------------------------------------------------配置并进入接收模式-------------------------------------------------------------*/
void NRF_RX_Mode(void)
{
NRF_CE_LOW();
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
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+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,接收模式
NRF_CE_HIGH(); //CE拉高,进入接收模式
}
/*----------------------------------------------------------配置发送模式-----------------------------------------------------------*/
void NRF_TX_Mode(void)
{
NRF_CE_LOW();
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,发射模式,开启所有中断
NRF_CE_HIGH(); //CE拉高,进入发送模式
Delay(0xffff); //CE要拉高一段时间才进入发送模式
}
/*---------------------------------------------------------主要用于NRF与MCU是否正常连接--------------------------------------------------------*/
//retval: SUCCESS/ERROR 连接正常/连接失败
u8 NRF_Check(void)
{
u8 buf[5]={0xC2,0xC2,0xC2,0xC2,0xC2};
u8 buf1[5];
u8 i;
SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址
SPI_NRF_ReadBuf(TX_ADDR,buf1,5); //读出写入的地址
for(i=0;i<5;i++) //判断是否连接成功
{
if(buf1[i]!=0xC2)
break;
}
if(i==5)
return SUCCESS ; //MCU与NRF成功连接
else
return ERROR ; //MCU与NRF不正常连接
}
/*-----------------------------------------------------向NRF的发送缓冲区中写入数据--------------------------------------------------------------*/
//txBuf:存储了将要发送的数据的数组,外部定义\
retval: 发送结果,成功返回TXDS,失败返回MAXRT或ERROR
u8 NRF_Tx_Dat(u8 *txbuf)
{
u8 state;
NRF_CE_LOW(); //CE为低,进入待机模式1
SPI_NRF_WriteBuf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF 最大 32个字节
NRF_CE_HIGH(); //CE为高,txbuf非空,发送数据包
while(NRF_Read_IRQ()!=0); //等待发送完成中断
state = SPI_NRF_ReadReg(STATUS); //读取状态寄存器的值
SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除TX FIFO寄存器
/*判断中断类型*/
if(state&MAX_RT) //达到最大重发次数
return MAX_RT;
else if(state&TX_DS) //发送完成
return TX_DS;
else
return ERROR; //其他原因发送失败
}
/*--------------------------------------------------------从NRF的接收缓冲区中读出数据------------------------------------------------------------*/
//rxBuf :用于接收该数据的数组,外部定义\
retval: 接收结果
u8 NRF_Rx_Dat(u8 *rxbuf)
{
u8 state;
NRF_CE_HIGH(); //进入接收状态
/*轮询标志*/
while(NRF_Read_IRQ()==0)
{
NRF_CE_LOW(); //进入待机状态
state=SPI_NRF_ReadReg(NRF_READ_REG+STATUS); //读取status寄存器的值
SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); //清除中断标志
/*判断是否接收到数据*/
if(state&RX_DR) //接收到数据
{
SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH); //读取数据
SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除RX FIFO寄存器
return RX_DR;
}
else
return ERROR; //没收到任何数据
}
return ERROR; //没收到任何数据
}
void Beep_ON(void)
{
GPIO_InitTypeDef GPIO_InitBeep;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitBeep.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitBeep.GPIO_Pin=GPIO_Pin_0;
GPIO_InitBeep.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitBeep);
GPIO_SetBits(GPIOC, GPIO_Pin_0);
}
void Beep_OFF(void)
{
GPIO_InitTypeDef GPIO_InitBeep;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitBeep.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitBeep.GPIO_Pin=GPIO_Pin_0;
GPIO_InitBeep.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitBeep);
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
}
(二)接收端main.c部分代码
int compare(u8 x[],u8 y[])
{
int a=0;
for(i=0;i<32;i++)
{
if(x[i]==y[i])
a++;
}
if(a==32)
return 1;
else
return 0;
}
void main(void)
{
int ans=0;
SPI_NRF_Init();
LED_GPIO_Config();
NRF_RX_Mode();
for(i=0;i<32;i++)
mishi[i]=i;
while(1)
{
status=NRF_Rx_Dat(rxbuf);
if(status==RX_DR)
ans=compare(rxbuf,mishi);
if(ans==1)
Beep_ON();
else
Beep_OFF();
}
// LED_RGB('R');
}
(三)发射端部分代码
SPI_NRF_Init();
NRF_TX_Mode();
if (count>57600)
{
//Beep_ON();
NRF_Tx_Dat(mishi);
}
else NRF_Tx_Dat(errorbuf);
复制代码
作者:
yueguang3048
时间:
2022-3-10 09:32
排查思路:
1.检查SPI读写功能
2.检查双方的地址,配置模式等等
3.接收方尝试通过串口打印信息
作者:
zhaobolove
时间:
2022-3-26 21:51
接收 建议用 中断, 你这样 接收程序要改一下。 要么你 在while里面加一个延时50ms试一试。
发送程序基本没有问题。如果间隔发送时间在50ms以上。
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1