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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。
" V0 j/ B! |- z2 v 51.JPG 4 a! r9 P% A& T7 P5 d- i* Q- U* l
首先是初始化SPI接口,这个非常简单:; Q  ]/ W9 g- L: i4 \/ J1 f
  1. SPI_HandleTypeDef g_spi_handle;
    ) V4 [  I, G$ s6 o! w# O/ w
  2. " `8 b; n& v1 T/ N# }
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)
    # U. ]8 V4 n) m
  4. {
    7 V# K% ~8 t# L/ E/ V# `
  5.   uint8_t rxdata;
    5 e9 n/ O7 ~! f8 u, Q& ]: x
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);+ D/ t& f+ Q+ ~% P
  7.   return rxdata;
    * F& c  O& S  ~. x( Y) b4 b% o$ |
  8. }
    9 a* _2 d2 W0 a# \" e# l# D2 C

  9. , q! t% ^1 D. d, _+ y+ j* A8 M
  10. void SPI2_PD3_PC2_PC3_Init(void)
    & y8 x3 [  I( Y( o& ~  G
  11. {
    - b' K0 \) k+ F% A
  12.   GPIO_InitTypeDef gpio_init_struct = {0};3 Q1 ]# T7 u: n. ~* r
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
    : D) ?" p& w: a4 W) I

  14. $ {! ^: p9 q/ z. H6 u) d
  15.   __HAL_RCC_SPI2_CLK_ENABLE();. g) t' L* r- a* z8 t1 M) y" K. f  @
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();$ D& ?- P& o" x/ e, d
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();! K+ M* A( D: ^& f$ J# w9 _' f

  18. - n" z1 @' u: G
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;& l' v. T) `9 e9 L" J  E, M0 T
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;  G4 ]# J6 z. [" d6 p% I
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    : m$ I0 @* p8 ]8 g: j# \7 g
  22. 3 |) r; z. y, e2 k4 J
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;+ j3 ?, A$ p! U8 D9 {' o' `
  24.   gpio_init_struct.Pull = GPIO_PULLUP;2 L5 B4 E7 _7 L0 B5 q
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    2 |% v8 H; z2 L9 R: {  i
  26. 7 {$ ]% {) V) O& O; m6 Y
  27.   gpio_init_struct.Pin = GPIO_PIN_3;" i7 G  j4 v! o3 [; A5 X9 x
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    / ~& j5 T. ?: _# }& E4 h% K# Z
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);! Q7 [$ D+ ^. p. U

  30. $ a$ p- M4 D2 M6 H* I0 v' L
  31.   gpio_init_struct.Pin = GPIO_PIN_2;. E" {# ]. L$ t! @) T
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;/ A* B  G% U* t& D7 o# n
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    : R4 u/ V4 T9 J: w

  34. 5 c9 u2 I* Y! g$ c: I
  35.   gpio_init_struct.Pin = GPIO_PIN_3;' @  P3 c$ N* S' v
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    2 d- {0 F% {2 D: h% m, r* ~
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);. v, A5 j8 R; L7 v
  38. - `# C( `6 a4 ^# G4 k7 ^6 r
  39.   g_spi_handle.Instance = SPI2;2 q3 ~% E" `( B3 h  |5 p; O3 p
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;& E- d! A9 k1 C/ L# t5 X$ L; p
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
    ! ^/ {) X, ^' h8 [% F: S  p
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    9 O: d& \5 k3 [4 i, E6 u8 A
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;4 K+ J6 ~2 H$ u4 _% \  g7 c% i0 l
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;( w: s* C% ^  {5 L( I
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
    # J! {. V* ?* l1 ^; _
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    + _8 u' Y$ ]# ]) N1 I
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    . @8 H: o+ X4 b$ _$ `8 S8 A" t) |
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
    % s( O4 c, k6 {% G
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;; e: c7 s! P- h* T1 e
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    ( D, m, S$ a% n$ q$ t5 F2 L# Y
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    ! w+ q4 s, [$ @/ \
  52.   g_spi_handle.Init.CRCPolynomial = 7;; V. v6 k3 d: s. U; @" d
  53.   HAL_SPI_Init(&g_spi_handle);3 g0 K0 l8 x5 w- s' ]
  54. - n( j. X; x5 {
  55.   __HAL_SPI_ENABLE(&g_spi_handle);. v3 A7 Q7 G1 f
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);1 P& G7 |) m4 {9 _
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。
# b3 r2 F( D: o# v' o
1 o. W. b$ Z, x7 z0 G  k' INRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:: z1 |) K" c1 u- j
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM( U! ?3 D  ^6 x1 p7 F; X
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    ' \; W9 T5 d0 x
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    2 ~& X$ L* Z8 D# }
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);
    4 Q9 f2 K" W$ x6 W6 [" H0 `7 S
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);2 |; r6 \) ~% U
  6. 0 t  E& s4 y; w
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM# l* {1 t  ~" ]3 N
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    * D2 D$ a2 J* Y% W3 _
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();# T. Z0 O) }' {
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
    8 M5 I+ M* H3 @) o6 }$ |7 d% B
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);6 w( G; I5 u+ V" m

  12. / `" D9 S6 S$ ]- O& Z
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF
    4 z( t. ]. a5 @2 `: O
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2
    0 s4 D0 j4 N5 G3 L, n
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();: B) n; M; p. t
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
    ) q" D1 I4 E* w* G6 W- D( O
  17. 7 n( [" t- }1 Z$ Z
  18. void NRF24L01_GPIO_Init(void)
    : G. R3 N: ~: s4 P4 z
  19. {( L+ S0 z# ]# Z9 {7 ~
  20.     GPIO_InitTypeDef gpio_init_struct;. L8 }( F2 v: r  R: e1 A
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;# h" a' q0 F8 ]" [$ s
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;
    8 o$ K) P1 a5 ]" M+ z9 J1 o7 i* T
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;% l6 c* Z: \1 R- ~" t4 v0 z% b
  24.     ! b0 L7 b/ j4 W( B( G4 [! o. Y
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;+ `) C& m/ F' {  i6 D3 M, t) L
  26.     gpio_init_struct.Pull = GPIO_PULLUP;: _7 P- O4 \( i' F% @1 u) A
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;( p2 b2 F7 t/ m1 [1 C
  28.    
    ( R3 }( k! N, t5 p8 R) {# B( d
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    ' X4 R2 s- |6 ^0 g& Y. z$ d
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
    - \, z0 C1 ~- K4 J* y3 n
  31.    
    5 _$ _# b$ ?( v  h) v; i4 e3 d6 M
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    5 A9 w7 P' U. C4 \2 l$ W
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    ( C% b$ j+ C/ i2 E$ d0 i9 L( z
  34.     7 A6 f0 B% }# R' D
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;  N; D! p. @$ s! t6 z8 ?+ q+ t, `: Z
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;5 j; @4 H+ \5 P% q9 f$ q
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);0 I! |& S' G3 [) S% Y
  38.    
    0 a$ }# o3 {0 T: G! K5 S
  39.     NRF24L01_CE_LOW;8 W% q) r* `& c: Z+ X
  40.     NRF24L01_CS_HIGH;% n" B% u6 h6 `& ~7 f0 }
  41. }
