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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。8 Z; l8 Q& p- [4 j3 d( l3 L2 l
51.JPG
" Z8 E2 y1 k0 @3 ^+ S4 X* r首先是初始化SPI接口,这个非常简单:) n- a/ `- f( Y9 A; l6 m
  1. SPI_HandleTypeDef g_spi_handle;
    + W$ `7 b& |) X

  2. ' {# X( @  u  t
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)* ^; ~* |0 H! k, G, A5 f! L
  4. {# H) S% K( O# C, Y6 m6 S+ p! ^
  5.   uint8_t rxdata;
    2 K- t3 M; X) h+ E
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
    . w9 q+ [5 `+ ]3 `, H' J6 i9 U; b
  7.   return rxdata;  |6 |0 M/ T; @- x0 l  t9 [# `
  8. }
    ; C9 z0 ?5 z$ J6 _) H
  9. $ c3 o( ^  s8 z8 @$ H$ l
  10. void SPI2_PD3_PC2_PC3_Init(void)0 d; h7 S: B6 R
  11. {$ Y3 h, W" ^! q
  12.   GPIO_InitTypeDef gpio_init_struct = {0};; p6 D! H5 X, _7 ^
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};5 w  Q6 H; W2 u
  14. + ]4 X+ ^! W( D
  15.   __HAL_RCC_SPI2_CLK_ENABLE();2 {- ~; R5 S9 H* [4 I! ?. B
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();
    % D* M& {; R3 o- q8 @1 F; G. X
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();/ O' _$ s5 v8 C$ d. [8 {. N
  18. ) z3 c4 i+ R5 |0 J% V4 c
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;8 I1 I, j* }+ o$ n$ {4 @
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
    $ R& d$ ?' C( K% V/ n& G5 U
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    ' l5 {  r$ B, ]
  22. % N1 a/ Y$ ?* }8 ?& Q
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    ) M4 L0 L8 D. R( F$ k1 w0 {
  24.   gpio_init_struct.Pull = GPIO_PULLUP;
    ' k( L* u3 ?8 v5 T5 Z5 J7 a+ B" A
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    & [2 p! z: }9 I% L* Z

  26.   L, `; t( V- `" ~
  27.   gpio_init_struct.Pin = GPIO_PIN_3;
    . w( P6 K, u+ F4 `) p+ g" f
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    6 D5 k8 Q, [1 r" ]$ m, e: f) Z* |
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);( X5 G6 W* k' Q

  30. 6 r0 E& O" D3 j
  31.   gpio_init_struct.Pin = GPIO_PIN_2;; J# c0 P9 [5 s* H! H- R
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;0 Q( r. u! H& y5 t; U: b
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    $ w( [' ^9 q+ h

  34.   ]7 Y7 M  M7 l3 @8 L& K/ |
  35.   gpio_init_struct.Pin = GPIO_PIN_3;
    + d  [. k# ~5 ?: p
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;9 ]4 \% K/ g& |& G7 O
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    $ Z2 D) ?! |" @, S: q' [9 }: S

  38. / i% L; ?2 H8 h  o
  39.   g_spi_handle.Instance = SPI2;
    + D% K0 w$ F" V+ `# _% r* F
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;, {' G  Q1 F  b
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;3 C. T+ p3 k6 y: O5 b: j, J3 y7 n
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;# h4 d1 v3 L5 h4 |
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    7 o( ]6 @1 r- Q& J
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
    & f5 E4 {) Q9 q$ y9 Y1 g
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
    " e) K% v: `9 D8 U7 `  E& S  E% V- h
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;: A7 y+ i" b) S" u) R# i; |$ A
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    " J. X2 z5 @* _6 E+ Z4 w
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;+ U5 j+ n3 q  Q
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;) s3 Y7 Y5 s& r# P5 j
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;6 Y- f# \) H4 d! k9 Q3 f
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    , [1 [: f5 Y' S4 Q
  52.   g_spi_handle.Init.CRCPolynomial = 7;. t7 Y! m/ X# x- [% Y+ O
  53.   HAL_SPI_Init(&g_spi_handle);
    + k- c' Z7 z4 Q7 ]5 j
  54. # U) [9 l" u) M! h3 L3 }% J/ m
  55.   __HAL_SPI_ENABLE(&g_spi_handle);5 [7 |2 g" G7 H7 g; t: Z* Z
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
    ) p, z9 P6 o& F! q& [0 G% ]
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。
0 b$ P& L, m# L$ X. K
) x5 A* L* }& \. UNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:  a2 l% C1 e) Q
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM
    5 ^) p$ @6 c8 h1 Q( }# v$ j6 `
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    8 S& S/ D5 K% l5 V. t0 ?2 d, U3 e
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    $ g; ~$ j& r0 d7 }
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);9 e) d2 L/ i3 W0 ?
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
    . c; @) m0 O4 s' m1 M8 d& }5 g: G; P

  6. ; C* S4 z) P* y  i* z
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM7 K: `) b; d1 B* T% d( Y6 R% b$ s
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    1 J" R, u2 a3 @
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    ! b- ?' G. K4 H6 D
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);+ s: q0 X, V) H
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
    3 G- X. {7 n5 _4 n# l

  12. 8 k2 Q1 C0 n5 ]; `  q4 G2 B3 y
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF
    1 i- }' l8 P1 m
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_28 O* q$ g- @0 U4 \+ |2 R
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();
    ( ^* @$ o; W# S% t7 s: ?' K7 b
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
    7 ~9 T* v" P, x

  17. 9 h  v' F1 ?9 Y- Z& H1 D6 x
  18. void NRF24L01_GPIO_Init(void)
    ( ]# c+ N& e& n+ {" x6 K4 W
  19. {7 s. n# h( \. D6 A5 z5 L8 L7 T
  20.     GPIO_InitTypeDef gpio_init_struct;
    - ]  C. z# M' o2 W8 @* V0 x
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;  e9 w. b* e9 U2 P+ z- z
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;) Y' u- Y, g! Y8 l2 p
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;6 T" ]4 ?+ `: l3 h
  24.    
    5 W8 m6 m& {1 X: }9 i' ^5 _/ T! J5 l
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;9 z: l4 D# w0 a! B+ W
  26.     gpio_init_struct.Pull = GPIO_PULLUP;
    , X; _6 n3 b; T4 Q/ Y+ |
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;( E0 w5 X: S& S; H! e, I6 v5 U
  28.    
      O+ P5 `* L: p: R6 ?- D
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    7 D7 y4 f  R9 Q2 J1 q' P2 f
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);: z* y; U* ~) H" x/ r* e9 a1 F
  31.    
    # a) b7 \% \0 O* q
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    1 A% n$ U/ R/ ^+ a% `# a
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    9 [4 p" @3 F4 b8 F
  34.     ; c+ }. D5 j2 I2 {+ A0 Q& ]
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    4 m! `/ k# F' G# j8 L: @7 t
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;/ P7 D  q: P7 M; N
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);# \3 T% R' R. z& x3 W
  38.    
    $ i. I5 A! Q! m1 l# L) @
  39.     NRF24L01_CE_LOW;
    5 r+ f4 |' r3 f! l7 a6 b; D
  40.     NRF24L01_CS_HIGH;
    ! W- |5 W/ w" H+ S! o% _/ N
  41. }
复制代码
5 W: l% \4 \: i
4 K  z  S6 O1 {1 |5 s. p" }7 u
8 ~: T& Y4 l* r* v1 A+ n3 h2 P  r  l
NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:' _8 a% K6 l' _! h/ l5 L/ _4 V
  1. uint8_t NRF24L01_Check(void)6 r0 b4 ?- g' Y3 L, P
  2. {! k+ U0 r% y. S
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};; Z8 M3 V( a" B
  4.     uint8_t i;& f2 @6 d3 `2 x. X( l
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);+ ^; E9 r' |3 W3 a, @& s1 i3 f/ K) E
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);
    - Q; \$ A4 R8 ^. h7 `
  7.     for(i = 0 ; i < 5 ; i++)9 Q. {6 Z8 u- A
  8.         if(buf[i] != 0XA5)$ i! U' {% S* T, F9 q4 o; T1 h
  9.             break;                                    4 O' a4 z4 X+ J8 r+ L: Q% f2 H( C
  10.     if(i!=5)9 g! ^, o0 V6 w5 l) s( G$ a
  11.         return 1;
    . O% o, C! V  E( x/ \
  12.     return 0;
    - c+ E  U8 }/ M& U$ o
  13. }
复制代码

' S# T  w- G& \
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
' n" N6 O2 U) o- I* G4 v  t4 U. K
  1. void NRF24L01_RX_Mode(void)( y* b  P' Z' s& T9 U; x
  2. {9 S; F0 k1 b1 K4 B5 }
  3.     NRF24L01_CE_LOW;; k& Z. `; q, Q: M( G+ A3 d* q
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);5 V/ |1 J% y3 Z6 w7 n
  5.    
    # L7 ?/ F' W1 G& o' D( E1 I
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    ' W, E6 l6 p0 a
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    & D8 d' M+ `9 c+ V6 B
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);  x" c' L/ T, \  I" R- [5 A+ y8 P
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);' v5 v) G6 A+ M4 H
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    $ h9 Q, `; k6 n- ~
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    3 U, q  D. P- P, I! V
  12.     NRF24L01_CE_HIGH;" B7 v' d0 g: f4 L
  13. }& D/ y) k" d, k$ F5 [$ q

  14. ' R, L$ z! s- x  ]; L% A2 K1 J
  15. void NRF24L01_TX_Mode(void)
    & t) u+ L3 L: g% n! Y# Z
  16. {                                                         
    5 g. h! \5 ]9 g4 v
  17.     NRF24L01_CE_LOW;
    7 \2 @  c) O7 K# t2 D
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);, [' s& R! f% A( b: D' |. w
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);3 G( g6 k; x; g3 @3 S
  20. ; P. J$ P! V" O1 `& \" \' w8 X
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);& \. c1 M! j" q8 v1 Q4 M# x" |5 Q& M
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    4 u) V( K% ]" e3 o; O+ E
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);' e) l6 O& y6 |% G+ t) a* W' C
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    # C& z2 n# g: s- h" F: n* ]
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    5 w: L( y; N/ \" n2 V
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);2 p% M* j* G; Z
  27.     NRF24L01_CE_HIGH;- e3 Y: H  J! Z- o
  28. }  b% q6 Q# K( c* }! Y" b

  29. , s( D) [: y: c3 r" T) H  ?6 _
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)2 N- \0 J* q4 T) {
  31. {
    & U- n4 u9 ]$ B- B; u# u, F0 O
  32.     uint8_t sta;                                          
    % A0 R1 t* }  k; W  z
  33.     sta = NRF24L01_Read_Reg(STATUS);
    1 ]% G( e6 z& a, S

  34. 2 b3 h2 ]6 X6 e0 @) t
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    - Y3 _5 f% S) q3 _
  36.    
    " k* O# i' G5 ?, Y5 z/ |. y; }
  37.     if(sta & RX_OK)! d2 ^0 D" a/ I( ~7 I7 E+ p* m) O
  38.     {, R# y/ R7 e4 }: E1 Z+ P0 r
  39.         printf("sta = 0x%x RX_OK.\n" , sta);; {4 e7 V, R8 X# R) B5 ?8 _
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);: g! S; C; ?% V9 R! h; @7 l
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
    ( e5 P# f- t! G6 m5 c* W- Q
  42.         return 0;" P9 d/ o$ ~5 T- s6 D
  43.     }       $ I2 v1 \7 i  I4 j# {( {
  44.     return 1;) G8 o. S! [3 D6 {# M
  45. }    ' p3 o9 [% j3 ^& w

  46. " `5 n7 k8 g4 [) m) m/ n
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)1 ~7 F% S% T* L) z6 A* K- W
  48. {& s( O8 h1 a. ?  N7 X, q% D
  49.     uint8_t sta;
    - p9 g5 d8 l- Y
  50.     NRF24L01_CE_LOW;
    8 C( Y4 k) I1 K, R: }/ Y6 P
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    / `  Y4 n! L: Q
  52.      NRF24L01_CE_HIGH;
    $ `+ T# N! |5 Y) O0 q/ }
  53.     while(NRF24L01_IRQ_READ() != 0);
    $ ]& O0 h+ `, Y8 a6 ~1 G
  54.     sta = NRF24L01_Read_Reg(STATUS);
    5 N& Q$ c; t; }7 H, T
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);2 r# L0 `2 _: T7 p& s- U1 @8 d
  56.     if(sta&MAX_TX)5 g* z! J, m0 b# h$ f7 U( N# d
  57.     {* p+ w1 _3 k( C+ M2 t
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
    1 F1 g9 e$ {7 @
  59.         return MAX_TX;4 S0 h7 D4 T! m" }4 k$ @3 R
  60.     }
    ' P1 e8 A% Q! c; _' ?
  61.     if(sta&TX_OK)+ r" x8 `& V) ]$ v; n
  62.     {
    4 ~7 q6 U# s$ i6 j. ?7 z
  63.         return TX_OK;# ^4 [) C6 c' h4 P4 t  u0 ^0 s
  64.     }
    : q2 c' W" D' s, D) u. L0 ~
  65.     return 0xff;$ _0 d: z0 q1 @8 i# Y3 g
  66. }
复制代码

; a) W' \7 g( ~  z! {我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
, K+ R& v6 n& ~8 `: \6 y6 d5 ]( R
52.jpg 53.JPG ( b0 c" w7 l9 Z$ w8 ~9 s: s

  q" x9 a% q7 ^" C7 f) X( Q看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:8 y" D. I5 V, u
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
$ y6 m0 }; ?2 X9 G- ?然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
5 Y. K3 E7 o3 b; ?6 ]4 n: c! f 55.JPG 8 X: `! {! h, m3 Z% r1 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)的合照
( R0 ]3 i! D8 Q2 P5 R IMG_20250524_125758.jpg ! g. }# x: A( {- B+ M$ z

- Y( m" ]0 t5 M

所属标签

相似分享

官网相关资源

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