×
单片机 > 单片机程序设计 > 详情

NRF24L01无线模块多机通信单片机程序 上位机+下位机

发布时间:2020-06-08 发布时间:
|

最近在接了一个项目,要求各个设备能够联网(不是互联网)控制。nrf24l01刚好有这个功能。但是之前只做过一对一的通信,还是用例程的那一种。我在想,用两个地址,共用同一个通道应该也可以完成。后来他又要求发过去的数据还要能回传,这下我只好来研究多通道通信了。

多机通信和一对一通信基本上相同,就是要配置其他通道的地址和使能其他通道的有效数据宽度,还有自动应答。

这是接收机的:

void NRF24L01_Init_RX(void)
{   
CE=0;   
CSN=1;   
SCK=0;   
SPI_Write_Buf(WRITE_REG + TX_ADDR, RX_ADDRESS, TX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P1, RX_ADDRESS1, RX_ADR_WIDTH);
SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);
SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);
SPI_Write_Reg(WRITE_REG + RF_CH, 40);
SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0F);
SPI_Write_Reg(WRITE_REG + CONFIG, 0x0f);
}

由于我用的是KeilC51和MDK5共存的,所以注释复制过来之后就成了乱码,在此贴图一张:

NRF24L01_Init_Rx(void)
下面就到了发送机了的配置了:

void NRF24L01_Init_TX(uint8_t *ADDRn)
{   
CE=0;
CSN=1;
SCK=0;
SPI_Write_Buf(WRITE_REG + TX_ADDR, (uint8_t*)ADDRn, TX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, (uint8_t*)ADDRn, RX_ADR_WIDTH);
SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);
SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);
SPI_Write_Reg(WRITE_REG + RF_CH, 40);
SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + SETUP_RETR, 0xff);
SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0f);
SPI_Write_Reg(WRITE_REG + CONFIG, 0x0E);
}

同样:


NRF24L01_Init_TX(uint8_t *ADDRn)
发送给其他通道,只要改成其他通道的地址就可以了,不用改通道号,现在还不知道为什么。

接下来就是发送函数:

uint8_t nRF24L01_TxPacket(unsigned char * tx_buf)
{
uint8_t Return_Flag=0;
CE=0;
SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);
Delayms(2);
Return_Flag = Check_ACK(1);
return Return_Flag;
}

由于我是通过电脑串口控制上位机,发给某一个下位机,然后再发回到我的上位机中,最后回传到电脑,所以没有数据抢答的问题。

最后再说一句,要配置第N个的通道,前N个通道也必须被配置,要不然配置不成功。

最后贴上上位机程序:

#include

#include

#include "nrf24l01.h"

#include "delay.h"

#define uint32_t unsigned int

#define uint8_t unsigned char


uint8_t const RX_ADDRESS[TX_ADR_WIDTH]= {0x01,0x13,0x5C,0x0C,0x03};        //本地地址

uint8_t const RX_ADDRESS1[TX_ADR_WIDTH]={0x02,0x13,0x5C,0x0C,0x03}; //本地地址1



extern uint8_t Rx_Buf[32];

extern uint8_t Tx_Buf[32];


/**********************************RNF24L01状态标志位************************************************/

uint8_t         bdata sta;   

sbit        RX_DR        =sta^6;

sbit        TX_DS        =sta^5;

sbit        MAX_RT        =sta^4;


/**********************************NRF24L01管脚与单片机接口定义**************************************/



sbit  MISO =P3^4;

sbit  MOSI =P3^6;

sbit SCK =P3^3;

sbit  CE =P3^2;

sbit CSN =P3^5;

sbit IRQ =P3^7;




/***************************************************************************

函数名称:uchar SPI_RW(uint8_t dat)

函数功能:NRF24L01的SPI写时序

函数备注:

***************************************************************************/

uint8_t SPI_RW(uint8_t dat)

{

        uint8_t i;

           for(i=0;i<8;i++) 

           {

                MOSI = (dat & 0x80);         

                dat = (dat << 1);           

                SCK = 1;                      

                dat |= MISO;                         

                SCK = 0;                              

           }

    return(dat);                             

}


/***************************************************************************

函数名称:uint8_t SPI_Read(uint8_t cmd_reg)

函数功能:NRF24L01的SPI读时序

函数备注:

***************************************************************************/

uint8_t SPI_Read(uint8_t cmd_reg)

{

        uint8_t value;

        

        CSN = 0;               

        SPI_RW(cmd_reg);            

        value = SPI_RW(0);    

        CSN = 1;                

        

        return(value);        

}


/***************************************************************************

函数名称:void SPI_Write_Reg(uint8_t cmd_reg, uint8_t value)

函数功能:写入NRF24L01寄寄存器和从NRF24L01寄存器中读出

函数备注:

***************************************************************************/

void SPI_Write_Reg(uint8_t cmd_reg, uint8_t value)

{        

        CSN = 0;                  

        SPI_RW(cmd_reg);     

        SPI_RW(value);            

        CSN = 1;                   

}


/***************************************************************************

函数名称:uint8_t SPI_Read_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

函数功能:从NRF24L01寄存器中读出数据

函数备注:reg:为寄存器地址,pBuf:为待读出数据地址,uint8_t:读出数据的个数

***************************************************************************/

uint8_t SPI_Read_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

{

        uint8_t status,i;

        

        CSN = 0;                                    

        status = SPI_RW(cmd_reg);                       

        for(i=0;i

        CSN = 1;                           

        

        return(status);                    

}


/***************************************************************************

函数名称:void SPI_Write_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

函数功能:在NRF24L01寄存器中写入数据

函数备注:reg:为寄存器地址,pBuf:为待写入数据地址,uint8_t:写入数据的个数

***************************************************************************/

void SPI_Write_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

{

        uint8_t i;        

        CSN = 0;            //SPI使能       

        SPI_RW(cmd_reg);   

        for(i=0; i

        CSN = 1;           //关闭SPI

}


/***************************************************************************

函数名称:uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)

函数功能:数据读取后放入rx_buf接收缓冲区中

函数备注:

***************************************************************************/

uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)

{

   uint8_t flag;

        CE = 1;                          //很重要!启动接收!

        Delayms(1);

        sta=SPI_Read(READ_REG+STATUS);        // 读取状态寄存其来判断数据接收状况           //寄存器前面要加是读还是写

        if(RX_DR)                                // 判断是否接收到数据  如果置1则说明接到数据并且放置在接收缓存器

        {

           CE = 0;                 

                SPI_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH); //这本来就是指令,不用加,意思说去缓存器里读

                flag =1;                        //读取数据完成标志

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
如何为单片机选择合适的负载电容