NRF24L01P芯片的通信

之前有写一篇学习SPI通讯协议的文章,这次就通过NRF24L01+这款2.4G无线芯片来实际应用一下SPI协议,主控芯片用的STC15系列。

初始化

首先根据NRF24L01P的芯片手册对其进行初始化

void NRF_RC_Init(void)
{
    NRF_WriteRegister(NRF_REG_CONFIG,(RX_IRQ_ENABLE | TX_IRQ_ENABLE | MAX_RT_IRQ_ENABLE | CRC_ON | CRC_1bytes | PWR_DOWN | RX_ON)); //寄存器初始化,使能这些寄存器
    NRF_WriteRegister(NRF_REG_EN_AA, ENAA_ALL_DISABLE);     		//使能自动应答(不使用自动应答)
    
    NRF_WriteRegister(NRF_REG_EN_RXADDR, ERX_P0);           		//ENABLE P0 RX 使能pipe0作为RX通道
    NRF_WriteRegister(NRF_REG_SETUP_RETR, ARC_RE_Transmit_Diable);  //设置自动重传,自动重传0

    NRF_WriteRegister(NRF_REG_RF_SETUP,RF_DR_2Mbps | RF_PWR_N0dBm); //设置频率和功率,频率为2Mbps,设置射频输出频率为0dBm
    NRF_WriteRegister(NRF_REG_RX_PW_P0, NRF_BUFFER_SIZE);           //数据管0中RX有效负载的字节数,设为19

    NRF_RX_address(RC_Address); 									//读取地址,地址五个字节,可以自己设置
    NRF_TX_address(RC_Address); 									//接收地址,地址五个字节,可以自己设置
    
    NRF_WriteRegister(NRF_REG_RF_CH, NRF_RC_DEFUAL_CHANNEL);    	//设置NRF运行频率(通道)
    NRF_WriteRegister(NRF_REG_STATUS, CLEAR_RX_IRQ | CLEAR_TX_IRQ | CLEAR_MAX_RT_IRQ);  //清除RX、TX、RT状态寄存器
    NRF_TX_mode();                                      			//进入TX模式
    printf("\nNRF_RC_Init_OK\n");
}

有一些封装好的函数这里贴一下:

// 写寄存器函数
void NRF_WriteRegister(u8 address, u8 command)
{
    CS=0;
    soft_SPI_RW_MODE00(W_REGISTER | address);
    soft_SPI_RW_MODE00(command);
    CS=1;
}
//读寄存器函数
uint8_t NRF_ReadRegister(u8 address)
{
    u8 read_data;
    CS=0;
    soft_SPI_RW_MODE00(R_REGISTER | address);
    read_data = soft_SPI_RW_MODE00(NOP);
    CS=1;
    return read_data;
}
//TX地址
void NRF_TX_address(uint8_t address[])
{
    uint8_t i;
    CS=0;
    soft_SPI_RW_MODE00(W_REGISTER + NRF_REG_TX_ADDR);	//将地址写入TX_ADDR寄存器中
    for (i = 0; i < 5; i++)
    {
        soft_SPI_RW_MODE00(address[i]);
    }
    CS=1;
}
//RX地址
void NRF_RX_address(uint8_t address[])
{
    uint8_t i;
    CS=0;
    soft_SPI_RW_MODE00(W_REGISTER + NRF_REG_RX_ADDR_P0);//将地址写入RX_ADDR pipe0中
    for (i = 0; i < 5; i++)
    {
        soft_SPI_RW_MODE00(address[i]);
    }
    CS=1;
}

在想要对NRF进行寄存器写入操作时,需要先写入一个指令:soft_SPI_RW_MODE00(W_REGISTER | address),再进行写入的操作;读指令同理:soft_SPI_RW_MODE00(R_REGISTER | address)。
在这里插入图片描述

在想要进行读操作时,可以写入NOP(0XFF)。在这里插入图片描述

测试主控与NRF的SPI通讯是否正常

这里就不贴代码了,说一下大概思路。把NRF所有被配置过的寄存器的值全部通过NRF_ReadRegister函数读出来,在与写入的值进行比对,如果值相同说明没有问题,如果某个值出错了就输出错误就好了。我这里测出来的通讯是正常的所以直接进行下一步了,让两个NRF芯片通过无线进行通讯。

无线通讯

在这里插入图片描述根据图中的步骤配置好NRF的寄存器。

准备两个NRF芯片,一个作为发送端,另一个作为接收端,从而实现2.4G无线单向通讯。说一下大概思路。发送端在配置好寄存器后,需要进入TX_MODE才能作为发送端使用,接收端需要进入RX_MODE。

