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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。/ G* r/ _/ k" c9 W( \) M
51.JPG
3 @3 f  N; Z6 g2 e* ]/ h7 y# ^: d3 p首先是初始化SPI接口,这个非常简单:
  1. SPI_HandleTypeDef g_spi_handle;2 V/ Y+ n8 K, R& O( O
  2. - t, L  X( a7 }! }5 F) D7 j7 e, r
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)
    * I: ^: E. ^3 t5 F
  4. {9 Z1 U2 e# b" a  R, t% u0 e
  5.   uint8_t rxdata;4 R. \7 Q/ t4 L3 R. q' X
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);/ c* x! ]8 N' N  {; I
  7.   return rxdata;! S  n/ m, Y# |) Y/ J4 t% q" Q! O
  8. }
    1 h, x. S, t8 y1 G
  9. ; b$ p0 r+ u0 B/ M8 o
  10. void SPI2_PD3_PC2_PC3_Init(void)
    . m, N4 ^" H9 O' o  b( u
  11. {
    / w6 O' f0 O- j2 J. ~) f4 O
  12.   GPIO_InitTypeDef gpio_init_struct = {0};
    / s# ~( Q( a. ]$ @. R! n* D
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};& e  H" T9 H& ]+ l. H5 p: l9 @  a
  14. ; b3 Z! }/ v' Y) U
  15.   __HAL_RCC_SPI2_CLK_ENABLE();
    5 ?+ a+ y! ]3 @) L  o/ j2 @
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();2 |9 i% ?' Z% V' y' m: _% L
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();
    " p! w& Z, [; _) ]" Y  y
  18. 8 \! i6 {& J2 i
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;
    ! K, L$ X8 m9 ~( c
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
    * P1 N% F& L% @- M% @& R7 Z
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    ' \  l7 ]$ c  o& u

  22. . u. o0 S) a# L. t) K
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    2 w, N3 @! L# ~) R! G4 {
  24.   gpio_init_struct.Pull = GPIO_PULLUP;
    2 v' j: _: z: x+ {6 J& h
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;1 Q9 @$ @; n) k1 H7 J) j) f; S

  26. - z' f+ _% N0 R
  27.   gpio_init_struct.Pin = GPIO_PIN_3;
    . {+ a( C1 ~+ @" m5 y5 Q$ R
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;5 b( ^: d/ C7 b, G8 _
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);
    & t8 M' h  C& s! |3 d

  30. $ E3 q3 y$ w+ ?% L8 v6 G
  31.   gpio_init_struct.Pin = GPIO_PIN_2;
    ! ]$ j' u; w4 \9 c& ~9 s
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;* `: }+ x& j8 C) g
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);& ?4 i; Q$ O2 i9 j% A6 Q

  34. , c2 }/ f) {# b2 ?" O, e2 B! w
  35.   gpio_init_struct.Pin = GPIO_PIN_3;; n3 b) m7 H6 j) B- C. ]
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    9 i( ~: Z  Q' I* I
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);$ _  X) W9 c4 M. |
  38. 2 t- b2 ^, b: c
  39.   g_spi_handle.Instance = SPI2;" F( B! M* L# y- W8 f% R- I9 G
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;' G8 Y5 K6 T% Q4 P
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
    ; n* h; i4 T$ B  J
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;- X: n3 ]+ l- _+ U
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    ! R5 |' ~: \2 S. d) }' m/ J
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
    / Y; J2 C  H. h$ ?; H
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
    4 K. w& \( ~8 D* x
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    - x" O) X' D% e1 H
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    : g# @8 ~3 @+ Y
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;8 \4 Z+ c4 _1 K, S# M( S2 E- T
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
    0 M1 E# E" @+ g( E" e$ L1 D
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    - E$ A$ m* v& b
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    0 I7 w5 L1 j% D" c- w# ~% U7 o
  52.   g_spi_handle.Init.CRCPolynomial = 7;
    ! G: l& K. |* Q: z2 Z* |: m9 y  T
  53.   HAL_SPI_Init(&g_spi_handle);: K) j$ S- u2 `) B- r4 T( H% Y1 E% ~9 b

  54. $ H% h7 S, \+ S$ Z
  55.   __HAL_SPI_ENABLE(&g_spi_handle);# Q3 x6 X  C) I
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);0 t. I: F1 z4 |% ]  g
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。
6 q! e2 h% k* ^' A+ ^& _) K
6 |$ x/ u; J# RNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:
2 _' R3 W# b4 ~( A6 x; W, K1 r
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM
    ; f7 H' \, Y, R+ A
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    : w  E% Q# Z$ O: ]0 G
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();$ ~, n# v3 B: R" X0 s! k' d
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);* L+ U7 @3 C7 z% U
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
    6 s1 w+ A* k: x! L/ s) o3 y

  6. & \: ], i8 d: g, n. n- z
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM
    ! c' x5 q; c6 u
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14, u4 i, N1 Y! y2 Q9 I+ q$ z
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    $ G- x0 `; k. }: X0 Q
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
    " Z" k7 Y: ?+ A  p* G
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);4 C4 ?# L& B' @* f' Y

  12. 8 q4 n  t) g, Z1 q/ O+ g+ J8 p# F7 c
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF& D  e6 s" @1 A+ b
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_21 }# S1 f! x" G/ Z0 K% ~
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();2 {! l& z# W/ d
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
    ! O- @, Y) G2 C. L; t3 e
  17. ( L* j: U5 P# [  R- K' @- o
  18. void NRF24L01_GPIO_Init(void)
    ; ?7 A. m, J6 [. q( ?: A
  19. {
    * Z  w- p. Q/ Y& v
  20.     GPIO_InitTypeDef gpio_init_struct;
    ) a* |; ]! N2 @  t
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;3 \# p9 e5 d3 t( O; S- ~* B
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;; X( C" W* W  a: F+ w' v
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;6 X; \( j8 D: P4 e7 _
  24.    
    6 F" X1 o* m$ i# U: y
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    5 O7 R. g" t& z. A7 ]! X. O
  26.     gpio_init_struct.Pull = GPIO_PULLUP;
    2 r! O* `& G/ X9 Z6 @1 f5 |
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    2 _* O5 W: D: I5 ?$ B9 g$ I
  28.     1 w4 T# V/ _0 @
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    - x8 R/ @/ X. x8 g, m# k2 h' V! l( C% k
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);" U8 h4 o7 ^$ R4 f& d5 y1 G
  31.     7 Y8 \, h6 L* ]& Z) W' `0 n
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    , [( N8 ^1 U" M3 Y
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);3 o) @( g  h" z1 L; s
  34.    
    : e4 ~+ i7 ]7 W1 p( N
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;7 k5 [" S6 {3 B. l
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;
    1 s  r8 g9 w1 h. N1 ]
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);' O. z* [! }+ E$ g
  38.     - K! D4 ^% {7 o6 v
  39.     NRF24L01_CE_LOW;( Z2 I/ x; @& j4 }/ i" D' I1 z
  40.     NRF24L01_CS_HIGH;8 s$ B7 ~4 c  g; o4 \
  41. }
    * k3 b2 Z. N4 J9 z
