正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。, o' Y1 s5 Q" I- G6 r# w# a
& F1 \$ x5 Z) X6 K. H4 k& e
首先是初始化SPI接口,这个非常简单:
# k$ H7 ], }( p- SPI_HandleTypeDef g_spi_handle;. W# X) K$ ]4 f
: N3 e( h! i% G2 u- uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata): @4 w. M- ] u. \: b8 O6 b( c
- {$ z. }! a& k% M6 C/ B: ^/ p
- uint8_t rxdata;
3 B- Q- Y% R1 Z! D - HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);, }, a+ S8 Q$ W6 P9 _
- return rxdata;
, E8 _% F- p( Q0 v$ {: v - }
6 ~8 o& C2 K! Y: |) ]* \ - % K7 Q* g% `4 p
- void SPI2_PD3_PC2_PC3_Init(void)" ]# w0 s3 e' o% C) N
- {+ d9 T' T$ h( E: c6 x2 j1 h4 {
- GPIO_InitTypeDef gpio_init_struct = {0};+ w- Y3 f& \8 V
- RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
) g$ n, _' H% B& w* Q+ y
8 M1 B0 Y) j/ h! q- __HAL_RCC_SPI2_CLK_ENABLE();
) N7 i4 @) Y8 V5 T - __HAL_RCC_GPIOC_CLK_ENABLE();6 G3 R0 v: s) |
- __HAL_RCC_GPIOD_CLK_ENABLE();+ D4 e; {; ]! q$ T. d: |$ ^
-
2 i; r @2 e! p) m$ x - rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;! q ?2 M) g/ Y' g- J
- rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
4 S& F1 A9 @ @/ ^7 K5 ]& Y _ - HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
6 f2 ^4 {0 _) F* Z* U
# z1 J! h+ x9 r ]! D3 [- gpio_init_struct.Mode = GPIO_MODE_AF_PP;% g5 ~+ M+ S/ j! S
- gpio_init_struct.Pull = GPIO_PULLUP;- E1 D" t. R, h" g. A
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
G+ G2 x) ^. D) u; y3 l - 7 h( Y6 G0 ^0 ~4 z( [* G* u+ L
- gpio_init_struct.Pin = GPIO_PIN_3;
. Y) A1 G; a: E" S - gpio_init_struct.Alternate = GPIO_AF5_SPI2;3 `4 Y' [' p0 X5 A, X1 r9 z
- HAL_GPIO_Init(GPIOD , &gpio_init_struct);
4 I9 {) S, m* c- s' e - , r) Z- C7 `; ^. q( B
- gpio_init_struct.Pin = GPIO_PIN_2;4 ]4 n# N# c& s' j6 g4 [( D
- gpio_init_struct.Alternate = GPIO_AF5_SPI2;
/ h* _8 d" R K! k. x- T5 F$ T - HAL_GPIO_Init(GPIOC , &gpio_init_struct);
$ K1 q+ W- b' l# D7 z# r e -
' o: B# j0 K! a) j9 c7 D& G5 q - gpio_init_struct.Pin = GPIO_PIN_3;: W. l! H, D U3 S2 W% Y
- gpio_init_struct.Alternate = GPIO_AF5_SPI2;
+ \* I# j# g% f! x - HAL_GPIO_Init(GPIOC , &gpio_init_struct);
, b! H0 L1 U) v% [; `/ z5 l7 m - 2 b& d3 r- a8 `# e
- g_spi_handle.Instance = SPI2;
1 e0 ]# V% N3 e+ a3 v V - g_spi_handle.Init.Mode = SPI_MODE_MASTER;5 L/ C* I- O3 F, T' |
- g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;( r% _/ W4 d$ Y# {
- g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;+ s5 h- i k9 e( }8 }
- g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
* A' U) x" n. Y - g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;! z8 y# |4 o: E: m+ j! }
- g_spi_handle.Init.NSS = SPI_NSS_SOFT;
0 ?9 k% L6 a) |' d6 S1 K) g {4 f/ t - g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
2 x" ~; n5 V4 Y( I6 E0 V& {# Q - g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;; |$ R8 ^ S$ ^, E+ A
- g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;' `: H. d: S- ^, A8 C
- g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
- `/ e' J) f7 N' P - g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
' \" `( c! S' h; _7 F - g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
4 h) i) `& T! C) ?( L7 C - g_spi_handle.Init.CRCPolynomial = 7;
% ?2 q! Q5 |, f( T' ]* z - HAL_SPI_Init(&g_spi_handle);: r* A. ~" b6 c6 R, h8 Q7 D) Y7 V
! e$ r9 ?* @& h) v. P4 {; M2 [( b- __HAL_SPI_ENABLE(&g_spi_handle);
) s* R' j7 p3 O) U; M - SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
) h# D! K+ ?) [ - }
复制代码 这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。4 _5 w) A+ G1 @- [# E' h6 n. Y# g
$ v% C/ c3 q* h) }NRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:; _' Y, O$ Q! z; D1 B- ?8 `; t+ ~& O
- #define NRF24L01_CS_GPIO_PORT GPIOM& o5 t4 S& N8 }9 } C7 g# Q& K
- #define NRF24L01_CS_GPIO_PIN GPIO_PIN_13
# T6 h1 h; P" P% |$ A - #define NRF24L01_CS_GPIO_CLK_ENABLE __HAL_RCC_GPIOM_CLK_ENABLE();
" W- ~* l( w7 V* a8 h0 E - #define NRF24L01_CS_HIGH HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);+ o$ P* L' S* n+ m! F
- #define NRF24L01_CS_LOW HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);+ h5 r2 \, C% t% O
2 S2 `2 s/ U [% I( g+ U1 J, Q- #define NRF24L01_CE_GPIO_PORT GPIOM
6 \! A0 a# h5 U B" U - #define NRF24L01_CE_GPIO_PIN GPIO_PIN_148 k9 R* o5 M* x6 h, j
- #define NRF24L01_CE_GPIO_CLK_ENABLE __HAL_RCC_GPIOM_CLK_ENABLE();+ Y d8 w g/ C( u
- #define NRF24L01_CE_HIGH HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
$ ~, O. p$ V4 Y; L! T0 v - #define NRF24L01_CE_LOW HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);7 ?8 ~8 e" N, t8 f9 f1 H
- ; c8 F' T. \0 c! V# }
- #define NRF24L01_IRQ_GPIO_PORT GPIOF9 }9 Y/ M3 ~+ H& @) Z
- #define NRF24L01_IRQ_GPIO_PIN GPIO_PIN_23 T3 y0 O2 t% i$ Y0 M( V
- #define NRF24L01_IRQ_GPIO_CLK_ENABLE __HAL_RCC_GPIOF_CLK_ENABLE();; _: x' Q7 g, z O4 k, Z5 o
- #define NRF24L01_IRQ_READ() HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)6 R& L& p( S0 h/ ~6 `
- , ?% `6 g8 M3 j2 K( W- V
- void NRF24L01_GPIO_Init(void); f" D/ u% C6 a4 ?$ D& b
- {, i& C% B8 W5 R1 q6 d
- GPIO_InitTypeDef gpio_init_struct;2 t* w4 _8 x1 g+ T
- NRF24L01_CS_GPIO_CLK_ENABLE;0 r# d5 E- O' m
- NRF24L01_CE_GPIO_CLK_ENABLE;
+ o% x) F" S8 B( M# L f' V( e8 a - NRF24L01_IRQ_GPIO_CLK_ENABLE;
0 e7 Z9 k$ R2 Q# L -
, @% Z, k1 ^. s" V - gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; A% ^; }4 G+ G
- gpio_init_struct.Pull = GPIO_PULLUP;' e7 \. v$ j5 i7 Z+ I1 |
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;. Q, O# f1 s$ L% R( Z) @2 W7 X& X
-
+ B) o9 }$ H" L" |) C, T/ Z - gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
- E% h8 w% Q, N* u4 c - HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);( S2 g" u8 h; _. P5 G
-
$ {7 u7 T7 t. \) ~& E+ T6 } - gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN; O9 P- y$ N U
- HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);
; _" Q( K; b* y* A# R$ J* U - 1 e+ V. Q K n* j9 v. z% ~
- gpio_init_struct.Mode = GPIO_MODE_INPUT;
3 n# ~8 |- P& Y - gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;6 y9 d7 u( O4 B" m
- HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);# w8 e, {: q2 @- C. E+ J# ]" y
-
( N+ @4 r8 K0 f) U0 L0 i - NRF24L01_CE_LOW;
' A. d# e! F; U - NRF24L01_CS_HIGH;$ L. ^3 s, O( _$ b* z
- }
复制代码 5 M' g# e* m' R) w
! q. i* [* G+ G
. q& a& J( n) a
NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:! X3 N4 W/ W; d- ]6 I
- uint8_t NRF24L01_Check(void)
! N- M% i) N. M4 Q3 O! o0 u* V - {
5 @4 c' ^& J& m& k1 D. X0 L! H - uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
7 Z# r' Q ?( A6 G6 M `: `/ y' R - uint8_t i;* A+ `& ?' O- P+ `& z
- NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);, I/ i5 v' l. y9 t: o. e- b8 u
- NRF24L01_Read_Buf(TX_ADDR , buf , 5);
0 @) B5 n) D" z! ? - for(i = 0 ; i < 5 ; i++)
, T$ S: o/ {: s0 P8 v - if(buf[i] != 0XA5)
% Q* q. J6 l# k8 N! G S- ~1 ~ - break;
- [% Y: X3 b5 A' A! ` - if(i!=5) I% N" `) j9 \* b3 j/ u; l
- return 1;
* n' k4 C* U& b; g# t$ [ - return 0;
" |; C" _$ }2 N; y9 L/ T - }
复制代码
) r" x8 y& i6 }# a" @NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
6 p: D% B$ A1 j$ J* A- void NRF24L01_RX_Mode(void)! K$ {: d' |2 F6 w ?0 f0 I
- {
! J5 J) G4 p1 ~/ i - NRF24L01_CE_LOW;9 Y: \) ~! A. O; m5 g
- NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
+ |- h( A/ f+ J! W, P+ T -
* I& F# ?2 U" a! n! f) H - NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
& ?$ D7 R7 y. B7 ]* k - NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);$ X. Z3 q* b1 a0 s* p, L* A
- NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
+ C8 x; ?3 [2 _ - NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
, l! Q$ ~& k2 Z) D - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
! @8 r' D# ? b! {5 Q( l# L - NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
! M1 G0 i4 p: W* m$ ?9 m - NRF24L01_CE_HIGH;4 D8 x' o4 j) p) u" V
- }
$ z% F. k/ G% e _. h - ) ?( c! m4 @/ j# l' m! y
- void NRF24L01_TX_Mode(void)0 r f1 Y. c+ f# f: Z: p% y# E( P8 p- M
- {
& S2 z8 R: O j. N @/ A% | - NRF24L01_CE_LOW;
7 B7 C& w' z1 e1 P5 K# [ - NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
+ s+ W4 i; \# P6 J9 W" X. ^ - NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);6 @% h6 L, I" w% _/ _, f& w
- 0 d( E- C! O2 j9 O
- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);- l) G# l$ }! j% y
- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
! |- i/ ?- {1 h/ W - NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
* S. J2 L+ j, j! Z, |" K - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);% G& s Z- K9 w: B: E
- NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
* ^1 K9 t9 v% i7 H - NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
3 O8 E: @# j3 _$ G) r - NRF24L01_CE_HIGH;
2 ]* t; }/ U3 T& i8 V9 m; R1 \ - }& r$ `1 |$ [) j7 R, t; n
5 M" n1 v( A; y- uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)7 A1 E6 l0 ?3 Y+ W, v. ~+ `0 @
- {
1 f9 J2 o5 M, R; Z3 d6 v# C4 w8 J- R - uint8_t sta;
; J. U5 C' @3 @$ C - sta = NRF24L01_Read_Reg(STATUS);) \8 k' n @+ @% Z
- 3 L% h) b1 j3 z& D
- NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);- a6 `& {- D; S$ q1 i B, H
- : T- O$ d$ j2 f& n
- if(sta & RX_OK)
0 T: B% _ b0 S" t - {
H0 Z( R9 M# w+ F+ @" q* v - printf("sta = 0x%x RX_OK.\n" , sta);0 B6 Q# O* f$ c0 Z5 \; t
- NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);
) k* B m6 c! q& W. N - NRF24L01_Write_Reg(FLUSH_RX , 0xff);
_& ]' o) \. a: q - return 0;- O; R7 z8 Z% z
- } & X! [+ D2 J+ K- c( R9 F
- return 1;
. M/ |( P7 g$ ?( q* {8 A0 J - }
' C E4 G$ h( x7 s9 e6 }9 M' k
4 J' K( n, x2 B( k- uint8_t NRF24L01_TxPacket(uint8_t *txbuf)) ]/ n C8 x$ V. C
- {
) }% j! ~& d8 x5 }2 u0 {* t7 ^ - uint8_t sta;2 ?) }3 U: Z% `# P
- NRF24L01_CE_LOW;% n" n8 Q5 |) M$ `2 x& z' o
- NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
. a5 I# h; T6 T - NRF24L01_CE_HIGH;
+ x M" ^( u5 W - while(NRF24L01_IRQ_READ() != 0);" S) S; K7 Q0 \9 Z3 o7 u
- sta = NRF24L01_Read_Reg(STATUS);
, \0 n$ T: Z# J. t/ G) U - NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);" W {( ~- A( G/ [; ]& E, ~- e A6 S$ e
- if(sta&MAX_TX)
* e. w3 \3 x6 F9 y4 q - {- Q2 i0 e' d2 O; @
- NRF24L01_Write_Reg(FLUSH_TX,0xff);0 _7 ^: Z" ^, p) c% M/ X" N
- return MAX_TX;
2 v. r0 i p) [# U# [+ V - }. U$ c% M7 C9 m) ^- c" r- b
- if(sta&TX_OK)) V- @% q2 c$ g! A
- {- ~) l f6 E( Q7 I4 P" N. M8 G- m4 ]' {
- return TX_OK;
" x* l' C, @. Q# n - }( `* _, ^* X9 I. h( l* X* J- k
- return 0xff;
' \% k8 a7 D" K0 b; K - }
复制代码
5 v' t# l; y4 @. G我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:
" k7 E7 p, t8 t& R9 Q
- J' p; }1 E! D1 i! w" q _ |+ N) c1 z
看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
# ?, T' @" t& ^ \. p
8 k. A& S2 m$ a$ Q F, K. r然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
3 K1 \' l2 A; e, F# h8 ?3 K
~% @6 r. j v( J7 i3 _ |
! r4 I/ t1 ?# ^6 D7 g