首先说下个人对这个模块的调试心得(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%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。