复制代码
: b+ m0 @! _; `$ K
7 i9 j  y' U8 J! E$ @3 H6 ]
NRF24L01有五个可读写的寄存器是可以用来检测器件是否正常工作的:6 ], O$ f& Y  j3 @" S( t. \
  1. uint8_t NRF24L01_Check(void)  b( ~1 g& ]+ ^- n. s
  2. {5 b! l- b( \; a' f
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};) k$ @$ `$ c6 {, _% F* Q
  4.     uint8_t i;
    ' L* p; Q7 H9 {& t5 D! ]
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);2 m$ K/ R9 c! l2 F( L
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);
    " f+ V' b) a' i
  7.     for(i = 0 ; i < 5 ; i++)
    2 m- N4 x& D+ m% }6 S: L- R
  8.         if(buf[i] != 0XA5)
    : I8 |/ e5 T; r+ r. j! S; G
  9.             break;                                    
    ( r, J9 d- ]9 o0 }4 }6 `
  10.     if(i!=5)( J/ D. Z. r! X# Z- {5 `
  11.         return 1;# p; b+ o8 X% G) u0 H3 D! O% \
  12.     return 0;! }- L0 `- q: P0 H9 j
  13. }
复制代码

7 X" z7 {( _; {+ T/ u2 W( o# \8 L$ h
" b: E" ?/ L3 h. W2 _/ w/ Q# ]NRF24L01模块同一时间只能设置为单独接收或者单独发送模式,属于半双工器件,要实现全双工收发需要两个模块:
! [, j3 n# X' l! H
  1. void NRF24L01_RX_Mode(void)# C) W* Z7 W9 }* \+ m, J( y
  2. {
    $ u: i1 O) f6 i% Z' a+ [# v0 k' i
  3.     NRF24L01_CE_LOW;
    5 ^+ n- E- k) U: c" U9 Y
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    & n# K5 ^  l- M% U) r
  5.     / L7 L" o' Q' n7 S- h
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  3 V5 V. c7 T0 @8 z  E. |* k
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);" P* @5 ~4 o; v' q- R' t2 S
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);- F3 r) j4 z) A, q" _. A
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    % V' j/ q1 U) @& Q, c
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);# D2 x( y9 _3 t5 m
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);7 @7 m0 E  r2 T4 X3 }; P
  12.     NRF24L01_CE_HIGH;# I. I, n; b' D5 N& _: K9 g4 K
  13. }
    - k) e$ l- @. [! p

  14. 9 ]. K# A; {7 g1 q- U2 c9 T( X2 ]' Y
  15. void NRF24L01_TX_Mode(void)
    # }8 j+ d& @& |( C6 t3 u
  16. {                                                         " Z7 [# E7 e* @4 l! r3 R2 w3 j9 j) s  H
  17.     NRF24L01_CE_LOW;
    : h8 m% q8 i- \. C
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);, B+ t& T# L: i  ^) a
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    $ n; _# v7 h! u. |8 L

  20. - X& ?1 L- H* f$ m& w& K- _. j
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
    9 D2 I$ e) R/ L3 ~4 Z9 S
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);" h/ ]) D" \- X; h- Q
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
      O. ^' U4 I0 g: n
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    $ I$ p2 u. L( L$ s7 l# \
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);" ?5 B( s5 w- y# k, e
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);* C9 d" W2 E# {- }( C  j
  27.     NRF24L01_CE_HIGH;6 w0 |5 h5 E( ?1 ?) d" n
  28. }
    * E; }$ m6 ]2 [0 A5 D! w
  29. 2 [  B$ F' \9 I- q
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)3 H9 p7 c! l# i$ g: n
  31. {
    ) k: j) H+ ?7 p: k* U
  32.     uint8_t sta;                                          
    0 E, b% C2 t8 O
  33.     sta = NRF24L01_Read_Reg(STATUS);5 g5 s  a8 v4 f. f

  34. ( U& W1 [3 ?1 X( R) @5 d: H
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);/ I! t' O4 X# t5 P# a
  36.    
    # J* h$ B! G- X+ Z0 D( V
  37.     if(sta & RX_OK). n5 P7 t' d+ I: r7 d9 U5 e% P
  38.     {
    4 X1 p+ E( a. }. d1 L+ P3 M
  39.         printf("sta = 0x%x RX_OK.\n" , sta);
    * `/ G2 [2 y0 y$ D0 s0 W' z* K
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);4 Q5 O/ ~4 G1 ?
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);! g/ R- R& F2 _9 L1 j* P
  42.         return 0;
    9 O8 j) m" @: O/ e
  43.     }       : c& e1 M" |. a5 @6 J, N
  44.     return 1;
    5 h  H& e+ k/ M, f
  45. }   
    : ~- L$ v. ^9 H' t0 F/ P; x+ P" O; h

  46. 4 l4 c% h# v/ u" N
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
    $ f9 a; B5 f8 ]+ X% `' s4 J
  48. {* }: k. s! e6 L1 e. }2 o
  49.     uint8_t sta;. Y. y2 e6 p/ [" z
  50.     NRF24L01_CE_LOW;
    " B, k, E, O6 \
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    ) C' \  a. p& O% a* i) N+ Q
  52.      NRF24L01_CE_HIGH;$ J3 n$ z/ t4 R& s6 |' v( g
  53.     while(NRF24L01_IRQ_READ() != 0);7 z+ K0 w  T6 X6 O
  54.     sta = NRF24L01_Read_Reg(STATUS);
    ) G( b  S# E& I% j* i' G/ L1 I
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);3 P9 O: J/ u! @- t0 Y7 j& ^
  56.     if(sta&MAX_TX)
    1 `# O( l! o% T$ }8 a
  57.     {: n" u  ]" P5 _* }' K8 [, `
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
    * F8 L/ f4 c# p' k. P4 g# W
  59.         return MAX_TX;
    : j/ m' n. T( c9 j, B
  60.     }
    ) R) n/ n* e6 V
  61.     if(sta&TX_OK). s! G( e3 m) V- O4 }
  62.     {
    & e$ [5 K' C4 ^9 p) z0 v
  63.         return TX_OK;1 E( N: d3 W: y' G4 {: n) v
  64.     }
    . i& K2 ~" g) u+ }5 C" o
  65.     return 0xff;5 \6 H9 i, ]2 ?) L) f; a0 F. p
  66. }
复制代码

- W; F, E8 t) V- ~6 Y$ r/ J' v4 T9 ?: {; I8 d6 X4 y* b
我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
- @0 g1 H7 _9 Q5 P, T6 _3 C
52.jpg 53.JPG   N1 |0 n- l# z" O" }

3 X: o- W9 q( K1 H8 T看看发送效果,按下这个fb之后启动一行发送,在另一个设置了相同接收地址的接收机上接入电脑串口打印接收到的信息:' O) X! h8 L/ I
IMG_20250525_003610.jpg IMG_20250525_003612.jpg ) t2 E, T/ Q9 c( ~; n# Z2 E
54.JPG
; E( L5 T% ]$ f7 m& c. r然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
. b6 U; B* v( C3 G* G7 A2 C/ O 55.JPG
3 e9 w" d1 ]4 f+ \2 e1 F3 J# u
收藏 评论0 发布时间:2025-5-25 23:45

举报

0个回答

所属标签

相似分享

官网相关资源

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