你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【2025·STM32峰会】GUI解决方案实训分享5-调通板载的NRF24L01 SPI接口并使用模块进行无线通信(发送和接收)

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。
51.JPG
首先是初始化SPI接口,这个非常简单:
  1. SPI_HandleTypeDef g_spi_handle;

  2. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)
  3. {
  4.   uint8_t rxdata;
  5.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
  6.   return rxdata;
  7. }

  8. void SPI2_PD3_PC2_PC3_Init(void)
  9. {
  10.   GPIO_InitTypeDef gpio_init_struct = {0};
  11.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};

  12.   __HAL_RCC_SPI2_CLK_ENABLE();
  13.   __HAL_RCC_GPIOC_CLK_ENABLE();
  14.   __HAL_RCC_GPIOD_CLK_ENABLE();

  15.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;
  16.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
  17.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);

  18.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
  19.   gpio_init_struct.Pull = GPIO_PULLUP;
  20.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

  21.   gpio_init_struct.Pin = GPIO_PIN_3;
  22.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
  23.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);

  24.   gpio_init_struct.Pin = GPIO_PIN_2;
  25.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
  26.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);

  27.   gpio_init_struct.Pin = GPIO_PIN_3;
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
  29.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);

  30.   g_spi_handle.Instance = SPI2;
  31.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;
  32.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
  33.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
  34.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
  35.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
  36.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
  37.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  38.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
  39.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
  40.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
  41.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
  42.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  43.   g_spi_handle.Init.CRCPolynomial = 7;
  44.   HAL_SPI_Init(&g_spi_handle);

  45.   __HAL_SPI_ENABLE(&g_spi_handle);
  46.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
  47. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。

NRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);

  6. #define NRF24L01_CE_GPIO_PORT                                 GPIOM
  7. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
  8. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
  9. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
  10. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);

  11. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF
  12. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2
  13. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();
  14. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)

  15. void NRF24L01_GPIO_Init(void)
  16. {
  17.     GPIO_InitTypeDef gpio_init_struct;
  18.     NRF24L01_CS_GPIO_CLK_ENABLE;
  19.     NRF24L01_CE_GPIO_CLK_ENABLE;
  20.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
  21.    
  22.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
  23.     gpio_init_struct.Pull = GPIO_PULLUP;
  24.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
  25.    
  26.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
  27.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
  28.    
  29.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
  30.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
  31.    
  32.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
  33.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;
  34.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);
  35.    
  36.     NRF24L01_CE_LOW;
  37.     NRF24L01_CS_HIGH;
  38. }
复制代码



NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
  1. uint8_t NRF24L01_Check(void)
  2. {
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
  4.     uint8_t i;
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);
  7.     for(i = 0 ; i < 5 ; i++)
  8.         if(buf[i] != 0XA5)
  9.             break;                                    
  10.     if(i!=5)
  11.         return 1;
  12.     return 0;
  13. }
复制代码

NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
  1. void NRF24L01_RX_Mode(void)
  2. {
  3.     NRF24L01_CE_LOW;
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
  5.    
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
  12.     NRF24L01_CE_HIGH;
  13. }

  14. void NRF24L01_TX_Mode(void)
  15. {                                                         
  16.     NRF24L01_CE_LOW;
  17.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);

  19.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
  20.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
  25.     NRF24L01_CE_HIGH;
  26. }

  27. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
  28. {
  29.     uint8_t sta;                                          
  30.     sta = NRF24L01_Read_Reg(STATUS);

  31.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
  32.    
  33.     if(sta & RX_OK)
  34.     {
  35.         printf("sta = 0x%x RX_OK.\n" , sta);
  36.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);
  37.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
  38.         return 0;
  39.     }      
  40.     return 1;
  41. }   

  42. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
  43. {
  44.     uint8_t sta;
  45.     NRF24L01_CE_LOW;
  46.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
  47.      NRF24L01_CE_HIGH;
  48.     while(NRF24L01_IRQ_READ() != 0);
  49.     sta = NRF24L01_Read_Reg(STATUS);
  50.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
  51.     if(sta&MAX_TX)
  52.     {
  53.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
  54.         return MAX_TX;
  55.     }
  56.     if(sta&TX_OK)
  57.     {
  58.         return TX_OK;
  59.     }
  60.     return 0xff;
  61. }
复制代码

我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
52.jpg 53.JPG

看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
55.JPG
51.JPG
52.jpg
53.JPG
54.JPG
55.JPG
IMG_20250525_003610.jpg
IMG_20250525_003612.jpg
收藏 评论1 发布时间:2025-5-25 23:45

举报

1个回答
donatello1996 回答时间:2025-5-26 18:16:42
补上一张H7R7开发板和NRF24L01接收机开发板(STM32F103R)的合照
IMG_20250524_125758.jpg

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版