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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。, o' Y1 s5 Q" I- G6 r# w# a
51.JPG & F1 \$ x5 Z) X6 K. H4 k& e
首先是初始化SPI接口,这个非常简单:
# k$ H7 ], }( p
  1. SPI_HandleTypeDef g_spi_handle;. W# X) K$ ]4 f

  2. : N3 e( h! i% G2 u
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata): @4 w. M- ]  u. \: b8 O6 b( c
  4. {$ z. }! a& k% M6 C/ B: ^/ p
  5.   uint8_t rxdata;
    3 B- Q- Y% R1 Z! D
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);, }, a+ S8 Q$ W6 P9 _
  7.   return rxdata;
    , E8 _% F- p( Q0 v$ {: v
  8. }
    6 ~8 o& C2 K! Y: |) ]* \
  9. % K7 Q* g% `4 p
  10. void SPI2_PD3_PC2_PC3_Init(void)" ]# w0 s3 e' o% C) N
  11. {+ d9 T' T$ h( E: c6 x2 j1 h4 {
  12.   GPIO_InitTypeDef gpio_init_struct = {0};+ w- Y3 f& \8 V
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
    ) g$ n, _' H% B& w* Q+ y

  14. 8 M1 B0 Y) j/ h! q
  15.   __HAL_RCC_SPI2_CLK_ENABLE();
    ) N7 i4 @) Y8 V5 T
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();6 G3 R0 v: s) |
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();+ D4 e; {; ]! q$ T. d: |$ ^

  18. 2 i; r  @2 e! p) m$ x
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;! q  ?2 M) g/ Y' g- J
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
    4 S& F1 A9 @  @/ ^7 K5 ]& Y  _
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    6 f2 ^4 {0 _) F* Z* U

  22. # z1 J! h+ x9 r  ]! D3 [
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;% g5 ~+ M+ S/ j! S
  24.   gpio_init_struct.Pull = GPIO_PULLUP;- E1 D" t. R, h" g. A
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      G+ G2 x) ^. D) u; y3 l
  26. 7 h( Y6 G0 ^0 ~4 z( [* G* u+ L
  27.   gpio_init_struct.Pin = GPIO_PIN_3;
    . Y) A1 G; a: E" S
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;3 `4 Y' [' p0 X5 A, X1 r9 z
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);
    4 I9 {) S, m* c- s' e
  30. , r) Z- C7 `; ^. q( B
  31.   gpio_init_struct.Pin = GPIO_PIN_2;4 ]4 n# N# c& s' j6 g4 [( D
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    / h* _8 d" R  K! k. x- T5 F$ T
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    $ K1 q+ W- b' l# D7 z# r  e

  34. ' o: B# j0 K! a) j9 c7 D& G5 q
  35.   gpio_init_struct.Pin = GPIO_PIN_3;: W. l! H, D  U3 S2 W% Y
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    + \* I# j# g% f! x
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    , b! H0 L1 U) v% [; `/ z5 l7 m
  38. 2 b& d3 r- a8 `# e
  39.   g_spi_handle.Instance = SPI2;
    1 e0 ]# V% N3 e+ a3 v  V
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;5 L/ C* I- O3 F, T' |
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;( r% _/ W4 d$ Y# {
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;+ s5 h- i  k9 e( }8 }
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    * A' U) x" n. Y
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;! z8 y# |4 o: E: m+ j! }
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
    0 ?9 k% L6 a) |' d6 S1 K) g  {4 f/ t
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    2 x" ~; n5 V4 Y( I6 E0 V& {# Q
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;; |$ R8 ^  S$ ^, E+ A
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;' `: H. d: S- ^, A8 C
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
    - `/ e' J) f7 N' P
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    ' \" `( c! S' h; _7 F
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    4 h) i) `& T! C) ?( L7 C
  52.   g_spi_handle.Init.CRCPolynomial = 7;
    % ?2 q! Q5 |, f( T' ]* z
  53.   HAL_SPI_Init(&g_spi_handle);: r* A. ~" b6 c6 R, h8 Q7 D) Y7 V

  54. ! e$ r9 ?* @& h) v. P4 {; M2 [( b
  55.   __HAL_SPI_ENABLE(&g_spi_handle);
    ) s* R' j7 p3 O) U; M
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
    ) h# D! K+ ?) [
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。4 _5 w) A+ G1 @- [# E' h6 n. Y# g

$ v% C/ c3 q* h) }NRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:; _' Y, O$ Q! z; D1 B- ?8 `; t+ ~& O
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM& o5 t4 S& N8 }9 }  C7 g# Q& K
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    # T6 h1 h; P" P% |$ A
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    " W- ~* l( w7 V* a8 h0 E
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);+ o$ P* L' S* n+ m! F
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);+ h5 r2 \, C% t% O

  6. 2 S2 `2 s/ U  [% I( g+ U1 J, Q
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM
    6 \! A0 a# h5 U  B" U
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_148 k9 R* o5 M* x6 h, j
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();+ Y  d8 w  g/ C( u
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
    $ ~, O. p$ V4 Y; L! T0 v
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);7 ?8 ~8 e" N, t8 f9 f1 H
  12. ; c8 F' T. \0 c! V# }
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF9 }9 Y/ M3 ~+ H& @) Z
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_23 T3 y0 O2 t% i$ Y0 M( V
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();; _: x' Q7 g, z  O4 k, Z5 o
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)6 R& L& p( S0 h/ ~6 `
  17. , ?% `6 g8 M3 j2 K( W- V
  18. void NRF24L01_GPIO_Init(void); f" D/ u% C6 a4 ?$ D& b
  19. {, i& C% B8 W5 R1 q6 d
  20.     GPIO_InitTypeDef gpio_init_struct;2 t* w4 _8 x1 g+ T
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;0 r# d5 E- O' m
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;
    + o% x) F" S8 B( M# L  f' V( e8 a
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
    0 e7 Z9 k$ R2 Q# L
  24.    
    , @% Z, k1 ^. s" V
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;  A% ^; }4 G+ G
  26.     gpio_init_struct.Pull = GPIO_PULLUP;' e7 \. v$ j5 i7 Z+ I1 |
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;. Q, O# f1 s$ L% R( Z) @2 W7 X& X
  28.    
    + B) o9 }$ H" L" |) C, T/ Z
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    - E% h8 w% Q, N* u4 c
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);( S2 g" u8 h; _. P5 G
  31.    
    $ {7 u7 T7 t. \) ~& E+ T6 }
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;  O9 P- y$ N  U
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    ; _" Q( K; b* y* A# R$ J* U
  34.     1 e+ V. Q  K  n* j9 v. z% ~
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    3 n# ~8 |- P& Y
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;6 y9 d7 u( O4 B" m
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);# w8 e, {: q2 @- C. E+ J# ]" y
  38.    
    ( N+ @4 r8 K0 f) U0 L0 i
  39.     NRF24L01_CE_LOW;
    ' A. d# e! F; U
  40.     NRF24L01_CS_HIGH;$ L. ^3 s, O( _$ b* z
  41. }
复制代码
5 M' g# e* m' R) w
! q. i* [* G+ G
. q& a& J( n) a
NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:! X3 N4 W/ W; d- ]6 I
  1. uint8_t NRF24L01_Check(void)
    ! N- M% i) N. M4 Q3 O! o0 u* V
  2. {
    5 @4 c' ^& J& m& k1 D. X0 L! H
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
    7 Z# r' Q  ?( A6 G6 M  `: `/ y' R
  4.     uint8_t i;* A+ `& ?' O- P+ `& z
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);, I/ i5 v' l. y9 t: o. e- b8 u
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);
    0 @) B5 n) D" z! ?
  7.     for(i = 0 ; i < 5 ; i++)
    , T$ S: o/ {: s0 P8 v
  8.         if(buf[i] != 0XA5)
    % Q* q. J6 l# k8 N! G  S- ~1 ~
  9.             break;                                    
    - [% Y: X3 b5 A' A! `
  10.     if(i!=5)  I% N" `) j9 \* b3 j/ u; l
  11.         return 1;
    * n' k4 C* U& b; g# t$ [
  12.     return 0;
    " |; C" _$ }2 N; y9 L/ T
  13. }
