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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。& F/ I; E3 u; C  p8 ]5 m' P, w
51.JPG
0 r5 N7 l2 d7 Z7 @; H, H首先是初始化SPI接口,这个非常简单:
1 |: |* ^6 U& n1 J& H
  1. SPI_HandleTypeDef g_spi_handle;: Y3 J% h1 K; R7 ~

  2. ; J- c  u, |) s: Q+ ]
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)+ j! O" y: ?9 a3 ?8 V
  4. {5 [3 H) O, f0 g! J4 Y; _8 a/ E
  5.   uint8_t rxdata;& t/ ^* X- t7 R' C
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
    * t5 N4 I" j+ b& f' |4 e
  7.   return rxdata;' n4 x( V. R- w! ~
  8. }
    0 x7 j+ c* n1 l
  9. 7 C/ a" S$ E8 ]2 z
  10. void SPI2_PD3_PC2_PC3_Init(void)
    : S% `% D% r# ?: \
  11. {
    ; |. ~- M' w) f% b/ J
  12.   GPIO_InitTypeDef gpio_init_struct = {0};
    ! o3 u' C  }6 C) n& I" f5 T% \
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};. d! S; M0 _' y$ f' x* l

  14. 0 ?; \9 B/ w6 p1 H+ j) f
  15.   __HAL_RCC_SPI2_CLK_ENABLE();
    8 k* M4 N, m3 n. t+ b" I. E
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();
    6 F6 m) L9 J5 f# R' m! n
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();
    & g( x- i1 k1 f% n0 i
  18. ' Y5 T3 g- L& t# x2 }( @. Q
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;, S* n0 n& I/ V% g' E
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
    4 Y& f6 a: T4 z2 O% ~. X, d: \; H
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);: m, y8 J* p" w
  22.   z9 _, q8 J9 E
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    8 c2 S* q8 B4 Q8 A7 Q) }
  24.   gpio_init_struct.Pull = GPIO_PULLUP;
    6 p' o8 L( U2 ?2 a8 T2 G4 u+ h: h
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;0 U* m8 t7 W# H7 G! {2 Z3 ?
  26. 0 a. j8 o. \! X2 b. G
  27.   gpio_init_struct.Pin = GPIO_PIN_3;/ x8 L: S9 w, b; C1 @9 e, m
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    ) e7 Q* k2 Q# k
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);- F; q8 V( r$ Q" ]

  30. ) R" {. k+ c% z8 {! w! b
  31.   gpio_init_struct.Pin = GPIO_PIN_2;
    5 r: @- `0 [. p; h0 W: h4 G
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;: L' @8 J# h- M$ P  \
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);' b0 \( M1 I) ~- j- H; B7 ^
  34. 6 h7 w7 r  Z/ \* I, `' v3 a7 p, a
  35.   gpio_init_struct.Pin = GPIO_PIN_3;
    5 i9 F9 O' s% t  E8 p. B
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;1 q6 k  \& c: `# @- Y4 P
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);4 n& I6 D/ e- T" P

  38. 0 i" J+ u( E2 \0 V9 y) t
  39.   g_spi_handle.Instance = SPI2;8 a8 A; x! R- n( d8 }
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;; @, d0 d8 ]" ]
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
    ; A- s0 m& ?9 |  n
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;' b' J0 y2 R# ~( k1 b  X2 J
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    , O, I5 ^! l5 D$ l2 J; }2 B
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
    0 p# Y* Z8 j3 X3 R7 j
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  6 A5 |% U3 c- s) L8 p
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    # ]6 U! W5 f2 O+ C* S
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;2 e* _$ A" r" L6 @0 A
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;/ d- L* a3 @% X% n
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;* ^" X+ D% z) E6 O
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    " ]1 X' K' M, v/ u
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;, T& k" ^9 ]  f) d
  52.   g_spi_handle.Init.CRCPolynomial = 7;  n, n0 e: ~. X5 V
  53.   HAL_SPI_Init(&g_spi_handle);% W2 ^: c9 W- M8 }# u" ?' n- k$ k

  54. 2 d/ _3 }( }- |# r0 j
  55.   __HAL_SPI_ENABLE(&g_spi_handle);
    / W  C, H) `7 h
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
      U: p& M, y6 P
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。* M2 I, D, l( b8 `# P

