NRF24L01原子HAl库学习
IRQ产生中断有低电平,在TxFIFI发送完收到ACk后产生,
在RxFIFO收到数据后也产生
达到最大重发次数也产生
工作时序,SCK空闲状态为0,CPOL=0,第一个时钟沿采集数据CPHA=0,SPI工作模式0
另外SPI高位先出,低字节先出
30个寄存器,10个操作命令
nrf24l01整合一字节,只带操作,不带地址信息,带操作和地址信息
NRF写时序,返回的是寄存器的状态,下面的reg并非真正reg,有两种组合,是操作寄存器(10个操作命令)和地址信息(30个寄存器)整合的一个字节,或者只带操作信息的字节
读时序函数,reg同样为上述情况
操作指令
读写寄存器带操作地址
Tx和Rx都有FIFO, FIFO有三级, PWR_UP位是上电与否, PRIM_RX位是是否接收模式
自动重发
通道0的接收地址用来接收接收方接收到数据发送的ACK信号,所以要与发送方的发送地址一样。
发送流程
发送模式初始化步骤,发送频率和接收频率要相等
发送模式初始化代码
通过W_TX_PAYLOAD写数据
IRQ中断时变为低电平,接收到有效数据,发送完都会进入中断,下面while循环是等待发送接收应答完成
发送成功返回0,失败返回1
通过R_RX_PAYLOAD读数据
2,3,4,5是rx_packet的流程
注意:上面的发送和接收都是指同一个nrf器件
接收模式初始化
接收模式初始化代码
_write_buf(NRF_WRITE_REG + RX_ADDR_P0,(uint8_t *)RX_ADDRESS, RX_ADR_WIDTH)是把接收地址写入通道0
启动接收流程
发射端和接收端的RF_CH设置工作通道频率要相同
CONFIG寄存器,发送是0x0e,接收是0x0f,RX_DR,接收到数据触发IRQ中断,显示低电平,TX_DS,发送出去并接收到ACK信号是发送完成,触发中断信号,IRQ输出低电平
自动应答使能寄存器取值0x01,使能自动应答
数据接收通道使能
地址宽度设置寄存器,写入11默认5个字节,就是40位
自动重发寄存器,写入0x0A,设置自动重发间隔时间586us,最大自动重发次数为10次
发射端和接收端频率配置要一致
射频配置寄存器
【Low,High】共同决定传输速率
状态寄存器
RX_DR,接收数据标记,收到数据后置1,会引起IRQ中断输出低电平,写1清除中断
TX_DS,数据发送完成并接收到应答后完成置1,会引起IRQ中断1,写1清除中断。
MAX_RT,达到最大重发次数标志,写1清除中断,MAX_RT产生中断标志,需要清除中断后系统才能通信
数据通道0接收地址寄存器RX_ADDR_P0
通道0地址有40位 , 数据通道1接收地址设置寄存器设置P1~P5的32位高位地址,其他8位自己设置
P2~P5只能设置低8位地址
发送地址设置寄存器,接收通道0有效数据宽度设置寄存器
发送地址应该和接收通道0的地址设置相等,这样才能自动ACK,才能接收到应答信息
寄存器不用记住,要学会查看
编程实战
除了SPI的三个连接,还有CE引脚,控制nrf, CSN引脚片选信号引脚, IRQ中断引脚需要额外配置
代码详解,指定位置写
/*** @brief 在指定位置写指定长度的数据* @param reg : 寄存器地址* @param pbuf : 数据指针* @param len : 数据长度* @retval 状态寄存器值*/
static uint8_t nrf24l01_write_buf(uint8_t reg, uint8_t *pbuf, uint8_t len)
{uint8_t status, i;NRF24L01_CSN(0); /* 使能SPI传输 */status = spi1_read_write_byte(reg);/* 发送寄存器值(位置),并读取状态值 */for (i = 0; i < len; i++){spi1_read_write_byte(*pbuf++); /* 写入数据,*pbuf先获取数据,在对pbuf的地址进行++ */}NRF24L01_CSN(1); /* 关闭SPI传输 */return status; /* 返回读到的状态值 */
}
重点
CE引脚和CONFIG寄存器的PWR_UP位和PRIM_RX(第0位)共同控制nrf240l工作模式,
有四种模式
状态寄存器,4~6位写1清除中断,其他位不受影响,所以有了下面这个代码,写1清除那里非常巧妙
/*** @brief 启动NRF24L01发送一次数据(数据长度 = TX_PLOAD_WIDTH)* @param ptxbuf : 待发送数据首地址* @retval 发送完成状态* @arg 0 : 发送成功* @arg 1 : 达到最大发送次数,失败* @arg 0XFF : 其他错误*/
uint8_t nrf24l01_tx_packet(uint8_t *ptxbuf)
{uint8_t sta;uint8_t rval = 0XFF;NRF24L01_CE(0);nrf24l01_write_buf(WR_TX_PLOAD, ptxbuf, TX_PLOAD_WIDTH); /* 写数据到TX BUF TX_PLOAD_WIDTH个字节 */NRF24L01_CE(1); /* 启动发送 */while (NRF24L01_IRQ != 0); /* 检测中断IRQ输入为0,等待发送完成,收到应答后才会产生中断 */sta = nrf24l01_read_reg(STATUS); /* 读取状态寄存器的值 */nrf24l01_write_reg(NRF_WRITE_REG + STATUS, sta); /* 清除TX_DS或MAX_RT中断标志,写1清除 */if (sta & MAX_TX) /* 达到最大重发次数 */{nrf24l01_write_reg(FLUSH_TX, 0xff); /* 清除TX FIFO寄存器 */rval = 1;}if (sta & TX_OK) /* 发送完成 */{rval = 0; /* 标记发送成功 */}return rval; /* 返回结果 */
}
另外
nrf24l01_write_reg(FLUSH_TX, 0xff); /* 清除TX FIFO寄存器 */
nrf24l01_write_reg(FLUSH_RX, 0xff); /* 清除RX FIFO寄存器 */
总结
下面这段接收和发射模式初始化是设置发射方和接收方的通信频率的或者其他,通信频率要一样才能通信,所以比较重要,在原子例程都写好了
/*** @brief NRF24L01进入接收模式初始化* @note 设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR* 当CE变高后,即进入RX模式,并可以接收数据了* @param 无* @retval 无*/
void nrf24l01_rx_mode(void)
{NRF24L01_CE(0);nrf24l01_write_buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)RX_ADDRESS, RX_ADR_WIDTH); /* 写RX节点地址 */nrf24l01_write_reg(NRF_WRITE_REG + EN_AA, 0x01); /* 使能通道0的自动应答 */nrf24l01_write_reg(NRF_WRITE_REG + EN_RXADDR, 0x01); /* 使能通道0的接收地址 */nrf24l01_write_reg(NRF_WRITE_REG + RF_CH, 40); /* 设置RF通信频率,接收方和发射方一样才能通信 */nrf24l01_write_reg(NRF_WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); /* 选择通道0的有效数据宽度 */nrf24l01_write_reg(NRF_WRITE_REG + RF_SETUP, 0x0f); /* 设置TX发射参数,0db增益,2Mbps,低噪声增益开启 */nrf24l01_write_reg(NRF_WRITE_REG + CONFIG, 0x0f); /* 配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 */NRF24L01_CE(1); /* CE为高,进入接收模式 */
}/*** @brief NRF24L01进入发送模式初始化* @note 设置TX地址,写TX数据宽度,设置RX自动应答的地址,填充TX发送数据,选择RF频道,波特率和* LNA HCURR,PWR_UP,CRC使能* 当CE变高后,即进入TX模式,并可以发送数据了, CE为高大于10us,则启动发送.* @param 无* @retval 无*/
void nrf24l01_tx_mode(void)
{NRF24L01_CE(0);nrf24l01_write_buf(NRF_WRITE_REG + TX_ADDR, (uint8_t *)TX_ADDRESS, TX_ADR_WIDTH); /* 写TX节点地址 */nrf24l01_write_buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)RX_ADDRESS, RX_ADR_WIDTH); /* 设置RX节点地址,主要为了使能ACK */nrf24l01_write_reg(NRF_WRITE_REG + EN_AA, 0x01); /* 使能通道0的自动应答 */nrf24l01_write_reg(NRF_WRITE_REG + EN_RXADDR, 0x01); /* 使能通道0的接收地址 */nrf24l01_write_reg(NRF_WRITE_REG + SETUP_RETR, 0x1a); /* 设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次 */nrf24l01_write_reg(NRF_WRITE_REG + RF_CH, 40); /* RF通信频率,设置RF通道为40 ,接收方和发射方一样才能通信 */nrf24l01_write_reg(NRF_WRITE_REG + RF_SETUP, 0x0f); /* 设置TX发射参数,0db增益,2Mbps,低噪声增益开启 */nrf24l01_write_reg(NRF_WRITE_REG + CONFIG, 0x0e); /* 配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断 */NRF24L01_CE(1); /* CE为高,10us后启动发送 */
}
内容有点多,不过很细,很全