STM32
直播中

李平

7年用户 1207经验值
私信 关注
[问答]

如何去实现NRF24l01模块数据的接收与发送呢

SI24R1芯片的特性有哪些呢?
NRF24l01模块有哪几种工作模式呢?
如何去实现NRF24l01模块数据的接收与发送呢?


回帖(1)

李云逍

2021-12-16 15:28:55
首先说下个人对这个模块的调试心得(ACK模式):

  • CE控制的发射接收时序一定要控制好,多注意文档提供的时序参考。
  • 读写寄存器指令要加上R_REGISTER和W_REGISTER。
  • 有操作发射接收数据,一定要清空TX_FIFO和RX_FIFO,否则只能发射接收一次数据。
  • 有时频繁复位导致模块不正常,要重新上电(不知是不是我模块的问题....)。
  • 还有一个就是,这模块没有通过读写寄存器来检测发射接收有没有相互连接上。只是直接发送接收数据,有时就会卡在模块正确初始化和TX_FIFO写入正确发送之间,个人感觉调试起来有点麻烦。
SI24R1芯片特性:




  • 集成嵌入式ARQ基带协议引擎的无线收发器芯片,
  • 工作频率范围为2400MHz-2525MHz,126个1MHz带宽的信道。
  • 采用GFSK/FSK数字调制与调解技术,支持2Mbps,1Mbps,250Kbps。
  • 关断电流小于0.7uA,待机模式下时钟工作电流小于15uA。
管脚参数:







五种工作模式:



  • Shutdown:PWR_UP=0,此模式下收发功能关闭,芯片停止工作,消耗电流最小,内部寄存器和FIFO值不变,仍可读写。
  • Standby:PWR_UP=1,只有晶振工作。此模式下,CE=1时,进入到Idle-TX或RX模 式;CE=0时,返回Standby模式。
  • Idle-TX:晶振和时钟电路工作。FIFO为空,CE=1时,进入Idle-TX模式。此模式下,如果有 数据包被发送到TX FIFO中,则芯片内部电路启动,发送数据。
  • TX:此模式条件为:TX FIFO有数据,PWR_UP=1,PRIM_RX=0,CE有至少10us高脉冲。进入顺序为:Shutdown →2ms→ TX。发送数据后,CE=1, TX FIFO有数据,则继续在TX 模式下发送数据,否则进入Idle-TX模式。CE=0立即返回Standby模式。ACK模式中, 数据发送完成后,等待接收端应答。发送端接收到ACK信号,自动清除 TX FIFO数据并产生TX_DS中断。如果发送端在 ARD 时间内没有接收到 ACK 信号,则 重新发送上一帧数据。当重发次数达到最大,仍没有收到确认信号时,发送端产生MAX_RT 中断。MAX_RT 中断在清除之前不能进行下一步的数据发送。
  • RX:此模式条件为:PWR_UP=1,PRIM_RX=1,CE=1。当接收数据包地址与芯片地址相同,且CRC正确,数据会自动存入RX FIFO,并产生接收中断。最多同时存3个有效数据包。ACK模式中,接收端在发送 ACK 信号时,取接收管道地址作为目标地址来发送 ACK 信号,所以发送端需要设置接收管道 0 地址与自身发送地址相同,以便 接收 ACK 信号。   
重要延时:






指令:




  • 读写寄存器之前一定要进入待机模式或掉电模式。
  • 指令位由高到低,数据低字节到高字节,每字节由高位到低位。
  • 读寄存器:R_REGISTER+寄存器地址
  • 写寄存器:W_REGISTER+寄存器地址,寄存器值
参考代码:

主函数:


int main(void)
{
        LED_CONFIG();
        KEY_CONFIG();
        GPIO_CONFIG();
        Usart_Config();
        CHECK_DEVICE();
        CHECK_DEVICE_RX();
        NRF24_RX_MODE();
        delay_ms(10);
        while(1)
        {
                uint8_t buf[32] = {0};
                uint8_t a,rxx[32];
               
                if(KEY1())
                {
                        buf[0] = 0x88;
                        NRF24_TX_MODE();
                        LED_G(ON);
                        delay_ms(30);
                        LED_G(OFF);
                        TXPACKET(buf);
                        delay_ms(30);
                }
                buf[0] = 0;
                delay_ms(10);
                if(KEY2())
                {
                        RXPACKET(rxx);
                }                               
        }       
}


主要发射代码:


uint8_t DATAWIDTH=32;
uint8_t TX_ADDRESS[5]={0X3E,0x7E,0x7E,0x7E,0x7E};

//发送模式配置,ACK
void NRF24_TX_MODE(void)
{
        CE_L;
               
        SPI_WRITE_DATA(W_REGISTER+TX_ADDR,TX_ADDRESS,5);//写入发送地址,5字节
        SPI_WRITE_DATA(W_REGISTER+RX_ADDR_P0,TX_ADDRESS,5);//写入接收通道0地址,5字节

        SPI_RW_REG(W_REGISTER+FLUSH_TX,0xFF);//清空TX_FIFO
        SPI_RW_REG(W_REGISTER+EN_AA,0X01);//使能自动确认
        SPI_RW_REG(W_REGISTER+EN_RXADDR,0X01);//使能接收通道0
        SPI_RW_REG(W_REGISTER+SETUP_RETR,0X25);//750us自动重发延时,自动重发5次
        SPI_RW_REG(W_REGISTER+RF_CH,40);//射频通道40
        SPI_RW_REG(W_REGISTER+RF_SETUP,0X0F);//速率2Mbps,功率7dBm
        SPI_RW_REG(W_REGISTER+CONFIG,0X0E);//发送模式,2 Byte CRC

        CE_H;
        delay_ms(1);
}