复制代码

) r" x8 y& i6 }# a" @
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
6 p: D% B$ A1 j$ J* A
  1. void NRF24L01_RX_Mode(void)! K$ {: d' |2 F6 w  ?0 f0 I
  2. {
    ! J5 J) G4 p1 ~/ i
  3.     NRF24L01_CE_LOW;9 Y: \) ~! A. O; m5 g
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    + |- h( A/ f+ J! W, P+ T
  5.    
    * I& F# ?2 U" a! n! f) H
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    & ?$ D7 R7 y. B7 ]* k
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);$ X. Z3 q* b1 a0 s* p, L* A
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    + C8 x; ?3 [2 _
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    , l! Q$ ~& k2 Z) D
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    ! @8 r' D# ?  b! {5 Q( l# L
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    ! M1 G0 i4 p: W* m$ ?9 m
  12.     NRF24L01_CE_HIGH;4 D8 x' o4 j) p) u" V
  13. }
    $ z% F. k/ G% e  _. h
  14. ) ?( c! m4 @/ j# l' m! y
  15. void NRF24L01_TX_Mode(void)0 r  f1 Y. c+ f# f: Z: p% y# E( P8 p- M
  16. {                                                         
    & S2 z8 R: O  j. N  @/ A% |
  17.     NRF24L01_CE_LOW;
    7 B7 C& w' z1 e1 P5 K# [
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
    + s+ W4 i; \# P6 J9 W" X. ^
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);6 @% h6 L, I" w% _/ _, f& w
  20. 0 d( E- C! O2 j9 O
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);- l) G# l$ }! j% y
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    ! |- i/ ?- {1 h/ W
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
    * S. J2 L+ j, j! Z, |" K
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);% G& s  Z- K9 w: B: E
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    * ^1 K9 t9 v% i7 H
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
    3 O8 E: @# j3 _$ G) r
  27.     NRF24L01_CE_HIGH;
    2 ]* t; }/ U3 T& i8 V9 m; R1 \
  28. }& r$ `1 |$ [) j7 R, t; n

  29. 5 M" n1 v( A; y
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)7 A1 E6 l0 ?3 Y+ W, v. ~+ `0 @
  31. {
    1 f9 J2 o5 M, R; Z3 d6 v# C4 w8 J- R
  32.     uint8_t sta;                                          
    ; J. U5 C' @3 @$ C
  33.     sta = NRF24L01_Read_Reg(STATUS);) \8 k' n  @+ @% Z
  34. 3 L% h) b1 j3 z& D
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);- a6 `& {- D; S$ q1 i  B, H
  36.     : T- O$ d$ j2 f& n
  37.     if(sta & RX_OK)
    0 T: B% _  b0 S" t
  38.     {
      H0 Z( R9 M# w+ F+ @" q* v
  39.         printf("sta = 0x%x RX_OK.\n" , sta);0 B6 Q# O* f$ c0 Z5 \; t
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);
    ) k* B  m6 c! q& W. N
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
      _& ]' o) \. a: q
  42.         return 0;- O; R7 z8 Z% z
  43.     }       & X! [+ D2 J+ K- c( R9 F
  44.     return 1;
    . M/ |( P7 g$ ?( q* {8 A0 J
  45. }   
    ' C  E4 G$ h( x7 s9 e6 }9 M' k

  46. 4 J' K( n, x2 B( k
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)) ]/ n  C8 x$ V. C
  48. {
    ) }% j! ~& d8 x5 }2 u0 {* t7 ^
  49.     uint8_t sta;2 ?) }3 U: Z% `# P
  50.     NRF24L01_CE_LOW;% n" n8 Q5 |) M$ `2 x& z' o
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    . a5 I# h; T6 T
  52.      NRF24L01_CE_HIGH;
    + x  M" ^( u5 W
  53.     while(NRF24L01_IRQ_READ() != 0);" S) S; K7 Q0 \9 Z3 o7 u
  54.     sta = NRF24L01_Read_Reg(STATUS);
    , \0 n$ T: Z# J. t/ G) U
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);" W  {( ~- A( G/ [; ]& E, ~- e  A6 S$ e
  56.     if(sta&MAX_TX)
    * e. w3 \3 x6 F9 y4 q
  57.     {- Q2 i0 e' d2 O; @
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);0 _7 ^: Z" ^, p) c% M/ X" N
  59.         return MAX_TX;
    2 v. r0 i  p) [# U# [+ V
  60.     }. U$ c% M7 C9 m) ^- c" r- b
  61.     if(sta&TX_OK)) V- @% q2 c$ g! A
  62.     {- ~) l  f6 E( Q7 I4 P" N. M8 G- m4 ]' {
  63.         return TX_OK;
    " x* l' C, @. Q# n
  64.     }( `* _, ^* X9 I. h( l* X* J- k
  65.     return 0xff;
    ' \% k8 a7 D" K0 b; K
  66. }
复制代码

5 v' t# l; y4 @. G我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
" k7 E7 p, t8 t& R9 Q
52.jpg 53.JPG
- J' p; }1 E! D1 i! w" q  _  |+ N) c1 z
看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
# ?, T' @" t& ^  \. p
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
8 k. A& S2 m$ a$ Q  F, K. r然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
3 K1 \' l2 A; e, F# h8 ?3 K 55.JPG
  ~% @6 r. j  v( J7 i3 _
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)的合照2 Z) r( c/ z- n* G% E8 m
IMG_20250524_125758.jpg
: M* w1 o! a" z, c* z# H! r4 I/ t1 ?# ^6 D7 g

所属标签

相似技术帖

官网相关资源

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