NRF24l01的使用(附stm32主要代码)

本文详细介绍了无线收发器SI24R1的调试经验,包括ACK模式下的发射接收时序控制、寄存器操作、工作模式切换以及重要延时。此外,还分享了读写寄存器的注意事项和参考代码,展示了如何在发射和接收模式下配置模块。测试结果显示模块能正常进行数据传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先说下个人对这个模块的调试心得(ACK模式):

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

SI24R1芯片特性:

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

管脚参数:

 

五种工作模式:

  1. Shutdown:PWR_UP=0,此模式下收发功能关闭,芯片停止工作,消耗电流最小,内部寄存器和FIFO值不变,仍可读写。
  2. Standby:PWR_UP=1,只有晶振工作。此模式下,CE=1时,进入到Idle-TX或RX模 式;CE=0时,返回Standby模式。
  3. Idle-TX:晶振和时钟电路工作。FIFO为空,CE=1时,进入Idle-TX模式。此模式下,如果有 数据包被发送到TX FIFO中,则芯片内部电路启动,发送数据。
  4. 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 中断在清除之前不能进行下一步的数据发送。
  5. 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%x\n",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%x\n",status);
	
	if(status&0x40)
	{
		SPI_READ_DATA(R_RX_PAYLOAD,rdata,32);		
		SPI_RW_REG(W_REGISTER+FLUSH_RX,0xFF);
		printf("接收的数据为:0x%x\n",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<<i)&0x80)? MOSI_H : MOSI_L;
		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。

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值