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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。2 f+ D! J9 ]4 N: s; D+ [; I" b
51.JPG 1 ?1 O" q# u, \  B  i* S* @: _2 X
首先是初始化SPI接口,这个非常简单:9 j7 b$ d# a" a; V3 G
  1. SPI_HandleTypeDef g_spi_handle;; |' l9 P( }, t7 ^
  2. 3 t& c9 e7 N( U, k- U
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)) L8 [# ]/ d$ z# ^7 ?
  4. {
    - A9 c; J& Y) j5 ]. b0 N: X" N
  5.   uint8_t rxdata;' a4 r1 b, ~2 u) o( x
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);7 a% r- l3 X; @% k6 n+ s2 I) |4 E4 }
  7.   return rxdata;
    , e: m5 n2 t5 Y3 D
  8. }
    $ |0 v* k! v4 U
  9. * h4 T5 ?5 I* v  |  m0 c  \9 @
  10. void SPI2_PD3_PC2_PC3_Init(void)
    , A$ [7 i$ N7 g$ o: \* v
  11. {
    4 {' p* t. h. J, e5 ~
  12.   GPIO_InitTypeDef gpio_init_struct = {0};
    / J) L) ?4 b( {6 W, m  d4 L
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};! ]! `' r+ s* _0 M7 K, z$ M: }5 H
  14. ; k: e; v. x2 V7 D: T3 V9 q
  15.   __HAL_RCC_SPI2_CLK_ENABLE();
    / O7 _* K. V1 o: u0 [6 E
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();3 w! S/ [) R8 Q8 B
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();5 C, L; S0 Q8 \* o1 `6 U3 L

  18. $ L; _5 O  d! N) R, |  p
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;+ @) u, G( M: X& H8 P
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;2 m# W7 s  H; J+ Q( H9 K
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    . y! D, t; D4 @# @( V; X. n

  22. / m* Z  q- b' L6 U( g' W
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    % g; L7 z( u' E* Q: i
  24.   gpio_init_struct.Pull = GPIO_PULLUP;
    7 C2 s( x' j- ^. L; W
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    . ~8 l- y) I% G6 {

  26. & b+ e1 S5 Y3 H" Q- l$ I
  27.   gpio_init_struct.Pin = GPIO_PIN_3;; I: v7 O. A* q- G0 R' ]: k: `
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
      i  x! _. l% z( H" v
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);+ {$ Y' Z% ~1 {9 O- T, @/ K
  30.   O, h6 Y, w; D$ x: \  q. H$ i
  31.   gpio_init_struct.Pin = GPIO_PIN_2;
    0 t* Q8 n. L( j4 z: N7 I5 s
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    " b1 j9 \' n) X, v' k# l
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);( z' y+ Y! \! F7 T
  34. ; D+ X7 G; n- X# m  o- A
  35.   gpio_init_struct.Pin = GPIO_PIN_3;$ @- X- N3 s1 N0 \
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;2 {1 r! E0 ~5 b
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);" w& {2 u% l/ e. z
  38. 6 A5 a" A  g3 ?- q; d# U1 }
  39.   g_spi_handle.Instance = SPI2;
    8 i7 S8 c, ~+ F, |$ L: J
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;
    ' l5 @5 Q# y2 {) t% t
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
    0 n8 T, K& v1 h) J- R6 @5 v
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    ( l3 z2 X: w4 d3 b' g- o
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    - S# T+ W4 {1 V# @$ W
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;: `# x  c& I% f: \) A& I9 }) Y; l
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
    ! u3 m: t9 ]' _* V  G
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;( m# `. d! S/ g$ e9 W+ }3 @
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    7 \8 z* Q" @5 n& f
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;% [& M8 v) V1 w, p$ h* g6 W
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
    6 ]8 [# m8 r+ T- C. H$ n& y
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    6 `/ s/ |& _* M! j7 F
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;7 A. {4 I4 C$ j# l  }9 J* F+ b, C
  52.   g_spi_handle.Init.CRCPolynomial = 7;, M/ @% q2 ?6 g; c3 |% P% L* H
  53.   HAL_SPI_Init(&g_spi_handle);
    8 v- B% d( l6 h$ B7 `/ B/ d2 g% r
  54. 4 U. y. e' L$ Y- Z
  55.   __HAL_SPI_ENABLE(&g_spi_handle);- h! `5 P. w" B1 [# G
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);8 u/ ?% r) M  h' g, d/ b
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。6 C; N& ~4 \! z$ V  e

9 h8 K, D$ ~% r- d% b" n3 pNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:( `- S: D0 w- b  r
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM% v; p- W) G9 U1 M! X3 C
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    7 o5 e2 K8 l- l2 j& H
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();/ c( h! g/ N% s1 n
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);
    % _( i6 r  o% _$ |
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);) @1 y% f& _/ j

  6. $ o: p5 a( o: w
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM
    5 P. X4 C2 O$ [1 l; Z2 N% k
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    6 R# D3 B, B" v% t$ _
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    : H+ a- V/ M, j, K& @2 z
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);5 m4 N/ ?7 V* B* |, F
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
    * n9 u- R, ?2 w' R9 \
  12. ( K4 H! E$ N7 Q4 z0 W
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF  g) k  b, z" \9 g7 G3 e
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2
    8 T  U: v- s; X8 Z' a
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();3 G! r" p7 M# o; z" @$ p; H9 t
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
    - z7 k/ M  c1 h. T; d/ v

  17. * }( b$ s* h, q  _
  18. void NRF24L01_GPIO_Init(void)( V  m( R- [* w6 s" o
  19. {
    " C. J% h' w: ^) y+ |- y" r3 j
  20.     GPIO_InitTypeDef gpio_init_struct;3 {; I. c0 i5 T0 u2 M+ r5 S4 F
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;
    * ]; G3 w" W9 G
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;# W' \" }! N, U/ I5 l* v
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
    9 u% [8 S/ F1 H9 ^  _
  24.    
    0 K4 F: c1 X) g1 K
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    4 K  N) q, h- K1 C& k. N+ K
  26.     gpio_init_struct.Pull = GPIO_PULLUP;4 z& q7 q% e8 D9 ]' A8 M
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;) M% ]0 U* @/ U
  28.    
    , x8 q! @4 r8 U' z
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    ( E, b+ _) P( M0 O; t+ w! z$ H
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
    - Y9 m/ j8 z$ J0 R7 k
  31.    
    6 @' K4 E- `: }# s; s7 C
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    0 j6 V/ X* P/ B2 |: m0 ~  n
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    . C% M" g- O: {0 ?( D8 ]8 \. x
  34.    
    " R" p& a. n* x. i
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    0 z4 l0 I, C8 o5 F) Y( k9 a
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;
    8 H: ]& v; K& h0 |/ Q6 F
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);$ E9 V1 E% N4 h5 \5 G) k
  38.     % `6 w7 T  ~  `* W: K
  39.     NRF24L01_CE_LOW;0 @/ g$ _8 L- q4 ^$ _8 a
  40.     NRF24L01_CS_HIGH;" n# V) F- j4 y; \2 ?
  41. }
