请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。
: V# A+ h4 k* [2 h& Q4 { 51.JPG
( }+ V# c( M2 n0 G9 h7 a首先是初始化SPI接口,这个非常简单:+ R) y5 n: ~% I4 y4 V
  1. SPI_HandleTypeDef g_spi_handle;
    0 G/ p" q. X% Z* q- A, t) s" V

  2. 1 V+ |4 g  Z9 c" @4 M
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)+ @1 F$ b& j) u7 [% Y# d2 L
  4. {
    : p3 f/ Y9 R1 j8 a$ r  b4 x  F
  5.   uint8_t rxdata;
    . V8 {+ H7 z4 U; d) f" V
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);3 Z+ z: W) z: f, y
  7.   return rxdata;
    & b' j/ t( ~, G) o7 d' X* _1 `
  8. }
    8 M% N' B  q' M( ?  n

  9. # G3 a! p) `* a% c$ X
  10. void SPI2_PD3_PC2_PC3_Init(void)0 b  ]( ?) ~) _: J! X2 g; U
  11. {
    " ~% e! O0 K( e* Z3 Y
  12.   GPIO_InitTypeDef gpio_init_struct = {0};+ |4 ~6 e/ \9 K  k) L8 B  M
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
    2 O8 R# G: T* r1 z# {8 ^2 y

  14. # _9 O* U3 F1 f! N* X. ~/ \
  15.   __HAL_RCC_SPI2_CLK_ENABLE();: H7 o) b, S" z% U1 r+ U
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();' j- I  S: H- t' N1 t4 M  G
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();1 L  @! y% o& r+ b/ i

  18. * S5 o( o6 S. z" a; \
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;+ S+ [3 W5 Q. `  W% L! B% D  K
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
    8 F+ @/ g- I1 f9 ^- F8 ^0 |3 h
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    , |! p; Z7 i; [4 J) Z0 Q" y
  22. 2 N8 X4 |, A3 R- q3 O
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    % D6 ]( c& c7 _
  24.   gpio_init_struct.Pull = GPIO_PULLUP;$ R+ I: d) ?7 f7 D! C7 ~
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    " ~: E9 T$ n8 b& R; V4 |" i4 W  B
  26. 5 Y* C; ~- c% M
  27.   gpio_init_struct.Pin = GPIO_PIN_3;" H3 k( ?# Y9 i1 M: O5 Z1 J6 _
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;+ k! G8 s# Y3 z! J- w
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);5 e: u. t$ s' p  L" `1 k" Q
  30. . ?: d. @: K: U8 v1 t9 [
  31.   gpio_init_struct.Pin = GPIO_PIN_2;
    5 i+ p: g3 X0 J0 `8 A
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    : q$ t8 }) M9 B: K; _8 R
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    " d; ]  O& O. T, F9 ^

  34. + a, j* @* P0 ~9 N
  35.   gpio_init_struct.Pin = GPIO_PIN_3;
    ! R4 R+ i  L* f% y
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
      o- W2 f. u; u4 t1 U
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    # U5 ?  \& u3 C6 w

  38. * o4 T# q/ Q0 \( m; `0 c
  39.   g_spi_handle.Instance = SPI2;
    & r- R$ {8 ]% [9 J/ G
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;1 {/ E" b: b. u5 G4 R7 h2 I8 E
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;) S  W7 ^; ^) x; ]# s0 t: Y( @
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;7 |* W( V6 `* V4 m0 x- C
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;# u- j0 ~. h& V
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;7 X& N1 ?; j, L' f
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  
    ( {% D) x' @# c# N1 y
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    + e; L1 z2 f6 q5 f) f  d& _
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;5 Q* @9 S- O4 m+ F0 L: z
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;& a" L2 l( I6 m/ n" N$ q$ p
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;$ [6 o6 F5 p/ @  r$ I+ C
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    7 X- H; L+ `- a$ H
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;: e$ \0 J! Y( T' X( M( k
  52.   g_spi_handle.Init.CRCPolynomial = 7;4 l; t) i. x/ b9 D, y
  53.   HAL_SPI_Init(&g_spi_handle);
    + y! _4 R- |' F+ ?7 Y+ {

  54. ; j4 }- \3 R1 @9 R; h; d: W' a
  55.   __HAL_SPI_ENABLE(&g_spi_handle);. l( e& p$ a1 h+ @% [$ {
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
    6 s0 T7 g# P. u& g, B
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。6 t% u, _$ {$ r1 f, B8 O3 G9 e' S

* M0 J) Y& m( T1 K9 t" ~- L2 Z: m7 jNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:  e! u/ U  n* n
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM: U5 x! |) y  O/ S* A  L( L$ y
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_13
    9 s- o& k. L* @5 P) m, W
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    + r4 s# x  u8 H* K
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);! ^/ Q- ]  ]! z( W+ H4 \
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);  h6 ]* |, t) r+ @. y) L% n* x8 ]

  6. 3 h+ d$ k) T( z: d$ S) m2 [
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM) _3 P6 E, S# N( X
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    # K6 \* O8 T& D/ Y
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();( g$ K/ l- }: t
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
    + K5 x/ E4 S; W( l1 `' D
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);8 t* t7 s! C- y  j: ?
  12. ; p# Y! O7 n4 {8 q0 N
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF
    6 b: d- c% o/ X& _
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2
    6 i- d0 d: D1 B# T" O
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();
    2 G6 L( V7 ?1 \7 E( y3 x: {
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)+ h& N( j8 _: k! e5 t

  17. : G  d& N5 A4 t( Z
  18. void NRF24L01_GPIO_Init(void)
    ; P- T2 ?4 s/ S& m. x' }9 h9 `# E
  19. {5 P3 m0 V# B( h8 e  V1 {
  20.     GPIO_InitTypeDef gpio_init_struct;& ], M6 m! X  \, J; v8 J) }
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;
    2 @' i# m) C: j+ m) c
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;
    . M; B1 I6 o7 K. P
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
    ) |. R: J. U3 X+ o
  24.     & m9 B& K0 f+ e3 c/ w) {- d- E
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    ) w6 p* a6 u$ f4 m0 N: ^: s
  26.     gpio_init_struct.Pull = GPIO_PULLUP;
      n. n) v* x+ c3 \, \: ?
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    8 ?& z! l8 V* O  I0 z3 N
  28.    
    7 _. O/ z  c! V1 I9 Z+ _
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;  |; L' Y' E: {+ [  C2 J& U0 B# G: [
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
    $ G6 r0 y/ H4 |- b1 n3 Q) }
  31.     ; H6 B, p$ f$ _  [: A! z/ c; C% }$ T
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    - I1 [, }) \2 ~. q7 J
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    & g1 P: i: d3 e  h
  34.    
    3 g! V% j5 ]* ]
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    , g* u5 W2 D- n2 e
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;# `3 e' S& b/ e( G: p5 g. w
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);: h$ K( D$ B+ {' Y7 M$ G  h+ `  k
  38.     ' Z# Q' ~1 B0 b  N* I8 Z5 t6 G
  39.     NRF24L01_CE_LOW;
    . t2 e: K. l! Z
  40.     NRF24L01_CS_HIGH;
    # V3 X* j+ c" {6 v' t
  41. }
复制代码
4 I; V! X4 F' U2 S

* z- k$ v) H4 y8 q5 m
/ X# n* c$ P& w" n4 {. b8 B' M& eNRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
4 N( @, w1 j) L
  1. uint8_t NRF24L01_Check(void)
    5 {, I* v; e5 L& e
  2. {
    & F8 S9 v! ^/ k! b2 A; z
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
    9 h; d8 _0 b1 h2 W" k. @
  4.     uint8_t i;
    # w) w' o+ f& `2 A" E
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
    - Y5 n2 b/ T" c! k8 T5 w9 }
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);
    3 ^; `! ~1 k$ q, N% I7 ?; Z" i
  7.     for(i = 0 ; i < 5 ; i++)2 d% u) S$ J, O( @3 b, S
  8.         if(buf[i] != 0XA5), C- n# |) G. u; ]/ o% |7 h! ]
  9.             break;                                    
    - ^8 j: \% p: N! P7 k- m% a( x/ i/ a
  10.     if(i!=5)
    ' R  N8 C- I7 O" Q: T
  11.         return 1;* |" R$ \8 h6 Q8 I# Z
  12.     return 0;
    * |7 ^7 U" j6 b& O( J
  13. }
复制代码
/ Z! }5 J! D5 u/ s  F
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
5 M8 x7 c" N% a8 f5 m- g5 k6 i' f
  1. void NRF24L01_RX_Mode(void)* B( m# L& A8 i! b
  2. {9 }6 k, W# z1 n/ |  I# I! j& F
  3.     NRF24L01_CE_LOW;* e* C/ V7 F9 V2 w5 N: w( X  I# b
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    5 r0 k" l* u1 ?5 {
  5.     1 \# u# D2 K# b$ w/ W
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  $ U: u+ ~% ?9 ?
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    ; @! c$ p2 ?4 U1 M3 q! B
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    , ~. e. x" q& o& N9 R; Y  h
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);% j  ~: x7 F# T7 J; k* p. h& t
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    + F- ?0 ]/ f# W) i2 S4 r
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);3 z7 ~4 `# K' _) X* K
  12.     NRF24L01_CE_HIGH;
    1 }! }+ o  ?# K6 W' [+ ~
  13. }
    6 |! L' F' X" P, m# G

  14. " ~( P) e, L7 m8 w$ F: @: D0 e
  15. void NRF24L01_TX_Mode(void)4 e0 Q) g# [, v6 C1 T2 C4 F
  16. {                                                         
    . L2 [4 s6 ~9 ?, K1 V" u
  17.     NRF24L01_CE_LOW;
    + E# \9 i- ?# B0 x9 }
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
    + L2 ]' C) Y  n! k' [: r  I4 B: i+ w$ U
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    0 ~" A1 B/ }5 G2 f/ r! ]
  20. $ p# z$ `  X0 x. p; \7 X
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);! I( X, w+ p# h0 ]
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);- k( f3 S( x; b3 e
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);, R8 W  U8 r) r4 |- n: \' j" f
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    5 e! \3 {+ \5 E
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);" H6 q# x) i: [, E8 f- P* O3 O
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
    & B6 H) `0 f8 P+ Q8 c  h5 e9 I* a
  27.     NRF24L01_CE_HIGH;$ G! _- ]( S8 c4 ^% z& o( A
  28. }5 C% [) \! H7 |- H( M) [
  29. - I) B, q" c- K
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
    / x) h- W/ H1 k9 N- n. Q
  31. {7 B* A, z) o, w
  32.     uint8_t sta;                                           % F# P( o$ A6 P& U* i
  33.     sta = NRF24L01_Read_Reg(STATUS);
    8 {8 l5 [7 l$ [2 V: t3 Y0 ]8 ^
  34. % C5 d- I, f1 Y: x( y* _
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);( H& L1 ^! w# r& {. n
  36.     : Y/ u7 K6 ]; |8 J
  37.     if(sta & RX_OK)
    % ?1 d4 q8 V6 O! w, I' s
  38.     {
    9 j5 Q0 y9 k; Y5 h/ t
  39.         printf("sta = 0x%x RX_OK.\n" , sta);
    : Z; N) C5 X2 K  N. I( V0 h
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);3 M# S  h1 z( N& }$ ^" Y8 a* A7 M
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);( e7 e4 p3 b( ]# T+ f0 C8 q$ p
  42.         return 0;
    3 Q5 f2 J# l  q( B
  43.     }      
    " Y. O3 o! s2 S9 H3 S! W4 v
  44.     return 1;/ _& ~+ r1 t' M4 k: J4 l4 b
  45. }   
    ' W- g9 {7 c/ i: |  [  X8 Q

  46. ; P5 w& E' f! J; Q( C$ [8 B
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)" B& f$ x, `: A
  48. {
    ! t' ]1 w% ]# Q. ]8 ^
  49.     uint8_t sta;
    * ~; A: Z) c6 t/ E1 P/ {
  50.     NRF24L01_CE_LOW;5 Q- r6 _& {) i; K
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    : x# G8 Q; E  k( r/ I- b, e
  52.      NRF24L01_CE_HIGH;
    & z+ x/ n* R' G  v$ O
  53.     while(NRF24L01_IRQ_READ() != 0);6 ], B6 [6 e$ B1 O! z
  54.     sta = NRF24L01_Read_Reg(STATUS);
    ( K5 q! q, s5 s, c
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
    , I; F4 e) Y8 j- d
  56.     if(sta&MAX_TX)
    ! L8 T6 n+ ~9 c& X# E/ T
  57.     {% w- c. A% j. E- o) \+ L7 B$ X
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);. f. q3 v5 n1 C
  59.         return MAX_TX;, j$ B5 h( s5 k6 y4 U, }& O- k
  60.     }
    - M; D2 j6 l2 v. X$ m- P
  61.     if(sta&TX_OK)- h# ]& N& `+ e! \* L2 F& J
  62.     {5 ~0 K3 @9 r* ~
  63.         return TX_OK;
    0 Q0 ~' n8 l6 V) J( E- r
  64.     }
    - N8 N% e; f# ?" h9 ~# t
  65.     return 0xff;
    : f/ \" Q; j6 S% o$ S& o6 }
  66. }
复制代码
9 h, y0 U( b* \" ?' o
我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
3 [( _7 }' t0 J: {
52.jpg 53.JPG 0 z) ^, W/ L" a$ w/ A" W4 X

/ S: V5 U) |: j; [看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
' B) [+ u! b( Y" F' L0 o  P/ V) ^4 G
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg $ n' d9 ]+ y8 }9 Z, @0 V+ F) }
然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
# X+ c* w( k, C: Q) ]3 Q 55.JPG
9 n' i# Q0 T. h7 ~
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)的合照6 ]" S- b. W( \! q- `- A
IMG_20250524_125758.jpg ; u3 L* e' e$ C  j2 S% N

; x- c- k' f; T4 B+ n( C

所属标签

相似技术帖

官网相关资源

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