复制代码

0 B7 E  C, _5 r2 w, B/ V, o& \% U
) X; w1 {# E. C6 W
6 {2 P" U8 V% b/ T, M3 rNRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
- \/ F. k9 v% Y5 r0 a) ~$ {2 |+ ^  f3 H
  1. uint8_t NRF24L01_Check(void)
    7 a( H9 \; J( a( ?! P, t9 K) O
  2. {. b! ~5 V$ x8 v2 f2 [% f) ?
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};6 X5 X) J6 e2 }& K
  4.     uint8_t i;
    9 [5 p( I4 @% \( p
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);, {3 }3 A) V* o& d
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);4 }; N2 O( M, e' D8 D! Q
  7.     for(i = 0 ; i < 5 ; i++)5 c. b9 F; C2 |% Y
  8.         if(buf[i] != 0XA5)
    8 r, L, G1 F1 t+ `# Y4 b+ v
  9.             break;                                    ! i6 Q! \0 |. K- S3 O& m
  10.     if(i!=5)" l5 L% x: u8 m5 \
  11.         return 1;5 T8 D  J4 c# G: {* A
  12.     return 0;
    ( {' @5 o- ?* n( @0 H
  13. }
复制代码

2 `9 a% S* N* |
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
4 O( j+ Q7 C2 |8 h; Y; W9 V1 m
  1. void NRF24L01_RX_Mode(void)! y4 R* [2 s' p! c
  2. {
    ) J0 d( J9 S5 h8 \' J% i" S
  3.     NRF24L01_CE_LOW;
    . o2 P2 z3 [( b  S0 {
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);5 n" B. j+ `/ t6 _' I3 o: s
  5.     " Q% J; D9 [' }- n4 N  V
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  9 |6 h& E% C' v" X7 V
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);& ^  u/ B8 U( x' ~& O, \+ E5 y; m
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    3 M. @/ C. i4 J9 L3 E, h- r/ k8 X
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    , x( w" _4 r7 S" ?* q
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  w3 x; V0 S, J" l2 I
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    6 g5 }' }5 q7 Q% D
  12.     NRF24L01_CE_HIGH;
    ( K8 h5 j, L  k# v: M0 M' H
  13. }7 K/ Z0 K; E9 Y* m- H% ]

  14. 9 b( i- {  _- T6 v7 _
  15. void NRF24L01_TX_Mode(void)
    2 ?6 G0 f7 U! n2 }
  16. {                                                         
    ( f! G3 N# P- j9 J8 Z' t
  17.     NRF24L01_CE_LOW;& ~- z( o# [0 z$ g5 K
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);8 L. X* _9 k( A+ D' Y6 A$ U
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    9 c& L0 l- e* G# G' H9 y
  20. 1 a0 ]* i% g- B4 q; k. ^
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
    ' l$ J/ O9 V, V1 ~9 ]4 A
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    - x, K! B$ Z" c5 L
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);/ l1 C0 A$ Y, U, {* u
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);5 ], `  T/ f4 {
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    8 w  z$ H9 M" D) S0 i9 F
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);( u1 O; ^+ ~) i5 \) o/ X" h5 v
  27.     NRF24L01_CE_HIGH;, P: f- C/ q7 ^/ j. J4 J2 a0 y
  28. }: Q, ]& F8 a7 u
  29. ) j& W; `' B5 _8 x
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
    4 }! N- X* d; \/ N* I1 @5 T
  31. {
    9 e( ^% O0 I5 M8 @  q
  32.     uint8_t sta;                                          
    ) I3 M: O9 m( ]9 B7 l: Y; i
  33.     sta = NRF24L01_Read_Reg(STATUS);* j  d8 t* V. O" p

  34. - o0 T% a' t' `0 o# m: e, f
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    . w8 @+ K  g  _+ I% X
  36.     - q: W) e0 c; s+ E3 b
  37.     if(sta & RX_OK)# t5 J. I0 _) i8 t8 j5 M
  38.     {
    , X' a* P9 g5 h
  39.         printf("sta = 0x%x RX_OK.\n" , sta);
    ) L5 H! r7 ~5 [, T1 q2 c
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);6 A/ \# _; ^" V* H7 e, o
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
    + u. A" d9 H  ^7 B" u% p* A
  42.         return 0;1 {' k( r! l: V* o1 h; f( M
  43.     }      
    : B" t# ^/ e7 i' G1 Y+ n
  44.     return 1;
    ! o9 X; C' R! `
  45. }    4 G) ^( l8 w4 h$ J
  46. / ?: W$ d6 q& @0 v1 D1 ]. f0 K
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
    5 H; |% v( {: f, m: y  X
  48. {8 ^! ^* |/ M6 P$ A* |% B
  49.     uint8_t sta;
    3 R# i) ^+ C( S* e9 w8 B
  50.     NRF24L01_CE_LOW;
    / N$ p  A9 \- z
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);' |* N# B; \0 B0 i
  52.      NRF24L01_CE_HIGH;
    6 x4 X& @/ k9 N) g, Z$ N! h
  53.     while(NRF24L01_IRQ_READ() != 0);
    1 U; ^4 R- x; E& ?+ p5 j7 c6 c" i
  54.     sta = NRF24L01_Read_Reg(STATUS);1 c% R3 ]& i- m. U& X
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
    - C- q- H5 w) Q" B
  56.     if(sta&MAX_TX)" Y+ u) _& F* x* ?# P* ]+ ~
  57.     {- f% ?1 }, Y) {, l4 _' Q& z
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
    0 a& }! d/ Y, a
  59.         return MAX_TX;& u/ b$ \9 H( ^5 q
  60.     }
    , P9 V$ \3 w* e1 y9 X3 Y( b9 I
  61.     if(sta&TX_OK)8 C) y% z2 f$ |& _' _3 v
  62.     {, G# E/ D1 O  f1 ]( F6 j
  63.         return TX_OK;) P1 U: b; t! {8 M. H
  64.     }
    $ X4 z5 M- H6 F' O2 Q/ N
  65.     return 0xff;8 k# ^! m6 r2 v
  66. }
复制代码
5 C- C) N8 N2 S" a3 P5 Z2 T' B( _
我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
% S4 N; ~% B# d" s+ H
52.jpg 53.JPG 4 A6 h) Z; S, c  _9 t8 E* _& f
& F, W2 r; M' ^- W8 s
看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:+ [( X' W3 m! T
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
5 e. A7 H0 o! h6 v然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
7 E- z) k) u- v 55.JPG 2 Q- r) y) o! x$ `/ z- }
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)的合照
7 O9 j0 L; u/ k- z1 X% V IMG_20250524_125758.jpg + ^/ H: I7 h7 E# N, r/ s

, a% b9 J2 V1 ], [* ~5 T! u9 h

所属标签

相似技术帖

官网相关资源

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