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

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

[复制链接]
donatello1996 发布时间:2025-5-25 23:45
       正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。) q4 ~6 d1 a8 v* m9 A
51.JPG , I2 Z/ i9 Z8 y# v& j
首先是初始化SPI接口,这个非常简单:7 |) X, o- i/ V( g( @, s8 {$ s& u
  1. SPI_HandleTypeDef g_spi_handle;
    / j- Q2 Z5 t# L7 t
  2. ; o' z5 T: E1 \9 W9 L' ~, K, H
  3. uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)
    % ?  }( B  M" J
  4. {
    : i& I, y* Q1 L. v' z8 S+ J; x
  5.   uint8_t rxdata;
    4 J7 u3 b# z5 d. e, y& G
  6.   HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
    - s( o* L7 t3 s$ J! x
  7.   return rxdata;
    3 v( T% h% @. g
  8. }
    ' S  Z% v9 p) n1 u! f

  9. ' H" x( ~) T4 d8 a0 {3 x; H
  10. void SPI2_PD3_PC2_PC3_Init(void), X; k' A8 f/ s3 o) u0 ~
  11. {
    & U% s% M! N7 Q7 H
  12.   GPIO_InitTypeDef gpio_init_struct = {0};  S! T1 x+ s9 u3 D
  13.   RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
    ( q( x, G; }$ w

  14. . ]6 ?$ r, d1 {, i7 N
  15.   __HAL_RCC_SPI2_CLK_ENABLE();
    $ b4 r2 u" x3 i" A8 P5 h
  16.   __HAL_RCC_GPIOC_CLK_ENABLE();$ ~* I$ v' y' \& r$ o; D% h3 i7 [
  17.   __HAL_RCC_GPIOD_CLK_ENABLE();6 s$ Z( g3 H% T3 w" m7 M
  18. & ^- H$ q" W  v, _- f
  19.   rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;& _+ Q! N( N0 y0 w- a* i9 P) W
  20.   rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;$ }% o1 G. s( P; U) a# m. k; L
  21.   HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
    6 R4 w7 X2 `! ?/ ~
  22. # j1 y: Z3 t  \, X( {# u
  23.   gpio_init_struct.Mode = GPIO_MODE_AF_PP;$ h! n" a! r( h) @
  24.   gpio_init_struct.Pull = GPIO_PULLUP;
    ; w, L, ^7 w$ r( l
  25.   gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    6 S, R5 S5 e7 a; c0 d9 X1 q

  26. ( e, r  c; u) r( ~8 q% l8 k+ [9 p
  27.   gpio_init_struct.Pin = GPIO_PIN_3;
    3 L* Z$ l9 C; f% S. f+ t
  28.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;- f- c" l4 d2 \7 L! p, r' [% p
  29.   HAL_GPIO_Init(GPIOD , &gpio_init_struct);8 {, D0 ]3 U: c' k
  30. / U+ g# L7 G0 I7 x8 t5 B
  31.   gpio_init_struct.Pin = GPIO_PIN_2;
    ! r. q' I5 }* c5 z& L. X. u, f3 N
  32.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;
    5 F$ u' m# r3 u, N' w0 U
  33.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);  Y# v. r% u1 S

  34. 4 C8 i/ L& ]) _$ T/ w
  35.   gpio_init_struct.Pin = GPIO_PIN_3;( _+ p& A( w" c$ n; O
  36.   gpio_init_struct.Alternate = GPIO_AF5_SPI2;% s/ r9 ^2 X* A8 g
  37.   HAL_GPIO_Init(GPIOC , &gpio_init_struct);
    % v7 p( {% Q( O$ O( \/ n$ X1 t5 \! z! `
  38. ; e* I/ Z: v; ?5 c3 w( ~
  39.   g_spi_handle.Instance = SPI2;
    % `% T7 V2 v( z& A
  40.   g_spi_handle.Init.Mode = SPI_MODE_MASTER;+ w  Y0 W( ^0 C9 Z
  41.   g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
    # T% J+ ^+ q( e7 X  H( W; r/ m
  42.   g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    2 o& H$ D" i5 X: y
  43.   g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
    - }) \- I0 r2 t; C
  44.   g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;. h' }, v! f; ]' x' R5 R
  45.   g_spi_handle.Init.NSS = SPI_NSS_SOFT;  0 _* R! b3 E# o# }  o2 `+ B- ~
  46.   g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    . ~* W% t0 [$ t; i5 B$ g
  47.   g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;2 o5 M& e; |3 H. i9 J  {9 S
  48.   g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
      n, S; ~) w& d: W) A8 _( u4 |' n% U
  49.   g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
    . p$ c6 U9 e5 z. P
  50.   g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    + h# ^/ H+ ~) m+ k9 P
  51.   g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;' W% ]) S- X: x
  52.   g_spi_handle.Init.CRCPolynomial = 7;
    3 `* t# C4 O3 P/ ]8 F5 S1 I' h) Q
  53.   HAL_SPI_Init(&g_spi_handle);
    9 P; C, v2 B9 G; m5 q. I) m

  54. ( o" f/ F) g* I# f* b
  55.   __HAL_SPI_ENABLE(&g_spi_handle);. s/ H2 @' b: e
  56.   SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
    9 V: D# ]! _1 k' @' @! M  ~
  57. }
复制代码
这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。& G! O% w) H! Y" j

$ X* K: u7 V) o: S; VNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:
- Q( Q7 m. [- O  @4 W& k" ]
  1. #define NRF24L01_CS_GPIO_PORT                              GPIOM  M: F  `  S. G7 b- C
  2. #define NRF24L01_CS_GPIO_PIN                            GPIO_PIN_134 Y7 v- J* @9 ^2 j6 g' ?
  3. #define NRF24L01_CS_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    - K" m& s0 y; D$ d  l1 t8 x/ l
  4. #define NRF24L01_CS_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);; V* U: o# V% V' [; W
  5. #define NRF24L01_CS_LOW                             HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
    8 ^# R% A* v# K
  6. + N+ _- K5 Z1 C; e# ]
  7. #define NRF24L01_CE_GPIO_PORT                                 GPIOM
    8 C( G$ Z# r' \; T0 c2 N; E
  8. #define NRF24L01_CE_GPIO_PIN                                  GPIO_PIN_14
    & W- i5 z7 F: E. E! Q& ~9 {
  9. #define NRF24L01_CE_GPIO_CLK_ENABLE                            __HAL_RCC_GPIOM_CLK_ENABLE();
    ' b4 t1 b! C* M' l
  10. #define NRF24L01_CE_HIGH                                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
    # ~) |' B6 m2 q+ X" r0 I" q1 @
  11. #define NRF24L01_CE_LOW                                HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);% d. d3 z- f& Z+ t6 J

  12. % l8 `* }) B7 I
  13. #define NRF24L01_IRQ_GPIO_PORT                                 GPIOF
    : k" o. s; a/ b) j
  14. #define NRF24L01_IRQ_GPIO_PIN                                  GPIO_PIN_2) p/ c! {! @+ }4 K7 t% M7 e
  15. #define NRF24L01_IRQ_GPIO_CLK_ENABLE                        __HAL_RCC_GPIOF_CLK_ENABLE();. L$ X5 g# J) r" k
  16. #define NRF24L01_IRQ_READ()                                            HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
    : m" @+ t7 h$ T1 E1 D0 H

  17. 5 L0 e$ b: F5 ?3 ~1 ?1 Q
  18. void NRF24L01_GPIO_Init(void)
    - ^9 f8 q9 G2 {! q7 K) x
  19. {! S9 k2 s1 M: C* ?  e8 k+ h1 z8 U- |% ~3 h
  20.     GPIO_InitTypeDef gpio_init_struct;
    2 M; v0 E1 \: Y* D; c
  21.     NRF24L01_CS_GPIO_CLK_ENABLE;2 u) a7 {7 g9 L" X
  22.     NRF24L01_CE_GPIO_CLK_ENABLE;( ^6 r2 ^+ x5 r# d2 J. {
  23.     NRF24L01_IRQ_GPIO_CLK_ENABLE;
    6 U1 p! _, m: @0 ^, g( v
  24.     ( u4 u1 G* q! F! s/ `3 |
  25.     gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;3 C3 ]1 b( k0 H7 k6 I
  26.     gpio_init_struct.Pull = GPIO_PULLUP;9 j6 e1 h! r$ E, x, t
  27.     gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;' X" D% ]" ~! K* W  R
  28.    
    - H- M) P, O8 x+ c
  29.     gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
    + U6 ]' x& a0 F0 I& S9 ~1 N
  30.     HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);, Q5 M0 ~5 t5 W3 R$ i, ^
  31.    
    ) o# w- y( L2 ^, i7 c
  32.     gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
    1 u- t+ h/ s, W' M) x
  33.     HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
    0 x2 k# \2 `* R: k5 g0 x
  34.     6 V' c+ A( N; {! H: t4 K9 X1 l
  35.     gpio_init_struct.Mode = GPIO_MODE_INPUT;
    ; R: K* k8 I* [
  36.     gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;8 U9 ]; C+ a3 k) d) E1 i$ A3 o
  37.     HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);
    ( W2 y, r/ {3 P+ j) Z, ]
  38.     6 A. b' K2 \+ z" H! P/ T
  39.     NRF24L01_CE_LOW;
    8 c! H9 ~* C8 P
  40.     NRF24L01_CS_HIGH;. Z/ p3 {& h2 m7 x+ I% m' N# Y9 ~
  41. }
复制代码
6 e" p. \: G6 T0 p' R7 A
% W' v% q; |' X4 F( G# E
6 k* A- J) P- u
NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
: b6 b4 `4 [, q, ]" U0 E
  1. uint8_t NRF24L01_Check(void)
    ( B( [3 v$ q# X' \" X7 }
  2. {) k/ y' R/ x4 Q, b$ I0 m6 Y9 v
  3.     uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
    9 {3 e+ v4 ]6 L
  4.     uint8_t i;1 r/ O  e6 m4 t! T
  5.     NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
    ) _8 n5 {6 Q0 ^, y8 p' ~
  6.     NRF24L01_Read_Buf(TX_ADDR , buf , 5);, a% ?& O( I* }% x$ Z$ x$ W
  7.     for(i = 0 ; i < 5 ; i++)3 `. b4 J: Z' B8 W% k
  8.         if(buf[i] != 0XA5)
    " H' R' U# L( E: @
  9.             break;                                    # M' N7 @' M" K% W
  10.     if(i!=5)- v* b, t0 G6 m5 v$ \5 u$ k
  11.         return 1;
    ; o7 m3 T3 o4 t+ A1 e$ ~5 U3 D
  12.     return 0;
    6 h6 n: t' m5 w& U3 ?$ |! X' a
  13. }
复制代码
$ X) X. g3 D% \; d8 {( V
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
1 p7 [" a2 X( x
  1. void NRF24L01_RX_Mode(void)/ E, n: k; e8 g2 X3 y
  2. {
    ) E5 I2 w) w# H
  3.     NRF24L01_CE_LOW;
    , P: n; o+ ]# [6 {" l& [
  4.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);8 o# B1 W2 z# M
  5.     8 E) F3 {2 p1 a" G- Z
  6.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  8 _# e( }$ b$ w8 g$ T5 a# ~0 ]
  7.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    ! F- a# J% I. _) U, w, l
  8.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);$ V9 g! _' R, r0 @) v+ S
  9.     NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    4 ^% q: U* K/ w/ P
  10.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    / L0 }4 `1 D% @! {+ c
  11.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    1 b7 q+ m, W. a0 G
  12.     NRF24L01_CE_HIGH;
    % t: }9 b+ u9 t6 L) t
  13. }' P" X1 L5 f: `1 [$ X
  14. 9 V. g; M7 f! b  V6 p4 d
  15. void NRF24L01_TX_Mode(void)
    " l2 r6 W. y' V9 [0 w2 O$ a5 e
  16. {                                                         ; d% Z" [; f4 s3 G
  17.     NRF24L01_CE_LOW;
    % |5 A. d" O% Y- T4 G; I* H$ j- |* s
  18.     NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);' k- @0 J* ~* v+ Y/ Z
  19.     NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);( P5 Z7 O1 o4 z
  20. ) m% x8 t2 g9 N! C: X0 j/ b
  21.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);) J2 {% X/ }* U0 g0 y
  22.     NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
    : f0 P) L" O; u
  23.     NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);- M& j7 q9 p* ]/ S9 l
  24.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);+ F' e  S0 L" ^, R
  25.     NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);1 w+ E2 Y; ~) f. K( K" Y% W# `" n; \7 L
  26.     NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);. }6 w! l/ |0 ]6 a. `" y0 [
  27.     NRF24L01_CE_HIGH;7 R( Y6 n# a* {$ h0 ]- C) n
  28. }
    - J  B" |' ^2 A" H3 M' ]8 ?$ T1 q

  29. ) z$ h8 K4 h# k" S4 f
  30. uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
    + x8 a/ U6 R# c' Z4 P
  31. {
    ' ]7 q  o) _) T/ Q' p" O% G$ T
  32.     uint8_t sta;                                          
    * t+ I* K* {2 D2 z2 J1 }7 @: z: ?
  33.     sta = NRF24L01_Read_Reg(STATUS);
    8 d' X/ ^# L$ f5 h: A. C+ ]7 m

  34. ) |) F% ~6 \; p# E" d% ?" B# u
  35.     NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    2 o7 P/ e) l' i% r8 x
  36.     9 @' x, M' y/ B) f) ?
  37.     if(sta & RX_OK)$ R' ~+ ?# t. Y1 L$ N
  38.     {
    / P9 @5 G' D* ~) X% G* q
  39.         printf("sta = 0x%x RX_OK.\n" , sta);
      ]7 c8 O( `5 G, t- t
  40.         NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);8 V; ]* m4 d; U) n( n) S2 f; q
  41.         NRF24L01_Write_Reg(FLUSH_RX , 0xff);; C0 K: A0 n: j  ^5 O$ [& ~. }4 c
  42.         return 0;
    8 D9 l6 W+ \0 K7 T) M
  43.     }      
    6 R% c( R7 a! I  o, J7 L6 {
  44.     return 1;4 ?: r! h3 v8 A4 f3 {0 o
  45. }    . y, Y: S& a% b  T9 X

  46. ! `2 V9 V  I% L
  47. uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
    5 u! x7 N" X! `7 d' A6 J
  48. {% h; @1 B8 C, K/ w: q2 a% I
  49.     uint8_t sta;
      W1 v8 |6 L' W5 @- ^& u
  50.     NRF24L01_CE_LOW;
    $ Z" J6 o3 h! b4 G; @, c  S
  51.   NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    0 u4 B/ w: R. E0 Q! J: T
  52.      NRF24L01_CE_HIGH;
    3 S9 m* |6 F% G+ y% C
  53.     while(NRF24L01_IRQ_READ() != 0);
    " R# \8 _, k+ \0 p$ p
  54.     sta = NRF24L01_Read_Reg(STATUS);5 Z# }3 @8 j- G) g. y
  55.     NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
    - |- c8 Q+ x  N
  56.     if(sta&MAX_TX)
    . G1 ?' x0 }6 o9 Q6 s/ j6 @# r" q3 a
  57.     {( L4 R' {! J5 `, {
  58.         NRF24L01_Write_Reg(FLUSH_TX,0xff);* Z& _! [; V9 q7 W* Z8 D0 y0 j- |
  59.         return MAX_TX;& _/ O8 V0 e, b
  60.     }$ T1 _* X" o2 F3 o
  61.     if(sta&TX_OK)" @6 a/ E' \6 n6 {! [
  62.     {0 n. c& M% L% T0 S+ j' m  {
  63.         return TX_OK;1 u" R$ m6 C0 a& T
  64.     }
    % Z3 f+ D" R7 b% n( u
  65.     return 0xff;
    ' P  z0 {" t/ p0 }) M
  66. }
复制代码
: C6 B" P; b6 b, W  `" g: @' [
我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
/ U! A  A; I" U+ L* z7 \
52.jpg 53.JPG
. \: }- G9 o' j: y/ S$ n7 R0 K+ U8 A! d6 X# y% a* O
看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:% d% b+ X/ F# ]# v' o! V
54.JPG IMG_20250525_003610.jpg IMG_20250525_003612.jpg % @, ^1 G, Y. S, s) y
然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
; k$ l+ S& r" z0 N! @* J; U1 } 55.JPG
% ^' E  ?9 F6 C0 s' l
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)的合照! O) [: }% s( c: }; o
IMG_20250524_125758.jpg
( W3 l% m* v0 J" t7 \0 y  J3 m& c9 G* ^( Q$ @! V9 M

所属标签

相似技术帖

官网相关资源

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