# f3 F- {2 m' v* A) D1 a/ Z0 @4 dNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:
0 `1 r6 q4 _: C& o" d/ C  K: p
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM
    ! w# ]# \% l) [7 @1 t3 [  j, @* f
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    8 V# j* Z% q8 @3 X; n
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();5 R+ t- _5 [# s- `
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);
    ; n2 x# Y" F& f6 i& x
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
    & O1 t' J9 ]( N# k

  6. ( B" m% I$ U, I, ]  ]
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM. a( o2 d$ _% A4 }7 c0 |9 x0 E
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14; n; }( L% e/ A: s4 {$ a2 O
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();6 U( G$ a- `0 \2 k2 t* W" z
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
    1 A" f' _: _3 S  e! u" X" ~
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
    0 T3 V' o4 F- p% a1 C
  12. ' G1 Z/ B- B/ [9 \  ^
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF- P! g! J% u! D& P6 p, a2 Y1 w0 z  s
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2
    ' m) w: T  M" @- W  S$ o% q
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();7 X( C! g; F; g" H. O) D0 Q  l8 U
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)/ a3 s$ `! ?5 J" d
  17. 3 g6 [, z, c% s
  18. void NRF24L01_GPIO_Init(void)) r9 c0 ?& _* j8 M  l
  19. {
    ) e6 ~! \  R7 B" L" a8 U! J
  20.     GPIO_InitTypeDef gpio_init_struct;
    8 |1 w+ W' v2 k
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;, P& H: h4 c  U9 G% S# `$ ?
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;
    $ o3 ^5 |( ]- u6 I- |8 [8 F  A* i
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
    $ O. c6 g+ {3 C& y( n
  24.    
    ) J. U" `$ ?0 D/ u- q
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;. e5 S' b+ t7 ^* ^( V# a+ Q
  26.     gpio_init_struct.Pull = GPIO_PULLUP;- z* Z( V3 w3 t; R5 C
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
      O' y; }7 {; f% ]
  28.    
    8 E  ?: k) `/ {
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    * a; u/ ^8 j6 ~. O6 |
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
    ! h3 K7 {- s$ s! E6 J, [
  31.     # N3 B! }7 {( C. c5 Q& y
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    ) ]. b3 [2 v2 @$ u
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);1 l: j9 ^8 N- W
  34.     , Z3 G/ h% ]7 S" n
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    4 \' |9 w! ]# {
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;$ L! W' X1 f( X. G6 [4 Z& C: K
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);
    9 W. j" w  u2 H5 I* }. d" s6 |
  38.     - s6 L1 R1 b# @5 M: P2 r1 e
  39.     NRF24L01_CE_LOW;% O& @/ w; G2 R' ?+ Y4 U- }
  40.     NRF24L01_CS_HIGH;- w  x0 l2 z/ G# R5 x' _
  41. }
复制代码
. e, j" E) N0 J$ [) H

/ @. S. T7 J: |: i4 b
& l4 O0 j& G: }. m9 m) Y& }NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:( y9 l$ X- l* j
  1. uint8_t NRF24L01_Check(void)
    * _  D4 H3 U6 X- O9 f
  2. {
    ' m' |5 L1 I: s+ f5 v
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
    7 U3 A6 k  L" }+ g
  4.     uint8_t i;1 v# f; d5 L4 Q, y, g5 ^; N) m
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
    1 Y5 Q, K6 x* M7 C4 u) L
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);) p) c3 b9 x) `# f) t) ?& V( A
  7.     for(i = 0 ; i < 5 ; i++)
    7 z/ `( Q; h4 ~" w7 g) I
  8.         if(buf[i] != 0XA5)
    ) J. F, N- g9 b+ I' q: p
  9.             break;                                    & D  p' Y; ~7 Q: ~
  10.     if(i!=5)' e. u, W9 h$ v7 o
  11.         return 1;
    4 [# @, b. D$ p  {$ M& G9 S" N
  12.     return 0;, [; N/ ?- q- r
  13. }
复制代码
8 M, F8 e, B$ S/ B9 O# b
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
/ _! J) Z. e1 }+ g5 D& `5 u
  1. void NRF24L01_RX_Mode(void)
    % ]& f9 Q/ f% d4 a5 Q$ l, u/ r
  2. {
    6 O! j, s2 _' E# y/ i7 `
  3.     NRF24L01_CE_LOW;
    . j5 C; H: P9 f. {8 A/ l( T. z
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    5 {- m' L! d4 ]' ?1 H& b
  5.     * W) x# c+ V4 n& {: `
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    ) ~0 {+ Z8 c! @" X% s5 P' s
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    / n1 A) w; K' B( v0 V) _$ y
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    ( R) ^  n/ i- x6 M
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);8 t$ |2 p7 e9 d  |" N0 a9 j& M
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    ) j- u* W1 a1 }+ O. i0 ^0 `
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);4 n4 }& D% n; V! s0 [( A
  12.     NRF24L01_CE_HIGH;' G) W, M* f' I: X: b- p
  13. }7 R4 `/ A% P  U8 H5 _
  14. , N8 |; p. |$ Z5 z* p
  15. void NRF24L01_TX_Mode(void)
    0 e" c: S. U, Y3 A
  16. {                                                         3 w2 [9 U0 P3 ?+ I8 e1 s; b- c( \
  17.     NRF24L01_CE_LOW;
    ) \: U: ~6 z2 C+ A$ w
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);8 h: r' i& H' ^% L/ ~
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    . N* b& N. U, D4 F

  20. ; N3 F# E/ ?/ \) z9 ]! _  L
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);8 k! q0 {% s8 S) k& `7 |) i$ q
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    ; E; R$ ^# Q: k
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
    ; R  T# h8 e& H- P
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    * F0 S) G6 R5 y5 r( z4 F
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);/ D, k) q0 l4 M2 C3 y
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
    * q1 x2 n/ a3 k! b9 x3 n' I, f/ i
  27.     NRF24L01_CE_HIGH;2 W( i& }3 o3 i. r# i
  28. }1 ]. l0 C- C  k( z$ [3 w" C6 m  T
  29. 4 G. k; r! o2 j) q9 A8 \
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
    & `" h  p" C: X) |# V0 A/ H
  31. {& s0 g# E* D' \+ Q" E& `. G* g
  32.     uint8_t sta;                                           6 t4 ]5 V# f% B) e. B/ ^( V
  33.     sta = NRF24L01_Read_Reg(STATUS);
    # e& Z) A7 o( x. m- t/ ?5 z+ Q
  34. 2 _$ `: L1 {2 K+ _3 F: ~
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);4 @; C8 P' H0 q
  36.     5 A. |- H4 R, {" n
  37.     if(sta & RX_OK)  j0 M1 u+ U0 l: B0 G. t1 B
  38.     {
    7 c3 {# t8 }; V7 E& L& F
  39.         printf("sta = 0x%x RX_OK.\n" , sta);
    7 l$ V! F1 }: T: p+ e7 J
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);7 W& g0 u1 Y, [2 T1 e
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
    : A5 k+ A7 U! F1 D
  42.         return 0;" K4 S& |# g% q- V' f
  43.     }      
    : ?) n3 c; o1 z  I/ }! n
  44.     return 1;; y8 o$ b$ o* m! v
  45. }   
    ! e' y7 S. I4 r" U% y

  46. ' q6 E/ i- S! O+ |$ g. B
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)0 K) U& ?/ [$ T, H
  48. {
    ' v; ?, t# `; X6 {( ^1 ?$ Z# V
  49.     uint8_t sta;
    ! w4 a& a/ a) [' L1 Z
  50.     NRF24L01_CE_LOW;. G! y2 P2 }; B. u( V3 D' b
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);' r2 _% I# ], a2 B
  52.      NRF24L01_CE_HIGH;) y, i3 }8 |; Z- P. D" k' q
  53.     while(NRF24L01_IRQ_READ() != 0);
    ' b3 U9 D) ?1 h3 k% i
  54.     sta = NRF24L01_Read_Reg(STATUS);
    ' B  p  D9 `3 C9 M. S: t, q
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);- ^) |; r$ T# N: ^/ n6 q
  56.     if(sta&MAX_TX)( D# L: o9 [9 U6 K/ I/ U3 J+ a
  57.     {
    ( Z4 ?, N5 T4 ^# }( K6 `
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
    : E' d" ]6 ^/ _8 F0 k
  59.         return MAX_TX;
    ! M- m# q; ?; P* v
  60.     }1 `7 G3 U1 T- G6 w
  61.     if(sta&TX_OK)
    7 K' F' _) X$ R% W/ _0 s4 X
  62.     {
    " h3 W4 V: \* m) S( T. g
  63.         return TX_OK;
    # k, |" J4 ?6 x. t+ h
  64.     }4 o0 [9 T: K  e
  65.     return 0xff;0 H' ]' F) `7 E, E. h
  66. }
复制代码

9 T% o. q6 T/ L: X) t7 U2 x我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:/ e; K% Y6 g/ P7 K
52.jpg 53.JPG 4 Q! T: ~3 t* ~

, {+ h" N4 k9 e看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
9 H1 `# U$ M% }3 V# _
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
/ L0 z0 J7 q# Z$ Y( P然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
+ ~# _* O  k, V9 k1 f$ Y 55.JPG
; [' o* G4 b+ r& ^8 a% ~
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)的合照& }/ P2 s# y/ |, ?, P, q6 e$ {
IMG_20250524_125758.jpg 8 O8 @# V, L/ W" g2 g1 U

" Z% S1 I* [% M

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版