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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。% x1 g% V# e; x+ h# a
51.JPG 8 L; R9 ^. z- Z2 W& }
首先是初始化SPI接口,这个非常简单:
0 C9 X) [! w: p; h; P0 w+ t( z
  1. SPI_HandleTypeDef g_spi_handle;/ H) A' S2 f- v+ y8 }+ G1 [
  2. 2 T: C  X9 Y- h; `
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)1 D+ Q3 t0 F7 f
  4. {
    7 y' V3 a2 c' b. |0 G7 x- Z0 D
  5.   uint8_t rxdata;
      v' _! B! @$ h8 o$ @0 y
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);6 o) \  |( k2 f9 t2 D
  7.   return rxdata;
    ; ~( Z: W4 w6 u6 A# z% \
  8. }2 X/ H$ t; ?& `  C

  9. & n$ B8 [! @" W( \9 i: G
  10. void SPI2_PD3_PC2_PC3_Init(void)
    $ x- q0 Q' h& W( N2 `3 i% L6 n
  11. {9 s# z* U! X6 I8 I
  12.   GPIO_InitTypeDef gpio_init_struct = {0};% S: \% a( Y" Y4 A: A. y
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
    4 f9 s, u7 ]7 t' c4 N+ C9 _

  14. 7 Z) P: M7 a7 x/ T, ?
  15.   __HAL_RCC_SPI2_CLK_ENABLE();
    ' ?5 i/ A$ r* l; B
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();! w3 P  W: N9 r3 Q. V: B
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();
    ! X, u! Y/ W: E8 U8 `* P

  18. % u, U- g6 c: V
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;* g2 D, \6 @& B
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;/ K- |4 s7 r( a5 |# p! B
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);" A" b- `7 e, S

  22.   _, V7 T: n# ]5 G# _( [4 M
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;' i9 i! @& X# c  `5 X8 E$ X
  24.   gpio_init_struct.Pull = GPIO_PULLUP;
    ( P7 P+ x% g( j* k
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    % R- L& ?8 i! N2 S' L

  26. 5 S) T2 z& ~) S/ e
  27.   gpio_init_struct.Pin = GPIO_PIN_3;
    0 s7 c  v/ C/ d" d, W4 M( x0 o" Q
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    $ s1 d3 l! Z$ y
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);
    " Z' J* i; g2 s4 D/ M
  30. + r! `0 I* W+ t6 b3 b  @
  31.   gpio_init_struct.Pin = GPIO_PIN_2;4 ]; Q" B6 X0 U( C. O
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    ; O. D1 h) y6 }# g) D
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
      o! ?3 |! P( s- g2 x

  34. % Z0 o  f+ c4 B  j+ R
  35.   gpio_init_struct.Pin = GPIO_PIN_3;( r  N- {( P1 I4 W7 i  X# X2 P
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    ) h  O0 m$ N* P. y4 p+ I; d( E( d" r" l
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    , }2 a, ?' w4 L! i6 i5 d: `
  38. & n  R. ?/ d$ E  k
  39.   g_spi_handle.Instance = SPI2;; |7 b9 Z  C  I. N, S- \" d6 q1 c" J
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;
    , A( n/ H: {% n$ _% ?& y
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;" I9 P3 w5 I# L! f, A
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    ' x% u9 p0 D- K: C& i
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    0 \7 j- @$ i  K2 `
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;% p% s; M1 F8 D" }/ W3 g
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  5 s' ?: ~/ j6 V3 v% m. I; o; A
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    $ S( u7 L9 @8 }* G. K+ @  S
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;# P. f# y, f: {) e; L
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;& ~. L$ i. o1 q& g$ E7 b
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;+ O0 [  S9 D, b% c* N- W1 ]
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    ; X# `( a' e- O9 B6 @% |( e. a
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;5 w. m2 ^: h$ V
  52.   g_spi_handle.Init.CRCPolynomial = 7;
    0 r& w9 s! m* x+ n4 Z* @5 o5 q
  53.   HAL_SPI_Init(&g_spi_handle);+ z7 A. v  i- e6 i( t
  54. . k8 {. p( c) d& L7 M
  55.   __HAL_SPI_ENABLE(&g_spi_handle);
    6 M* ]. N% B$ F* A# x! X
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);  O1 z+ r1 c3 Z. g7 C
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。
6 [5 x; l. x9 R- l0 H' f
% U% F4 X, d3 M1 CNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:
* {0 ?; C7 }( ~; E1 a  p
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM7 N' Y" d* w' Q6 Z8 S
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13* v- C* H8 |. m5 _' \0 I4 T
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();1 o- ~* |) m* A7 z+ q  K7 }
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);4 I* p6 z( h+ o
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
    5 ]- ]# ?7 K% u+ t4 O
  6. ! V, ~+ D' ]; N/ u8 {
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM5 D  J8 _. I' y& f! k+ j5 h9 u
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    8 h5 D( c& i1 y1 |& J0 [
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    / {/ q5 n  t- _/ W
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);9 {& F$ A6 c  e5 i! r9 I3 a' l, d
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
    6 q" s- |) K6 j7 G/ W( k) k: Y

  12. ' S+ _/ }% c* o6 G
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF9 ]5 n4 U1 H3 a0 |; W
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2
    # y5 J6 j& W: ?+ e/ C
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();
    6 }! z+ k2 s# W6 p: d3 e0 U# [+ B( n- B
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)! M& V( r" w% o" n1 m3 e
  17. ' q2 L! I, I1 L1 n
  18. void NRF24L01_GPIO_Init(void)
    9 k& Z7 P* p, ?- r+ g+ g
  19. {" c3 D8 w4 C: Z6 _, w" e
  20.     GPIO_InitTypeDef gpio_init_struct;
    7 O  L: T1 |2 g6 w
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;
    & j" s9 F* B, ^6 o6 i9 M- r
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;0 F$ f- G5 s  \; r  b5 e* ~
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
    6 z" z0 e' t  }& j7 R
  24.    
    4 G* ]5 n2 i$ ^) j7 d
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    * R+ E' r* v  Z4 @
  26.     gpio_init_struct.Pull = GPIO_PULLUP;
    # ]0 u" S5 G3 p8 h% p5 a
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;( l$ T3 C* P# r. o* Z
  28.     & R; J) {" w* s$ g
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    6 o4 p9 w- T; a7 N2 W1 R, S
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
    # v4 b, f, `2 J: ]
  31.    
    9 K. u8 {$ }: o% I
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    4 h4 V0 D7 F* e( z
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    / f3 Y. Q& d6 s4 J# M3 ~
  34.    
    ; A$ G4 x( M4 Y+ p) u/ v# R) ~
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    6 j  k$ f) B% V; O
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;
    ; f4 ^- v/ L4 m: o4 K; h" A
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);
    . Z6 ?! x4 E+ p4 _3 a3 I: [
  38.     & c6 t* k6 I: H7 p4 L$ S/ d
  39.     NRF24L01_CE_LOW;& N" P+ S3 d* f" e' D- q
  40.     NRF24L01_CS_HIGH;/ a* O( {$ o' _# ~+ |$ M1 F
  41. }
复制代码
3 c' s/ n# e. i6 Y# \- {3 q! S
- Y* B2 j& R* m" L: {- P

. T* ]! f8 b3 g  C8 U( I# o. qNRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
* W8 P( t7 |) e9 V$ t
  1. uint8_t NRF24L01_Check(void)
    - T6 a/ J) }9 K4 x! Z- [6 C) u
  2. {
    0 p# J' K6 C2 w9 V" w4 j" a
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};' I- J- e# |) S3 t
  4.     uint8_t i;; R! i5 x( R# v& g" n" h! P" V
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);2 D% a1 N6 d3 |0 f# r) y$ w
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);/ G( q$ z3 ^5 c0 P
  7.     for(i = 0 ; i < 5 ; i++)+ A4 D0 f( U- B5 d9 q" y. ^
  8.         if(buf[i] != 0XA5)& i- R1 P7 K# s8 ?% F
  9.             break;                                    
    0 P# M1 d: s2 J+ a
  10.     if(i!=5)
    " Y% s( s* Z: b! K6 S" C
  11.         return 1;3 {9 K8 s  _* S) H" F; M7 L; p
  12.     return 0;
    ( S" ]( O9 o" g+ E3 M+ ?
  13. }
复制代码
+ U: b& W' z* o7 \' j/ R
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
  P3 Q1 t$ M$ o9 H8 [) i1 w9 a% B# l
  1. void NRF24L01_RX_Mode(void)! K3 S, r4 K5 B( {, C
  2. {
    9 h  I" }  M) r; ]
  3.     NRF24L01_CE_LOW;) R" g2 j2 X7 [1 B( E
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);# X" {6 l' W, P6 u
  5.    
    # Y" G. Y% u" E! A5 O! m( u& G9 x
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    & Q; ]- b/ T) h% V
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    4 f$ W, \* d$ m+ k+ U
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    . }2 X0 q8 \4 f4 K6 a# {
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);& ~: ^* ~) _4 e0 d4 t, _7 ^
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);* L0 d4 w7 s$ J# Z
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    * T* N& L  a3 ~/ X: X* @
  12.     NRF24L01_CE_HIGH;7 }3 Z; X) }) u
  13. }3 {. X* B7 d, c* r2 h: a" l, L

  14. 7 ~0 J9 o# u$ t$ @! Q
  15. void NRF24L01_TX_Mode(void)7 }/ ]/ Y+ l6 b. G8 q
  16. {                                                         , ?. ]& |/ O/ R! F# O
  17.     NRF24L01_CE_LOW;
    2 r# ?1 I/ t6 ]
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
    $ w3 e/ G. G+ d6 E9 _' V# g; W
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    . ]3 y; C% q' F2 I# |( c3 @9 s
  20. 3 h. b( D' l: b  ?
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
      V0 U! U% T7 r2 ]& M2 T
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    * A$ X4 S" A/ R. k
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);$ j7 L. k$ o1 f* ^" ~
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);2 {2 [2 J5 d' v8 K0 c5 Z" K0 o1 i
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    . \) I+ ]; r% v! B
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
    # U! S* e  z9 |% N' _
  27.     NRF24L01_CE_HIGH;
    * K. K# M8 _7 D, ^# V. Y
  28. }) Q9 s! T  X. ^' w( `8 U

  29. 4 ~( X, v5 d& y8 s( L' y+ q9 y
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)5 D$ ]5 ]) t: W. V, Q  U
  31. {
    / C/ h3 e$ [! [
  32.     uint8_t sta;                                           , `" P: `3 y9 v8 m# R
  33.     sta = NRF24L01_Read_Reg(STATUS);+ G% `' }* s, j. t/ L2 E

  34. ' i" h* I7 ?1 v* W: @
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    ! \2 {9 h' d" k6 X4 F9 u9 g
  36.     5 C: O2 p# W6 H( {, a( E; L0 I7 g
  37.     if(sta & RX_OK)
    . e* ~3 q4 T/ j' _; f' f7 b, w
  38.     {
    - y9 N5 i$ ^+ B
  39.         printf("sta = 0x%x RX_OK.\n" , sta);, o7 Z$ T, z) F! a" O
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);
    8 Q/ H; L5 u/ r
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);0 b/ {- }2 F" a& k+ [8 Q. x! {
  42.         return 0;& \7 t" A: |3 t0 j5 t: E
  43.     }      
    ! v  `7 a8 m0 ?# e- O9 o
  44.     return 1;. k. w& k8 N$ Z: `$ G
  45. }    % \+ I- Q7 |4 E0 f

  46. ' d! x' b; V7 n  S, @
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
    0 U; t# }. u! @' S$ P; G7 A
  48. {4 `+ J, U! i9 }! v9 Q
  49.     uint8_t sta;
    . S) A! ~" W$ z
  50.     NRF24L01_CE_LOW;+ Z$ ]9 v* w3 u& ~
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    & N. ]" X! ~+ y( s3 h$ d8 r
  52.      NRF24L01_CE_HIGH;5 F  q+ J  J9 q, X
  53.     while(NRF24L01_IRQ_READ() != 0);
    - Z2 h* S! \9 g' ~. r7 g; W
  54.     sta = NRF24L01_Read_Reg(STATUS);
    9 J3 L6 b- a( q& _8 G% L
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);/ {! J; c- J# _# U% ]
  56.     if(sta&MAX_TX)  D/ Y" A; Y$ D; D3 t7 }5 _+ G
  57.     {
    * [6 P& `% @, x* D8 y
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);
      B6 N9 F" ~6 B' P3 }' R
  59.         return MAX_TX;
    1 }- N) G3 X+ y
  60.     }' k$ ~. y4 w, c
  61.     if(sta&TX_OK)
    ) o& j- G0 ]2 l! I% ^: F9 i
  62.     {
    & M1 ~$ P- F: A
  63.         return TX_OK;
    5 a7 L4 [2 R* ]7 t  |; r+ W* ?
  64.     }2 r0 ?; ]8 x3 v" I1 }
  65.     return 0xff;
    1 @. k& Y  p7 F7 f1 K+ x/ x
  66. }
复制代码
# \$ V" o( _! K9 i' k
我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
3 K  C- e% a3 M1 V- i
52.jpg 53.JPG
* i1 ^9 Q  ~* E& u4 s  v% {: v! [* Y/ H
看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
( I4 [. x/ i  Z0 E9 Y' C2 U
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg ) A- _6 K$ ?$ `3 [) ^  _
然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:( b1 w6 s% h4 q! ?+ X
55.JPG ) S7 ]% W% e- Q
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)的合照
4 ]+ \" i& M. K3 o IMG_20250524_125758.jpg
% ~, Q( ?, w: s6 @! L5 d+ T! Q! C. Z- ~/ S) \& E+ W" c6 A

所属标签

相似技术帖

官网相关资源

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