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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。
' C$ B8 ]1 s) f! U8 D; I! A) m 51.JPG " Q. G) h1 y# R3 H
首先是初始化SPI接口,这个非常简单:
- E% p5 N) S; V4 _
  1. SPI_HandleTypeDef g_spi_handle;. i& I. y: k  N+ Y0 c& q' q

  2. / q& C& y$ v, x6 u; ]1 M
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)" b( L. `: J# X! b( w- w
  4. {( `  q, z( I. t6 E
  5.   uint8_t rxdata;7 B- e! G* b5 ^( y( o
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
    0 s" W' x0 [" I' @; O
  7.   return rxdata;
    ! r8 V) Q- d, H$ P* f3 G) S' f
  8. }
    * T9 r; u2 P3 \+ i, `% n/ @
  9. 4 v2 D& A) }% K
  10. void SPI2_PD3_PC2_PC3_Init(void)
    9 d4 M/ [6 c% X
  11. {
    - X; v6 J0 e2 P, P' A
  12.   GPIO_InitTypeDef gpio_init_struct = {0};  N% ^4 f/ C7 Y+ Q( Z1 I
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
    % \9 X8 F2 w$ T; d9 O7 F7 _* a1 M
  14. ; q3 `" e4 h  h' j) p
  15.   __HAL_RCC_SPI2_CLK_ENABLE();( L( R/ c7 P/ v2 W0 k3 D# G
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();- Y5 |, N& c! J, S0 C. E
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();8 Z5 Z5 O! A% A" d  t

  18. 1 X$ C' P$ E$ v; v6 }- _
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;
    6 X% R6 V$ n: g3 a4 O$ [
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
    : r- R7 @$ Q& L* w- }
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    2 F8 y. Q) e" u8 y0 R7 z) G

  22. ; U5 c9 w/ k+ z. Q2 \
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    ; @. m- x* H+ F6 {
  24.   gpio_init_struct.Pull = GPIO_PULLUP;7 F* [1 e  T  v
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;) p0 Z) {5 i* |) E! E
  26. # V8 j" M8 V( N; {: P5 f, y; l' r1 s
  27.   gpio_init_struct.Pin = GPIO_PIN_3;
    6 E- P) x  F  R; O
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    # x  y& G% N8 Y. V% t  W- C6 z8 b9 q0 I
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);
      H, N0 u9 f; P  R( A$ T) C% ?
  30. 9 s, s. T8 H$ I2 l
  31.   gpio_init_struct.Pin = GPIO_PIN_2;5 p- O! Y: S: _3 T
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;; E; C( z. f1 d6 {4 f1 M7 @" `
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    ' H2 l" c% N2 u- z! q4 s7 B, Y7 y  V
  34.   _% [- B$ ?/ X* e
  35.   gpio_init_struct.Pin = GPIO_PIN_3;  g/ r$ M+ ^% A& s: z
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    . V: w& q; X1 s" |) j
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    / D! o& F  f( l% A0 q
  38. % o. u9 l3 q- T3 l' |3 L, L# _
  39.   g_spi_handle.Instance = SPI2;" u! S6 Q9 Z. e
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;
    5 p6 P& q; |! g4 p- G. m7 ^
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;, l( i, m+ v  J# n! }' O  n# c# x
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    7 t# \; |* @/ H4 D- h
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;* E. n! a; d% T* {) P) i' y
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
    9 @' V; k+ Q( o! j: c
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;    ^4 |7 U% I- u9 G5 Z% o4 m1 z- {
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;2 Z, C# W% Z" }9 t* c$ I+ B
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;' q2 F' n  n: k1 O7 b" T
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;! y" ~9 C" j3 ~3 S$ ?
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;/ k( s  C6 x& H" |: T1 d
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;- B) b& B/ K/ B  r# ~, N
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    8 _: @& V# z) w6 F  G
  52.   g_spi_handle.Init.CRCPolynomial = 7;  p6 W( X0 Z! z2 k  _( d& D
  53.   HAL_SPI_Init(&g_spi_handle);, ^& S) b5 S. n+ H9 T6 C; ?
  54. 0 B6 @# G8 X- _/ q' Q; N5 k
  55.   __HAL_SPI_ENABLE(&g_spi_handle);4 J1 V9 v9 L$ `
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);, A$ U1 p6 v( l9 z" @
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。
5 h2 A. ], {3 e6 |+ K' n& N
1 i% m9 M" x* H1 sNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:; O/ x) i$ I: |  a
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM! |) v# i! P& ?% C7 r0 ^  K' ]
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13- U, g; L  U) I) W8 j: V8 [/ ^, C+ i+ M
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();- r7 E4 o1 P( ]9 i+ ~  O
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);$ _/ X5 r4 Q: I, L- D/ Q. ?7 g: u
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
    # n* i: D; R2 u

  6. " G; T8 B/ `$ c/ n  q: c- A9 v! E
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM
    ; E4 [/ I( Z+ Q) L- z% M+ F
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    ! X6 l8 @2 `3 M& C. W2 R/ G
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();- Z  j6 S# m5 i4 K
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);; L0 c& K  E. X! F" d' w1 U
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
    . k5 {+ H! d* m
  12. " u( w5 w$ w: J& B: \! G; ~' G
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF" Q* |3 \$ }1 I" y8 C( x5 S" E% p
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2/ X2 R6 d- `6 }6 }6 |
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();/ B8 Q. O8 \( a; B8 [
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
    1 d& r2 R  S" i

  17. 6 ~# ?9 s" [6 |1 t, ?3 g
  18. void NRF24L01_GPIO_Init(void)
    + D' b2 d8 v) v! G; ?* n- t4 v# K
  19. {/ n$ S8 C: v5 }0 x9 z
  20.     GPIO_InitTypeDef gpio_init_struct;+ S9 g7 Y1 J7 L0 |1 S
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;
    . @' e5 `5 b" a; ]) q  G+ T
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;
    , [, n) u$ W6 E  d* T4 m
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;8 o7 ?4 d/ K' z" Z( R
  24.    
    + x1 T/ p! U) f- |- A# |* ~
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;; |4 @3 p3 |) X/ l2 h) W
  26.     gpio_init_struct.Pull = GPIO_PULLUP;+ f. q$ v7 c  X
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
      E1 X* U! t; H0 o9 O: T4 Z
  28.    
    " G, k$ \. l$ t3 U. ]1 V
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    : r$ S, l+ |! w" S5 I6 t% L& z3 M
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
    0 v6 S3 Q, N. p& O2 B; d1 M' I
  31.    
    & }3 l; m* `  u' `5 S, B8 z
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    % a+ V# i" w, S% W( j
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);- S7 V; t9 T( o# N5 I! g+ W& L& T
  34.       k/ x7 E" C# t" x/ @' X: J
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;& T$ W5 |6 t) j0 x; ?& _! l
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;
    ( Q7 c1 a$ H8 c6 b' H
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);8 j0 y! U0 H3 a0 \* i2 h- U
  38.     " N$ v, N( X  m4 W* g
  39.     NRF24L01_CE_LOW;& m' q- L2 w9 c; p' V- }
  40.     NRF24L01_CS_HIGH;8 X) H- J4 q$ [: [7 ]/ e) V
  41. }
