NRF24L01是重要的SPI总线通信器件,使用Nucleo-F446开发板驱动NRF24L01有利于加深我们对开发板的SPI总线的认识。
NRF24L01可以使用模拟SPI或是硬件SPI进行通信, 对SPI速度和CPOL、CPHA状态位有极高的要求。在以前,一些没有硬件SPI总线的八位单片机会使用GPIO模拟SPI总线进行通信,这样做的好处是IO翻转速度慢,远低于NRF24L01的最高速度限制,并且CPOL和CPHA可以直接修改。在STM32的32位机时代,硬件SPI总线成为主流,好在修改SPI速度和CPOL、CPHA状态可以直接通过修改寄存器或者库函数结构体来进行控制,驱动NRF24L01不算太大问题。
硬件连接上,NRF24L01连接Nucleo-F446RE板子的SPI1总线,即PA5-PA7,CE和CSN则接在PC2和PC3上:
STM32初试化硬件SPI总线需要初始化各项参数,如速率、数据位、CPOL位(CLK线空闲电平是高还是低)、CPHA位(CLK先上升沿还是下降沿传数据)等等,这里除了套用CubeMX常规配置以外,还需要针对NRF24L01进行定制:
void SPI1_Init()
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin=GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull=GPIO_PULLUP;
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate=GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
__HAL_RCC_SPI1_CLK_ENABLE();
SPI1_Handler.Instance=SPI1;
SPI1_Handler.Init.Mode=SPI_MODE_MASTER; //设置SPI工作模式,设置为主模式
SPI1_Handler.Init.Direction=SPI_DIRECTION_2LINES; //设置SPI单向或者双向的数据模式:SPI设置为单线模式
SPI1_Handler.Init.DataSize=SPI_DATASIZE_8BIT; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI1_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH; //串行同步时钟的空闲状态为高电平
SPI1_Handler.Init.CLKPhase=SPI_PHASE_2EDGE; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI1_Handler.Init.NSS=SPI_NSS_SOFT; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI1_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16;
SPI1_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI1_Handler.Init.TIMode=SPI_TIMODE_DISABLE; //关闭TI模式
SPI1_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
SPI1_Handler.Init.CRCPolynomial=7; //CRC值计算的多项式
HAL_SPI_Init(&SPI1_Handler);
__HAL_SPI_ENABLE(&SPI1_Handler); //使能SPI1
}
void NRF24L01_SPI_Init()
{
__HAL_SPI_DISABLE(&SPI1_Handler);
SPI1_Handler.Init.CLKPolarity=SPI_POLARITY_LOW;
SPI1_Handler.Init.CLKPhase=SPI_PHASE_1EDGE;
HAL_SPI_Init(&SPI1_Handler);
__HAL_SPI_ENABLE(&SPI1_Handler);
}
驱动NRF24L01从驱动单机单模块入手,成功初始化即可说明板子与一块NRF24L01通信正常。测试的方法参考正点原子的程序,往发送地址寄存器连续写入5个数据,然后在从这个寄存器读出5个数据,如果写入和读出的数据完全相同,则说明NRF24L01通信正常(PS:NRF24L01未配置发送/接收模式时CE引脚要置低电平):
int NRF24L01_Check()
{
unsigned char buf={0XA5,0XA5,0XA5,0XA5,0XA5},i;
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,buf,5);
NRF24L01_Read_Buf(TX_ADDR,buf,5);
for(i=0;i<5;i++)if(buf!=0XA5)break;
if(i!=5)return 1;
return 0;
}
由于单机测试模式无法测试接收,因此先测试发送是否成功,若发送成功,则状态寄存器返回0x10命令码:
unsigned char NRF24L01_TxPacket(unsigned char *txbuf)
{
unsigned char sta;
NRF_CE_CLR;
NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,5);//写数据到TX BUF 32个字节
NRF_CE_SET; //启动发送
//while(NRF24L01_IRQ!=0); //等待发送完成
Delay_ms(10);
sta=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值
NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
if(sta&MAX_TX) //达到最大重发次数
{
NRF24L01_Write_Reg(FLUSH_TX,0xff); //清除TX FIFO寄存器
return MAX_TX;
}
if(sta&TX_OK) //发送完成
{
return TX_OK;
}
return 0xff;//其他原因发送失败
}
串口助手打印信息:
NRF24L01是重要的SPI总线通信器件,使用Nucleo-F446开发板驱动NRF24L01有利于加深我们对开发板的SPI总线的认识。
NRF24L01可以使用模拟SPI或是硬件SPI进行通信, 对SPI速度和CPOL、CPHA状态位有极高的要求。在以前,一些没有硬件SPI总线的八位单片机会使用GPIO模拟SPI总线进行通信,这样做的好处是IO翻转速度慢,远低于NRF24L01的最高速度限制,并且CPOL和CPHA可以直接修改。在STM32的32位机时代,硬件SPI总线成为主流,好在修改SPI速度和CPOL、CPHA状态可以直接通过修改寄存器或者库函数结构体来进行控制,驱动NRF24L01不算太大问题。
硬件连接上,NRF24L01连接Nucleo-F446RE板子的SPI1总线,即PA5-PA7,CE和CSN则接在PC2和PC3上:
STM32初试化硬件SPI总线需要初始化各项参数,如速率、数据位、CPOL位(CLK线空闲电平是高还是低)、CPHA位(CLK先上升沿还是下降沿传数据)等等,这里除了套用CubeMX常规配置以外,还需要针对NRF24L01进行定制:
void SPI1_Init()
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin=GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull=GPIO_PULLUP;
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate=GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
__HAL_RCC_SPI1_CLK_ENABLE();
SPI1_Handler.Instance=SPI1;
SPI1_Handler.Init.Mode=SPI_MODE_MASTER; //设置SPI工作模式,设置为主模式
SPI1_Handler.Init.Direction=SPI_DIRECTION_2LINES; //设置SPI单向或者双向的数据模式:SPI设置为单线模式
SPI1_Handler.Init.DataSize=SPI_DATASIZE_8BIT; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI1_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH; //串行同步时钟的空闲状态为高电平
SPI1_Handler.Init.CLKPhase=SPI_PHASE_2EDGE; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI1_Handler.Init.NSS=SPI_NSS_SOFT; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI1_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16;
SPI1_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI1_Handler.Init.TIMode=SPI_TIMODE_DISABLE; //关闭TI模式
SPI1_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
SPI1_Handler.Init.CRCPolynomial=7; //CRC值计算的多项式
HAL_SPI_Init(&SPI1_Handler);
__HAL_SPI_ENABLE(&SPI1_Handler); //使能SPI1
}
void NRF24L01_SPI_Init()
{
__HAL_SPI_DISABLE(&SPI1_Handler);
SPI1_Handler.Init.CLKPolarity=SPI_POLARITY_LOW;
SPI1_Handler.Init.CLKPhase=SPI_PHASE_1EDGE;
HAL_SPI_Init(&SPI1_Handler);
__HAL_SPI_ENABLE(&SPI1_Handler);
}
驱动NRF24L01从驱动单机单模块入手,成功初始化即可说明板子与一块NRF24L01通信正常。测试的方法参考正点原子的程序,往发送地址寄存器连续写入5个数据,然后在从这个寄存器读出5个数据,如果写入和读出的数据完全相同,则说明NRF24L01通信正常(PS:NRF24L01未配置发送/接收模式时CE引脚要置低电平):
int NRF24L01_Check()
{
unsigned char buf={0XA5,0XA5,0XA5,0XA5,0XA5},i;
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,buf,5);
NRF24L01_Read_Buf(TX_ADDR,buf,5);
for(i=0;i<5;i++)if(buf!=0XA5)break;
if(i!=5)return 1;
return 0;
}
由于单机测试模式无法测试接收,因此先测试发送是否成功,若发送成功,则状态寄存器返回0x10命令码:
unsigned char NRF24L01_TxPacket(unsigned char *txbuf)
{
unsigned char sta;
NRF_CE_CLR;
NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,5);//写数据到TX BUF 32个字节
NRF_CE_SET; //启动发送
//while(NRF24L01_IRQ!=0); //等待发送完成
Delay_ms(10);
sta=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值
NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
if(sta&MAX_TX) //达到最大重发次数
{
NRF24L01_Write_Reg(FLUSH_TX,0xff); //清除TX FIFO寄存器
return MAX_TX;
}
if(sta&TX_OK) //发送完成
{
return TX_OK;
}
return 0xff;//其他原因发送失败
}
串口助手打印信息: