1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
NRF24L01+硬件资源
运行条件: 电压:最小值=1.9V;典型值=3.0V;最大值=3.6V; 有一些反映不小心接入5V的电,烧模块,只是经验,值得注意。如果要接入5V,需要使用电阻进行分压,可通过U=RI进行计算。 工作温度:-40℃——85℃。典型值=27℃ 工作模式 上电之后,要等待100ms的时间让其渡过上电不稳定状态,进入TX/RX模式时,有130微秒的等待时间,一定要让PLL准备好,不然数据有可能乱码。 下图中,黑色粗框是官方推荐的模式转换线路,虚框是过渡状态,该状态下一定会转换到下一个状态。 接收地址与发送地址的理解 PTX端(发射端)需要用到的地址:TX_ADDR和RX_ADDR_P0。(使用P0通道进行通信,使用其他通道x,地址就写:RX_ADDR_Px。) PRX端(接收端)需要用到的地址:RX_ADDR_P0。(使用P0通道进行通信或者Px) PTX的职责:1、发送数据给接收端(PRX);2、接收PRX的应答信号(ACK) PRX的职责:1、接收发送端的发送数据;2、发送应答信号(ACK)给PTX 所以: ①当我们写入5个字节的地址在TX_ADDR中时,PTX以TX_ADDR中的地址为目标,把FIFO中的数据发送到空中; ②PRX在空中收到信号后,把目的地址拿出来与RX_ADDR_P0中的地址对比(自动进行),匹配则说明时发送给自己的,并接收; ③PRX通道RX_ADDR_P0回复ACK; ④PTX接收ACK,目的地址与自身的RX_ADDR_P0对比,一致,则说明ACK发送给自己,最后确认收到ACK应答信号,通讯完成。 一对一模式(一收一发) 拿stm32f103为例,其他芯片可以参考其思路。 1、启用外设时钟:SPI1、GPIOA、AFIO(开启中断时)、USART1(使用串口时) 2、初始化SPI1的IO引脚,外部中断,串口 void GPIO_SPI1_Init(void) //SPI1引脚初始化 { GPIO_InitTypeDef pa; pa.GPIO_Mode=GPIO_Mode_AF_PP; //SCK(pa5)、MOSI(pa7)推挽复用 pa.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_7; pa.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&pa); pa.GPIO_Mode=GPIO_Mode_IPU; pa.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_1; //MISO(pa6)、IRQ(pa1)上拉输入 pa.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&pa); pa.GPIO_Mode=GPIO_Mode_Out_PP; pa.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_4; //CE(pa2)、CSN(pa4)推挽输出 pa.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&pa); GPIO_SetBits(GPIOA,GPIO_Pin_7|GPIO_Pin_4); GPIO_ResetBits(GPIOA,GPIO_Pin_5); } void EXTI1_Init(void) //外部中断初始化相关 { EXTI_InitTypeDef exti1; NVIC_InitTypeDef nvic; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); exti1.EXTI_Line=EXTI_Line1; exti1.EXTI_LineCmd=ENABLE; exti1.EXTI_Mode=EXTI_Mode_Interrupt; exti1.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&exti1); nvic.NVIC_IRQChannel=EXTI1_IRQn; nvic.NVIC_IRQChannelCmd=ENABLE; nvic.NVIC_IRQChannelPreemptionPriority=2; nvic.NVIC_IRQChannelSubPriority=2; NVIC_Init(&nvic); } void USART1_Init(void) //串口初始化相关 { GPIO_InitTypeDef pa9,pa10; USART_InitTypeDef usart1; pa9.GPIO_Mode=GPIO_Mode_AF_PP; pa9.GPIO_Pin=GPIO_Pin_9; pa9.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&pa9); pa10.GPIO_Mode=GPIO_Mode_IN_FLOATING; pa10.GPIO_Pin=GPIO_Pin_10; pa10.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&pa10); usart1.USART_BaudRate=9600; usart1.USART_HardwareFlowControl=USART_HardwareFlowControl_None; usart1.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; usart1.USART_Parity=USART_Parity_No; usart1.USART_StopBits=USART_StopBits_1; usart1.USART_WordLength=USART_WordLength_8b; USART_Init(USART1,&usart1); USART_Cmd(USART1,ENABLE); } 3、初始化SPI1,并使能。 void SPI1_Init(void) { SPI_InitTypeDef spi1; spi1.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_16; spi1.SPI_CPHA=SPI_CPHA_1Edge; spi1.SPI_CPOL=SPI_CPOL_Low; spi1.SPI_CRCPolynomial=7; spi1.SPI_DataSize=SPI_DataSize_8b; spi1.SPI_Direction=SPI_Direction_2Lines_FullDuplex; spi1.SPI_FirstBit=SPI_FirstBit_MSB; spi1.SPI_Mode=SPI_Mode_Master; spi1.SPI_NSS=SPI_NSS_Soft; SPI_Init(SPI1,&spi1); SPI_Cmd(SPI1,ENABLE); } 4、初始化模块,进入Standby-I模式 void NRF24L01_TX_Init(void) { TX_CE=0; TX_CSN=1; } /* *TX_CE、TX_CSN已经通过宏定义到指定F103上的引脚。CE为工作模式选择,CSN为片选 * / 5、配置模块工作状态,根据CONFIG寄存器的不同,有PTX,PRX模式可选 PTX_Mode初始化步骤 24L01 相关寄存器(节点地址、通信频率、发射参数、有效数据宽度、CRC、EN_AA都要与PRX一致) 1)写 Tx 节点的地址 TX_ADDR 2)写 Rx 节点的地址(主要是为了使能 Auto Ack) RX_ADDR_P0 3)使能 AUTO ACK EN_AA 4)使能 PIPE 0 EN_RXADDR 5)配置自动重发次数 SETUP_RETR 6)选择通信频率 RF_CH 7)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP 8 ) 选择通道 0 有效数据宽度 Rx_Pw_P0 9)配置 24L01 的基本参数以及切换工作模式 CONFIG PRX_Mode初始化步骤 24L01 相关寄存器 1)写 Rx 节点的地址 RX_ADDR_P0 2)使能 AUTO ACK EN_AA 3)使能 PIPE 0 EN_RXADDR 4)选择通信频率 RF_CH 5) 选择通道 0 有效数据宽度 Rx_Pw_P0 6)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP 7)配置 24L01 的基本参数以及切换工作模式 CONFIG void NRF24L01_TX_Mode(void) { TX_CE=0; NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH); NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01); NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1A); NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0F); NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0E); TX_CE=1; delay_us(10); //如果是连续发射,在初始化阶段就要拉高CE10us以上,一个一个包发送等到发送在拉高 } void NRF24L01_RX_Mode(void) { RX_CE=0; NRF24L01_RX_WRITE_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+EN_AA,0x01); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RF_CH,40); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RF_SETUP,0x0F); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+CONFIG,0x0F); RX_CE=1; delay_us(130); //开始进入接收模式,等待130us } 6、处理中断,并发送/接收信号 /*这是PTX端的中断函数*/ void EXTI1_IRQHandler(void) { u8 status; if(EXTI_GetITStatus(EXTI_Line1)!=RESET) { status=NRF24L01_Read_Reg(STATUS); NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,status); if(status&MAX_TX) { NRF24L01_Write_Reg(FLUSH_TX,NOP); printf("rnMAX_TX"); } else if(status&TX_OK) { printf("rnTX_OK"); } else { printf("rn0xF5"); } EXTI_ClearITPendingBit(EXTI_Line1); } } /*这是PRX端的中断函数*/ void EXTI1_IRQHandler(void) { u8 status; u8 rxbuf[32]; //在main.c文件中引用该rxbuf变量 if(EXTI_GetITStatus(EXTI_Line1)!=RESET) { status=NRF24L01_RX_READ_Reg(STATUS); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+STATUS,status); printf("rnZD"); if(status&RX_OK) { NRF24L01_RX_READ_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH); NRF24L01_RX_WRITE_Reg(FLUSH_RX,NOP); printf("rn%s",rxbuf); } EXTI_ClearITPendingBit(EXTI_Line1); } } 多对一模式(六发一收) 初始化阶段,跟一对一通讯一样。唯一的区别就是在与接收通道不一样。 通道0(PX_ADDR_P0)可以写入32字节的任意地址; 通道1(PX_ADDR_P1)也可以写入32字节的任意地址,但是会对之后的P2~P5有影响; 通道2~通道5(PX_ADDR_P2~PX_ADDR_P5),在写入地址之前,一定要先写入P1的通道的地址,P2~P5高4字节地址跟P1的地址一致,低1字节可以自己手动写入。 如果要开启ACK应答,设置EN_AA与EN_RXADDR寄存器,要使用通道x,前面的x-1通道也要开启。如要使用通道3,那么通道0~通道2都要开启功能。 /*PTX端使用P2通道通讯*/ void NRF24L01_TX_Mode(void) { TX_CE=0; // NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH); // NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); /*P1通道,TX_ADDRESS_P1是自定义的32字节数组*/ // NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS_P1,TX_ADR_WIDTH); // NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)TX_ADDRESS_P1,RX_ADR_WIDTH); /*P2*/ NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS_P2,TX_ADR_WIDTH); NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)TX_ADDRESS_P2,TX_ADR_WIDTH); NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x3F); NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x3F); NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1A); NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0F); NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0E); TX_CE=1; delay_us(10); //如果是连续发射,在初始化阶段就要拉高CE10us以上,一个一个包发送就除外 } /*进入接收模式*/ void NRF24L01_RX_Mode(void) { RX_CE=0; NRF24L01_RX_WRITE_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); NRF24L01_RX_WRITE_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDRESS_P1,RX_ADR_WIDTH); //新增P1通道地址 NRF24L01_RX_WRITE_Buf(NRF_WRITE_REG+RX_ADDR_P2,(u8*)RX_ADDRESS_P2,1); //设置P2通道地址 NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+EN_AA,0x3F); //使能所有通道自动应答 NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+EN_RXADDR,0x3F); //使能所有通道接收地址 NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RF_CH,40); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RF_SETUP,0x0F); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+DYNPD,0x3F); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+FEATURE,0x06); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH); //新增P1通道有效数据宽度 NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+RX_PW_P2,RX_PLOAD_WIDTH); //新增P2通道有效数据宽度 NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+CONFIG,0x0F); RX_CE=1; delay_us(130); } 使用ACK自动回复带数据功能 使用ACK带数据回复,是一个十分有用的功能,让PTX/PRX能交换一些数据,而不用来回切换收/发角色。 在PRX端收到数据后,MCU如果能在130us内将数据写入到FIFO寄存器中,那么在回复ACK信号时,会将FIFO内的数据带上,传输回去给PTX,以下图形象的说明了经过。 配置过程,其他跟上面一样,区别在于启用ACK回复带数据功能 发送端和接收端配置要一致: ▝ 启用DPL功能,DYNPD寄存器写0x3F,开启所有通道 ▝ 启用FEATURE寄存器,写0x06,激活DPL,EN_ACK_PAY 以下接收端设置: 使用W_ACK_PAYLOAD命令(10101xxx)在130us内,在对应通道写入回复数据 0xA8:通道0 0xAB:通道3 0xA9:通道1 0xAC:通道4 0xAA:通道2 0xAD:通道5 /*进入接收模式*/ void NRF24L01_RX_Mode(void) { RX_CE=0; ...... NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+DYNPD,0x3F); //开启所有通道 NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+FEATURE,0x06); //激活DPL,EN_ACK_PAY ...... NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+CONFIG,0x0F); RX_CE=1; delay_us(130); } /*PRX端的ACK回复*/ void EXTI1_IRQHandler(void) { u8 status,receive_length; u8 ack_buf[32]={0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x60,0x61}; if(EXTI_GetITStatus(EXTI_Line1)!=RESET) { status=NRF24L01_RX_READ_Reg(STATUS); NRF24L01_RX_WRITE_Reg(NRF_WRITE_REG+STATUS,status); printf("rnZD"); if(status&RX_OK) { NRF24L01_RX_WRITE_Buf(0xAA,ack_buf,32); //在P2通道写入ack_buf NRF24L01_RX_READ_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH); //读取接收数据 NRF24L01_RX_WRITE_Reg(FLUSH_RX,NOP); //刷新接收缓存 printf("rn%s",rxbuf); //打印接收到的数据 } EXTI_ClearITPendingBit(EXTI_Line1); } } ART回复时间 在2Mbps模式下,ack有效载荷大于15字节,则ARD必须大于500us 在1Mbps模式下,ack有效载荷大于5字节,则ARD必须大于500us 在250kbps模式下,不论有没有有效载荷,ARD必须大于500us 对于250kbps模式,ART时间表如下:
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1820 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1634 浏览 1 评论
1104 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
740 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1692 浏览 2 评论
1951浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
756浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
587浏览 3评论
605浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
569浏览 3评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-31 00:27 , Processed in 0.636439 second(s), Total 45, Slave 39 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号