注意:NRF24L01 无论是一对一通信,还是一对多通信,其实本质上同一时刻是一对一通信,它是属于半双工通信。你只需要先调通一对一的通信,无论是一对2,一对六也是同一个原理。(基础SPI知识和NRF24L01基础知识不多说)
一、项目背景
1.1项目材料
4块STM32F103C8T6的自制板子,4块NRF24L01无线通信模块。
1.2项目功能
一台主机单片机,进行对三个从机单片机进行监听接收,与三台从机进行交互。(也就是说主机只接收,从机只发送。具体想丰富交互可以自行拓展)
二、主机主要配置代码
2.1主机主要配置代码地址
const u8 TX_ADDRESS0[TX_ADR_WIDTH] = {0x00,0xff,0xff,0xff,0xff};
const u8 TX_ADDRESS1[TX_ADR_WIDTH] = {0x01,0xfe,0xaa,0xaa,0xaa};
const u8 TX_ADDRESS2[TX_ADR_WIDTH] = {0x02};
const u8 RX_ADDRESS0[RX_ADR_WIDTH] = {0x00,0xff,0xff,0xff,0xff};
const u8 RX_ADDRESS1[RX_ADR_WIDTH] = {0x01,0xfe,0xaa,0xaa,0xaa};
const u8 RX_ADDRESS2[RX_ADR_WIDTH] = {0x02};
这里一定要注意一下,通道2到通道5,这里配置只需要一个字节的地址。
2.2主机主要接收代码
void NRF_RX_Mode_BC(void)
{
NRF_CE_LOW();
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS0,RX_ADR_WIDTH); //写RX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDRESS1,RX_ADR_WIDTH); //写RX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDRESS1,1); //写RX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P2,(u8*)RX_ADDRESS2,1); //写RX节点地址
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x3f); //使能通道0的自动应答
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x3f); //使能通道0的接收地址
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,40); //设置RF通信频率
SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH); //选择通道0的有效数据宽
SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH); //选择通道1的有效数据宽
SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P2,RX_PLOAD_WIDTH); //选择通道2的有效数据宽
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拉高,进入接收模式*/
__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();
}
主机设置好接收代码,一通道地址需要重写。重写的时候只写入一通道低字节数据,然后2、3、4、5通道也只写入低字节就可以了,因为2、3、4、5通道地址是共用一通道的后四个高字节地址的。
三、从机主要配置代码
3.1从机主要配置代码地址
const u8 TX_ADDRESS0[TX_ADR_WIDTH] = {0x00,0xff,0xff,0xff,0xff};
const u8 TX_ADDRESS1[TX_ADR_WIDTH] = {0x01,0xfe,0xaa,0xaa,0xaa};
const u8 TX_ADDRESS2[TX_ADR_WIDTH] = {0x02,0xfe,0xaa,0xaa,0xaa};
const u8 RX_ADDRESS0[RX_ADR_WIDTH] = {0x00,0xff,0xff,0xff,0xff};
const u8 RX_ADDRESS1[RX_ADR_WIDTH] = {0x01,0xfe,0xaa,0xaa,0xaa};
const u8 RX_ADDRESS2[RX_ADR_WIDTH] = {0x02,0xfe,0xaa,0xaa,0xaa};
从机通道2到通道5,这里代码需要为满5个字节!!!,不能跟主机一样。(自己好好对比一下)
3.2从机主要发送代码
3.2.1 从机1发送代码
void NRF_TX_Mode_BC(void)
{
NRF_CE_LOW();
SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS0,TX_ADR_WIDTH); //写TX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS0,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x3f); //使能通道0的自动应答
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x3f); //使能通道0的接收地址
SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a); //设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,40); //设置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_ms(1); //3 Delay(0x5555); //CE要拉高一段时间才进入发送模式
__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();
}
从机1配置的是通道0的地址代码!!!
3.2.2 从机2发送代码
void NRF_TX_Mode_BC(void)
{
NRF_CE_LOW();
SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS1,TX_ADR_WIDTH); //写TX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS1,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x3f); //使能通道0的自动应答
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x3f); //使能通道0的接收地址
SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a); //设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,40); //设置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_ms(1); //3 Delay(0x5555); //CE要拉高一段时间才进入发送模式
__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();
}
从机2主要配置通道1地址代码!!!
3.2.3 从机3发送代码
void NRF_TX_Mode_BC(void)
{
NRF_CE_LOW();
SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS2,TX_ADR_WIDTH); //写TX节点地址
SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS2,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x3f); //使能通道0的自动应答
SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x3f); //使能通道0的接收地址
SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a); //设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,40); //设置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_ms(1); //3 Delay(0x5555); //CE要拉高一段时间才进入发送模式
__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();
}
从机3主要配置通道2地址代码!!!
四、主机通道选择代码
u8 NRF_Rx_Dat(u8 *rxbuf)
{
u8 state;
u8 RX_P_NO;
NRF_CE_HIGH(); //进入接收状态
/*等待接收中断*/
while(NRF_Read_IRQ()==0)
{
NRF_CE_LOW(); //进入待机状态
/*读取status寄存器的值 */
state=SPI_NRF_ReadReg(STATUS);
//RX_P_NO=SPI_NRF_ReadReg(RF_CH);
/* 清除中断标志*/
SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state);
/*判断是否接收到数据*/
if(state&RX_DR) //接收到数据
{
RX_P_NO = state & 0x0e; //获取通道号
switch (RX_P_NO)
{
case 0x00:
SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除RX FIFO寄存器
break;
case 0x02:
SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除RX FIFO寄存器
break;
case 0x04:
SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除RX FIFO寄存器
break;
default:
SPI_NRF_WriteReg(FLUSH_RX,NOP); //清除RX FIFO寄存器
break;
}
return RX_DR;
}
else
return ERROR; //没收到任何数据
}
return ERROR; //没收到任何数据
}
去通过状态寄存器去判断它传输的通道。这段代码主要是判断是那个从机发过来
NRF24L01模块是比较不稳定的模块。
(1)该模块的天线在PCB上,没有加功率芯片,属于传输距离最短的模块。空旷条件下,经过实测,2M传输速率下15 米,1M传输速率30米,250K传输速率50米。
(2)该模块的天线是外置天线,没有加功率芯片,传输距离比前者在每种速率下大概大了1倍的传输距离。
(3)该模块既加了外置天线,又加了功放芯片,在250K传输速率下,传输距离可达1100米。
所以我们在选择通信模块的时候需要注意这些方面。希望对大家调试NRF24L01通信模块有帮助,亲测已经实现一主机多从机发送的实验!!!