//发送数据包
uint8_t TXPACKET(uint8_t *tx)
{
        uint8_t status;
       
        SPI_RW_REG(FLUSH_TX,DUMMY);
       
        CE_L;
        SPI_WRITE_DATA(W_TX_PAYLOAD,tx,DATAWIDTH);
        CE_H;
       
        while(IRQ_TX);
        status=SPI_R_REG(STATUS);
        SPI_RW_REG(W_REGISTER+STATUS,status);//清除标志位
        printf("status=0x%xn",status);
        if(status&0x10)
        {
                SPI_RW_REG(W_REGISTER+FLUSH_TX,0xFF);
                printf("数据发送失败,达到最大发送次数!n");
                return 0;               
        }
        if(status&0x20)
        {
                SPI_RW_REG(W_REGISTER+FLUSH_TX,0xFF);
                printf("数据发送完成!n");
                return 1;               
        }
}


主要接收射代码:

extern uint8_t DATAWIDTH;
extern uint8_t TX_ADDRESS[5];

//发送模式配置,ACK
void NRF24_RX_MODE(void)
{
        CE_L;
       
        SPI_WRITE_DATA(W_REGISTER+RX_ADDR_P0,TX_ADDRESS,5);//写入接收通道0地址,5字节
       
        SPI_RW_REG(W_REGISTER+FLUSH_RX,0xFF);//清空RX_FIFO
        SPI_RW_REG(W_REGISTER+EN_AA,0X01);//使能自动确认
        SPI_RW_REG(W_REGISTER+EN_RXADDR,0X01);//使能接收通道0
        SPI_RW_REG(W_REGISTER+RF_CH,40);//射频通道40
        SPI_RW_REG(W_REGISTER+RX_PW_P0,DATAWIDTH);//设置接收通道0,与发送字节相同
        SPI_RW_REG(W_REGISTER+RF_SETUP,0X0F);//速率2Mbps,功率7dBm
        SPI_RW_REG(W_REGISTER+CONFIG,0X0F);//接收送模式,2 Byte CRC
       
        CE_H;
}

//接收数据
uint8_t RXPACKET(uint8_t *rx)
{
        uint8_t status,rdata[32];
       
        while(IRQ_RX);
       
        status=SPI_R_REG(STATUS);
        SPI_RW_REG(W_REGISTER+STATUS,status);//清除标志位
        printf("status=0x%xn",status);
       
        if(status&0x40)
        {
                SPI_READ_DATA(R_RX_PAYLOAD,rdata,32);               
                SPI_RW_REG(W_REGISTER+FLUSH_RX,0xFF);
                printf("接收的数据为:0x%xn",rdata[0]);
                return 1;               
        }
        else
                printf("数据接收失败!n");
                return 0;       
}


SPI参考代码:

发射接收模块共用MISO,MOSI,SCK,CE,IQR脚,CS不同管脚。默认上电SCK,CE为低,CS为高。

/*NRF24LO1指令定义*/

#define R_REGISTER 0x00
#define W_REGISTER 0x02
#define DUMMY      0x00

#define RX_PAYLOAD        0X61
#define TX_PAYLOAD        0XA0
#define FLUSH_TX 0XE1
#define FLUSH_RX 0XE2
#define RX_WID 0X60
#define NOP 0XFF
#define CONFIG 0X00
#define EN_AA 0X01
#define EN_RXADDR 0X02
#define SETUP_AW 0X03
#define SETUP_RETR 0X04
#define RF_CH 0X05
#define RF_SETUP 0X06
#define STATUS 0X07
#define OBSERVE_TX 0X08
#define RX_ADDR_P0 0X0A
#define RX_PW_P0 0X11
#define TX_ADDR 0X10
#define FIFO_STATUS 0X17
#define DYNPD 0X1C
#define FEATURE 0X1D

//读写字节
static uint8_t SPI_RW_BYTE(uint8_t wdata)//MSB
{
        uint8_t i;
        uint8_t rdata;
        //发送数据
        for(i=0;i<8;i++)
        {
                SCK_L;
                delay_us(5);
                ((wdata<                 delay_us(5);
               
                //接收数据
                rdata<<=1;
                SCK_TX;
                rdata|=MISO;
                delay_us(5);
                SCK_L;
        }       
        return rdata;
}

//指令读写
static uint8_t SPI_RW_REG(uint16_t cmd,uint16_t val)
{       
        uint8_t status;
        CS_L;
        status=SPI_RW_BYTE(cmd);
        SPI_RW_BYTE(val);
        CS_H;
        return status;
}

//读寄存器
static uint8_t SPI_R_REG(uint16_t reg)
{       
        uint8_t status;
        CS_L;
        SPI_RW_BYTE(reg);
        status=SPI_RW_BYTE(DUMMY);
        CS_H;
        return status;
}

//写数据
static uint8_t SPI_WRITE_DATA(uint8_t cmd,uint8_t *wdata,uint8_t wnum)
{
        uint8_t status;
        CS_L;
        status=SPI_RW_BYTE(cmd);
        while(wnum)
        {
                SPI_RW_BYTE(*wdata++);
                //wdata++;
                wnum--;
        }
        CS_H;
        return status;
}

//读数据
static uint8_t SPI_READ_DATA_RX(uint16_t cmd,uint8_t *rdat,uint8_t wnum)
{
        uint8_t status;
        CS_L;
        status=SPI_RW_BYTE(cmd);       
        while(wnum)
        {
                *rdat=SPI_RW_BYTE(DUMMY);
                rdat++;
                wnum--;
        }
        CS_H;
        return status;
}


测试结果:

分别按下KEY1,KEY2。






举报

更多回帖

发帖
×
20
完善资料,
赚取积分