复制代码

$ c# |" Q$ T* u& H/ e& S
$ n: ]& P5 d* J9 ~% K
4 G" q+ E' g3 ^' [# VNRF24L01有五个寄存器是可以用来检测器件是否正常工作的:( n, V# S. S7 a3 y' F) u; |
  1. uint8_t NRF24L01_Check(void)
    # ?; w' j. W/ s+ u7 F- H/ g
  2. {' T# S. J$ |* L# y6 `5 r
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
    & M, w- z: e; Q, v
  4.     uint8_t i;  x/ _" m) v) w
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
    / P3 F  l  ~: c% X7 t4 s
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);% |  E- n1 ?; j; V; [
  7.     for(i = 0 ; i < 5 ; i++)3 W" P$ v2 W* A5 x% ~" L: ?. _0 C
  8.         if(buf[i] != 0XA5)! i( \! a8 S) q. I1 Q
  9.             break;                                    
    ; c9 q" ^  P6 c3 U! s
  10.     if(i!=5)
    / }4 m! N' p5 i. X9 P; O9 P' N
  11.         return 1;
    + J) p& l8 C. ]% |
  12.     return 0;
    . y" ?" ^2 W0 b  @0 w
  13. }
复制代码
9 H0 l) W, d5 a) D3 j1 M. P4 @
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
' Y" C% t/ d& S1 K. [9 G2 e0 {
  1. void NRF24L01_RX_Mode(void)' h( R0 ]! R8 }9 U- W
  2. {
    ( [, H$ g" E& M* B, h2 i- i0 B" u
  3.     NRF24L01_CE_LOW;8 ?, N% u, g' h2 x& Q3 ^
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
      z# r8 N: E% K/ e* s7 q, D- q8 }+ D0 ~' d
  5.     ! j1 K: C6 t$ K- c0 k0 v3 c6 F
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    - M) I+ B. ~- m4 }* ~
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);- J; E& {& Q9 B6 K3 B
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    $ q4 @1 f0 Z4 K4 e4 \
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    * H6 `3 u/ T' v/ Q' u/ I9 r
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    $ O- [7 g; {1 J" o- y9 C# L
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);* h1 p2 ~$ Z2 S9 ^% @% y# N8 \1 Y
  12.     NRF24L01_CE_HIGH;
    8 S+ N* U, P- Y3 i2 c
  13. }
    2 X0 U  `- L; I2 S# E  M/ B4 T" \# t
  14. : m& _  n: b0 L
  15. void NRF24L01_TX_Mode(void); r; O7 \/ J3 n* c  ?7 G
  16. {                                                         
    2 y! r0 Y: `8 O% c. K
  17.     NRF24L01_CE_LOW;
    # l  r# S7 i* }4 c( \! C+ H
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);+ u+ @7 |5 ?7 ~8 x: }4 T. f& b1 u
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    2 T& I1 m! X$ Z4 A8 D9 M7 `- P
  20. 8 i; p! k- x3 l  N" D6 w7 c
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);- `& v7 {7 F8 d8 P3 Z3 \% \( @& C
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);, l1 `8 S$ R# q* |# M% o
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
      T# l' t+ n$ }. R+ y
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    6 V- m6 p* \6 j. @4 i
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    3 v/ x+ w2 v) j0 V) ^, b5 L8 J
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
    % W- Z8 L+ ]& r1 ~& G' `/ g
  27.     NRF24L01_CE_HIGH;
    . }% c5 d4 V6 I2 t9 V/ M
  28. }
    * y" d2 B3 T& S% C) `

  29. ) [" u2 A) U/ s# B$ R6 |
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)1 k* A9 d8 g& Z/ j' B  H, N+ C
  31. {) g: X$ C' [% F, r6 b
  32.     uint8_t sta;                                           ; n/ z" |- Q) C3 h; [: I
  33.     sta = NRF24L01_Read_Reg(STATUS);
    ) o( }# d  e4 O( N/ }( C( a7 }

  34. 7 f, Y! e9 n! Q2 |
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    $ @. L2 w0 t- \' m" A/ |5 R
  36.     $ \' C+ B* o9 V& m& G
  37.     if(sta & RX_OK)
    0 [. n  U" ]' X7 v1 T3 X
  38.     {
    ' q8 U; c$ p  B3 S7 O% P- w3 w
  39.         printf("sta = 0x%x RX_OK.\n" , sta);& m+ }# k7 u: d1 z& ~* }/ u5 V
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);
    : N. w7 e- T" p& o# h6 d8 S# m, T
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);
      `9 H5 G% c1 i( G9 s, W$ Q
  42.         return 0;: D6 C/ ^! u& ~; o
  43.     }       1 Q* [8 L6 l. a  S5 j$ |2 ^1 O
  44.     return 1;9 K4 ]7 S5 b9 K8 U
  45. }    $ {. ~% i7 N' [. r. n
  46. ) i, w7 K) u; m  z1 y
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
    # _- G; ^7 d7 c- n
  48. {
    ' O& X. Q  [! q6 c& ^0 e
  49.     uint8_t sta;4 y, [6 f: ?3 N7 H. _/ E& a4 j, {
  50.     NRF24L01_CE_LOW;- e( e9 E# L, t4 r* a% c+ [/ C
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);  d( D! _2 j4 W' V) Q) _
  52.      NRF24L01_CE_HIGH;
    " z% {/ Z( v. _
  53.     while(NRF24L01_IRQ_READ() != 0);2 h2 P& z. p0 B  z
  54.     sta = NRF24L01_Read_Reg(STATUS);( H: j% e; ?2 Q' X! |: T
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);! b& x% }2 U" u6 o
  56.     if(sta&MAX_TX)
    " }& ~! g+ n; `+ q
  57.     {1 u9 _' p) _, B" U* P( N* {- p5 E
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);+ S' i+ N0 d% n( o" A1 ]5 M
  59.         return MAX_TX;
    3 J1 q$ \$ o( Z
  60.     }
    7 L( M- Z6 c8 @; ]: a8 p1 k
  61.     if(sta&TX_OK)
    - f9 }  [; }, W: q0 f, ]
  62.     {
    & n  r+ ^% l7 d7 Y2 J1 ]
  63.         return TX_OK;
    . m! ?* r" ?" \* }
  64.     }
    6 Z0 u+ f$ ~" w1 `- G
  65.     return 0xff;, _3 E+ i" R3 E4 ~( ]- f9 \
  66. }
复制代码

7 P* Z4 a8 F. g  X. _% _* y  q我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:8 B" F1 }8 O: p& `
52.jpg 53.JPG
$ f7 |4 v1 Y7 g3 ?6 `1 g* q! A* V. o. c! H) Z4 X
看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:$ w! u8 h, \- A
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg
5 T) s( g( F6 ]. v: ?1 M3 u然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
1 w% I. D, l5 R1 Y0 s$ }* Y 55.JPG
0 Z9 G  n6 S" o# ?! B
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)的合照
# X; q5 {" R1 l: X IMG_20250524_125758.jpg
6 V3 c+ i6 Q+ Y7 `- y4 c- r$ W- l8 p3 s+ i

所属标签

相似技术帖

官网相关资源

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