如果想要进入TX或RX模式,需要先进入stand by模式,即power_up置1,然后CE管脚先拉低,再去对切换TX、RX模式的寄存器的对应位进行写操作。

//TX模式
void NRF_RX_mode(void)
{
    CE=0;
    NRF_WriteRegister(NRF_REG_CONFIG, RX_IRQ_ENABLE | TX_IRQ_ENABLE | MAX_RT_IRQ_ENABLE | CRC_ON | CRC_1bytes | PWR_UP | RX_ON);
    CE=1;
}
//RX模式
void NRF_TX_mode(void)
{
    CE=0;
    NRF_WriteRegister(NRF_REG_CONFIG, RX_IRQ_ENABLE | TX_IRQ_ENABLE | MAX_RT_IRQ_ENABLE | CRC_ON | CRC_1bytes | PWR_UP | TX_ON);
    CE=1;
}

进入TX_MODE之后就可以发送数据了,需要发送的数据会从TX_FIFO寄存器中发送出去。这里需要一个函数将数据写入FIFO中(可能表述不太准确)。

void NRF_FIFO_WRITE(uint8_t *d,uint8_t len)
{
    uint8_t i=0;
    CS=0;		//片选拉低
    soft_SPI_RW_MODE00(W_TX_PAYLOAD);
    for(i=0;i<len;i++)
        soft_SPI_RW_MODE00(d[i]);
    CS=1;		
}

在写入需要发送的数据之前,需要先写入一个指令:W_TX_PAYLOAD
在这里插入图片描述
完整的程序如下,这里做一个简单的应用,发送端每隔2ms发送一次系统运行时间:

void main(void)
{
	Timer0Init();
    ES = 1;
    ET0 = 1;
    EA = 1;
    NRF_RC_Init();					//初始化NRF
    nrf_check_all_reg_status();		//检测NRF寄存器的值
	NRF_TX_mode();					//进入TX模式
	if(millis()>=(RC_WRITE_HANDLE_PERIOD+RC_WRITE_HANDLE_TIME))
	{
     	RC_WRITE_HANDLE_TIME=millis();//计时
     	RED_LED_ON();
     	rc_txdata_handle();			//数据处理函数
     	NRF_FIFO_WRITE(nrf_tx_buffer,NRF_BUFFER_SIZE);//发送数据
     	NRF_CLEAR_TX_IRQ();			//发送完后清掉中断标志位
	}
}

有一段数据处理函数如下:

//数据处理函数
void rc_txdata_handle(void)
{
    trans_data.time = millis();
    nrf_tx_buffer[0]=trans_data.read_byte[0];
    nrf_tx_buffer[1]=trans_data.read_byte[1];
    nrf_tx_buffer[2]=trans_data.read_byte[2];
    nrf_tx_buffer[3]=trans_data.read_byte[3];
    printf("trans_data.time=%ld\n",(long)trans_data.time);
    // printf("nrf_tx_buffer[0]=%x\n",(int)nrf_tx_buffer[0]);
    // printf("nrf_tx_buffer[1]=%x\n",(int)nrf_tx_buffer[1]);
    // printf("nrf_tx_buffer[2]=%x\n",(int)nrf_tx_buffer[2]);
    // printf("nrf_tx_buffer[3]=%x\n",(int)nrf_tx_buffer[3]);
}

这里用到了之前学过的联合体union来处理数据。
接收端的代码如下:

while(1)
   {
       NRF_RX_mode();
       
       while (IRQ)		//接收标志位,如果在发送或接收过程中为高电平,结束后为低电平
            {
                static uint16_t wait;		//等待接收完成
                if(++wait>1000)
                {
                    wait=0;
                    break;
                }
            }
            if(!IRQ)			//接收完成后读取接收到的数据并处理
            {
                
                uint8_t status = NRF_ReadRegister(NRF_REG_STATUS);
                if (status & CLEAR_RX_IRQ)	//若该位为0则为空,为1说明有数据传入
                {
                    RED_LED_ON();
                    NRF_WriteRegister(NRF_REG_STATUS, CLEAR_RX_IRQ);
                    NRF_FIFO_READ(nrf_rx_buffer, NRF_BUFFER_SIZE);
                    rc_rxdata_handle();
                    NRF_FIFO_FLUSH(FLUSH_RX);	//清除RX_FIFO中的数据 准备下一次数据接收。
                    
                }
            }
   }

通过上面的几段代码就可以实现两片NRF芯片的单向通讯了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值