复制代码
2 m! b8 U6 s. U0 F) G  D8 V9 Q: ?8 [
! C+ b% D7 g8 [6 w9 l) ?
6 Z9 v4 p& R) i: V. i/ `
NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
7 M! G9 v4 n" b" v$ h& l& F/ a
  1. uint8_t NRF24L01_Check(void)" x! [% U: `, e& U) v
  2. {. t7 ]9 @' x4 U
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};, I7 H; h, E" V. s& T! F( \
  4.     uint8_t i;
    " Q+ D" V) z7 G9 T
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);: p, s9 w; a( j' ^+ A
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);' ~& \2 l/ N$ ~* w8 ?% `
  7.     for(i = 0 ; i < 5 ; i++)
    4 w9 }% S% M9 O! b( |( a5 \6 P
  8.         if(buf[i] != 0XA5)
    - R* ~4 m" ?/ y
  9.             break;                                    - ^3 r$ r) ^& B6 k& G$ n  `
  10.     if(i!=5)
    . o: U, P% [+ c) t) q
  11.         return 1;
    7 A8 _' T$ @( U4 b) t/ z' ^
  12.     return 0;
    4 g* P+ \+ P. s* M1 @
  13. }
复制代码

& |# l1 s5 c: O$ L# {! R" I
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:. o+ T* k4 Q4 F0 T
  1. void NRF24L01_RX_Mode(void)
    2 H# D: K0 }- i# n+ @
  2. {
    ( [8 g% g# H* J" R: s
  3.     NRF24L01_CE_LOW;
    & A. A' m1 C" ]
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    ( G* N0 L7 R6 v  r+ r" g7 e
  5.     * M; ]: g& ]. P4 \
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    - X" _" A: L, T: t+ r2 x& u) S
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);: z( x9 E+ j9 O  Y' X9 ?+ S0 g  H8 ~
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);; i5 W/ D. P! P* |6 c" N' E0 m
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    6 T  ~8 N! |* N! i: M, x! B
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    ! e5 i5 _$ U- P1 g
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    / Y+ z* a, }3 K; o/ w; @
  12.     NRF24L01_CE_HIGH;2 ~& O3 K+ |2 ?" @8 E& T
  13. }
    9 q# v. {' I" }: E# N. k+ f, t. U
  14. ) c' Z% E6 K; w: A' ^: G
  15. void NRF24L01_TX_Mode(void)
    ; h, ?: q3 }( t( r7 Y  T
  16. {                                                         
    ! W6 H! c7 _0 T4 O7 N$ z, }
  17.     NRF24L01_CE_LOW;# J+ J& m% a& |' V
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
    ( o3 Z+ O3 j- V3 A9 v8 Q  |; _
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);5 z+ b1 {- P# L/ b6 }( i6 @4 r6 t, n

  20. 3 W2 e) }) c4 `( @
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);3 e2 D8 H* S  A! o1 M" Y
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);" H( K0 Y7 i; m; T$ Q* y+ S( C
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);6 `( c+ H1 y& ?( D
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    % G* p' C( L* r
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);8 R  o6 m. U+ N& u+ `
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);- x" y: F1 Y3 J
  27.     NRF24L01_CE_HIGH;
    9 i/ f5 S! D* L8 q) M3 a
  28. }0 ?" d& |% G5 Z

  29. 2 U$ e+ d7 c% V0 W. x( w0 N8 d
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
      @6 @0 R0 a) [  q
  31. {
    3 x& o) v5 g! H6 X
  32.     uint8_t sta;                                             O( k+ }: B$ J# T, m% H3 O7 d. k2 ~
  33.     sta = NRF24L01_Read_Reg(STATUS);
    & m1 s! N& z+ k' B! T$ Q% }# a4 [
  34. . f- j5 q1 ^7 p1 W; i" Y& o6 U
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    1 |+ O5 M* G# c
  36.    
    8 x( A9 `% q$ y0 f3 |% w5 r6 r: V
  37.     if(sta & RX_OK)$ i- N5 }( G, s) R6 q- {2 {
  38.     {
    $ _  Y4 B6 F, D
  39.         printf("sta = 0x%x RX_OK.\n" , sta);
    0 e$ y% Y; Y; O! D- W
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);! M. _' a+ J; M! Y3 p7 U  c
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
    0 N/ t) A- X9 X: n
  42.         return 0;. d3 u% S- V# w5 K+ x* ^& ~* u0 {- L
  43.     }       ) q6 ?) A3 f/ G1 ^# w! l
  44.     return 1;
    $ A; ^' D" n+ X, D1 |
  45. }    " G( R7 i' d8 s; n# s4 E
  46. + \) ^5 e7 I$ V3 b7 H
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)$ m0 @6 @) `. v% J/ g, H3 d
  48. {
      O+ ]6 T% P2 R8 U8 [4 E
  49.     uint8_t sta;! e1 w& `9 h: ]( F0 w& `5 p3 w0 x) k
  50.     NRF24L01_CE_LOW;
    / w" t2 y1 {9 X5 d1 I: @& {
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    * k  b9 I! b. W. a7 l. _  m4 o6 R
  52.      NRF24L01_CE_HIGH;( N# Z" W2 y$ h$ t
  53.     while(NRF24L01_IRQ_READ() != 0);
    1 D0 _! L1 U- Y# w# v& U) D; D
  54.     sta = NRF24L01_Read_Reg(STATUS);3 m% o6 c' |) o$ z
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
    ) Z9 s/ V  u& C1 g: \* s0 D
  56.     if(sta&MAX_TX)- b$ o8 ^$ p- m' l& w
  57.     {& h# W& Y0 i9 o6 T2 q" k8 o5 i
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
    * y" F" C6 q, D; K$ f7 ]; y
  59.         return MAX_TX;7 p) S7 R0 d% r* I4 q( E- W1 B2 X0 Q
  60.     }% G7 W( a2 i5 k2 Q% w' N
  61.     if(sta&TX_OK)! q. h3 |5 ^8 F' p( f
  62.     {, `. i# e6 K' W
  63.         return TX_OK;, X( {- h( P# y' i$ P: V
  64.     }# d7 Y' _- V2 T, c
  65.     return 0xff;9 S  z& z3 Y, P# g& ~( I# _2 `0 Z  |0 e
  66. }
复制代码

. p  `( w4 U- Q  |9 y# M我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:9 X$ D% K4 n+ u: }7 F% r! U
52.jpg 53.JPG . @8 h6 a" _( `% U. v5 R( U. t( q

- h2 P) J3 H2 b/ p看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:* @) x6 F( B! u9 g5 e! i/ H
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
  G9 k6 i1 f( [1 n/ V然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:1 v9 h. G1 Y' H" q0 g
55.JPG
  j7 B1 h( ^; E  G, O8 U
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)的合照
$ b' ?3 E; J4 T6 j IMG_20250524_125758.jpg
0 K0 d! b6 E+ u- P. ~- W; \; h  K: p0 Y& C- C

所属标签

相似技术帖

官网相关资源

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