正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。
' C$ B8 ]1 s) f! U8 D; I! A) m
" Q. G) h1 y# R3 H
首先是初始化SPI接口,这个非常简单:
- E% p5 N) S; V4 _- SPI_HandleTypeDef g_spi_handle;. i& I. y: k N+ Y0 c& q' q
/ q& C& y$ v, x6 u; ]1 M- uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)" b( L. `: J# X! b( w- w
- {( ` q, z( I. t6 E
- uint8_t rxdata;7 B- e! G* b5 ^( y( o
- HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
0 s" W' x0 [" I' @; O - return rxdata;
! r8 V) Q- d, H$ P* f3 G) S' f - }
* T9 r; u2 P3 \+ i, `% n/ @ - 4 v2 D& A) }% K
- void SPI2_PD3_PC2_PC3_Init(void)
9 d4 M/ [6 c% X - {
- X; v6 J0 e2 P, P' A - GPIO_InitTypeDef gpio_init_struct = {0}; N% ^4 f/ C7 Y+ Q( Z1 I
- RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};
% \9 X8 F2 w$ T; d9 O7 F7 _* a1 M - ; q3 `" e4 h h' j) p
- __HAL_RCC_SPI2_CLK_ENABLE();( L( R/ c7 P/ v2 W0 k3 D# G
- __HAL_RCC_GPIOC_CLK_ENABLE();- Y5 |, N& c! J, S0 C. E
- __HAL_RCC_GPIOD_CLK_ENABLE();8 Z5 Z5 O! A% A" d t
-
1 X$ C' P$ E$ v; v6 }- _ - rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;
6 X% R6 V$ n: g3 a4 O$ [ - rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
: r- R7 @$ Q& L* w- } - HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);
2 F8 y. Q) e" u8 y0 R7 z) G
; U5 c9 w/ k+ z. Q2 \- gpio_init_struct.Mode = GPIO_MODE_AF_PP;
; @. m- x* H+ F6 { - gpio_init_struct.Pull = GPIO_PULLUP;7 F* [1 e T v
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;) p0 Z) {5 i* |) E! E
- # V8 j" M8 V( N; {: P5 f, y; l' r1 s
- gpio_init_struct.Pin = GPIO_PIN_3;
6 E- P) x F R; O - gpio_init_struct.Alternate = GPIO_AF5_SPI2;
# x y& G% N8 Y. V% t W- C6 z8 b9 q0 I - HAL_GPIO_Init(GPIOD , &gpio_init_struct);
H, N0 u9 f; P R( A$ T) C% ? - 9 s, s. T8 H$ I2 l
- gpio_init_struct.Pin = GPIO_PIN_2;5 p- O! Y: S: _3 T
- gpio_init_struct.Alternate = GPIO_AF5_SPI2;; E; C( z. f1 d6 {4 f1 M7 @" `
- HAL_GPIO_Init(GPIOC , &gpio_init_struct);
' H2 l" c% N2 u- z! q4 s7 B, Y7 y V - _% [- B$ ?/ X* e
- gpio_init_struct.Pin = GPIO_PIN_3; g/ r$ M+ ^% A& s: z
- gpio_init_struct.Alternate = GPIO_AF5_SPI2;
. V: w& q; X1 s" |) j - HAL_GPIO_Init(GPIOC , &gpio_init_struct);
/ D! o& F f( l% A0 q - % o. u9 l3 q- T3 l' |3 L, L# _
- g_spi_handle.Instance = SPI2;" u! S6 Q9 Z. e
- g_spi_handle.Init.Mode = SPI_MODE_MASTER;
5 p6 P& q; |! g4 p- G. m7 ^ - g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;, l( i, m+ v J# n! }' O n# c# x
- g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
7 t# \; |* @/ H4 D- h - g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;* E. n! a; d% T* {) P) i' y
- g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
9 @' V; k+ Q( o! j: c - g_spi_handle.Init.NSS = SPI_NSS_SOFT; ^4 |7 U% I- u9 G5 Z% o4 m1 z- {
- g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;2 Z, C# W% Z" }9 t* c$ I+ B
- g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;' q2 F' n n: k1 O7 b" T
- g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;! y" ~9 C" j3 ~3 S$ ?
- g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;/ k( s C6 x& H" |: T1 d
- g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;- B) b& B/ K/ B r# ~, N
- g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
8 _: @& V# z) w6 F G - g_spi_handle.Init.CRCPolynomial = 7; p6 W( X0 Z! z2 k _( d& D
- HAL_SPI_Init(&g_spi_handle);, ^& S) b5 S. n+ H9 T6 C; ?
- 0 B6 @# G8 X- _/ q' Q; N5 k
- __HAL_SPI_ENABLE(&g_spi_handle);4 J1 V9 v9 L$ `
- SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);, A$ U1 p6 v( l9 z" @
- }
复制代码 这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。
5 h2 A. ], {3 e6 |+ K' n& N
1 i% m9 M" x* H1 sNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:; O/ x) i$ I: | a
- #define NRF24L01_CS_GPIO_PORT GPIOM! |) v# i! P& ?% C7 r0 ^ K' ]
- #define NRF24L01_CS_GPIO_PIN GPIO_PIN_13- U, g; L U) I) W8 j: V8 [/ ^, C+ i+ M
- #define NRF24L01_CS_GPIO_CLK_ENABLE __HAL_RCC_GPIOM_CLK_ENABLE();- r7 E4 o1 P( ]9 i+ ~ O
- #define NRF24L01_CS_HIGH HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);$ _/ X5 r4 Q: I, L- D/ Q. ?7 g: u
- #define NRF24L01_CS_LOW HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
# n* i: D; R2 u
" G; T8 B/ `$ c/ n q: c- A9 v! E- #define NRF24L01_CE_GPIO_PORT GPIOM
; E4 [/ I( Z+ Q) L- z% M+ F - #define NRF24L01_CE_GPIO_PIN GPIO_PIN_14
! X6 l8 @2 `3 M& C. W2 R/ G - #define NRF24L01_CE_GPIO_CLK_ENABLE __HAL_RCC_GPIOM_CLK_ENABLE();- Z j6 S# m5 i4 K
- #define NRF24L01_CE_HIGH HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);; L0 c& K E. X! F" d' w1 U
- #define NRF24L01_CE_LOW HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
. k5 {+ H! d* m - " u( w5 w$ w: J& B: \! G; ~' G
- #define NRF24L01_IRQ_GPIO_PORT GPIOF" Q* |3 \$ }1 I" y8 C( x5 S" E% p
- #define NRF24L01_IRQ_GPIO_PIN GPIO_PIN_2/ X2 R6 d- `6 }6 }6 |
- #define NRF24L01_IRQ_GPIO_CLK_ENABLE __HAL_RCC_GPIOF_CLK_ENABLE();/ B8 Q. O8 \( a; B8 [
- #define NRF24L01_IRQ_READ() HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)
1 d& r2 R S" i
6 ~# ?9 s" [6 |1 t, ?3 g- void NRF24L01_GPIO_Init(void)
+ D' b2 d8 v) v! G; ?* n- t4 v# K - {/ n$ S8 C: v5 }0 x9 z
- GPIO_InitTypeDef gpio_init_struct;+ S9 g7 Y1 J7 L0 |1 S
- NRF24L01_CS_GPIO_CLK_ENABLE;
. @' e5 `5 b" a; ]) q G+ T - NRF24L01_CE_GPIO_CLK_ENABLE;
, [, n) u$ W6 E d* T4 m - NRF24L01_IRQ_GPIO_CLK_ENABLE;8 o7 ?4 d/ K' z" Z( R
-
+ x1 T/ p! U) f- |- A# |* ~ - gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;; |4 @3 p3 |) X/ l2 h) W
- gpio_init_struct.Pull = GPIO_PULLUP;+ f. q$ v7 c X
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
E1 X* U! t; H0 o9 O: T4 Z -
" G, k$ \. l$ t3 U. ]1 V - gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
: r$ S, l+ |! w" S5 I6 t% L& z3 M - HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
0 v6 S3 Q, N. p& O2 B; d1 M' I -
& }3 l; m* ` u' `5 S, B8 z - gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
% a+ V# i" w, S% W( j - HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);- S7 V; t9 T( o# N5 I! g+ W& L& T
- k/ x7 E" C# t" x/ @' X: J
- gpio_init_struct.Mode = GPIO_MODE_INPUT;& T$ W5 |6 t) j0 x; ?& _! l
- gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;
( Q7 c1 a$ H8 c6 b' H - HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);8 j0 y! U0 H3 a0 \* i2 h- U
- " N$ v, N( X m4 W* g
- NRF24L01_CE_LOW;& m' q- L2 w9 c; p' V- }
- NRF24L01_CS_HIGH;8 X) H- J4 q$ [: [7 ]/ e) V
- }
复制代码 2 m! b8 U6 s. U0 F) G D8 V9 Q: ?8 [
! C+ b% D7 g8 [6 w9 l) ?
6 Z9 v4 p& R) i: V. i/ `
NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:
7 M! G9 v4 n" b" v$ h& l& F/ a- uint8_t NRF24L01_Check(void)" x! [% U: `, e& U) v
- {. t7 ]9 @' x4 U
- uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};, I7 H; h, E" V. s& T! F( \
- uint8_t i;
" Q+ D" V) z7 G9 T - NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);: p, s9 w; a( j' ^+ A
- NRF24L01_Read_Buf(TX_ADDR , buf , 5);' ~& \2 l/ N$ ~* w8 ?% `
- for(i = 0 ; i < 5 ; i++)
4 w9 }% S% M9 O! b( |( a5 \6 P - if(buf[i] != 0XA5)
- R* ~4 m" ?/ y - break; - ^3 r$ r) ^& B6 k& G$ n `
- if(i!=5)
. o: U, P% [+ c) t) q - return 1;
7 A8 _' T$ @( U4 b) t/ z' ^ - return 0;
4 g* P+ \+ P. s* M1 @ - }
复制代码
& |# l1 s5 c: O$ L# {! R" INRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:. o+ T* k4 Q4 F0 T
- void NRF24L01_RX_Mode(void)
2 H# D: K0 }- i# n+ @ - {
( [8 g% g# H* J" R: s - NRF24L01_CE_LOW;
& A. A' m1 C" ] - NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
( G* N0 L7 R6 v r+ r" g7 e - * M; ]: g& ]. P4 \
- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
- X" _" A: L, T: t+ r2 x& u) S - NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);: z( x9 E+ j9 O Y' X9 ?+ S0 g H8 ~
- NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);; i5 W/ D. P! P* |6 c" N' E0 m
- NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
6 T ~8 N! |* N! i: M, x! B - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
! e5 i5 _$ U- P1 g - NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
/ Y+ z* a, }3 K; o/ w; @ - NRF24L01_CE_HIGH;2 ~& O3 K+ |2 ?" @8 E& T
- }
9 q# v. {' I" }: E# N. k+ f, t. U - ) c' Z% E6 K; w: A' ^: G
- void NRF24L01_TX_Mode(void)
; h, ?: q3 }( t( r7 Y T - {
! W6 H! c7 _0 T4 O7 N$ z, } - NRF24L01_CE_LOW;# J+ J& m% a& |' V
- NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);
( o3 Z+ O3 j- V3 A9 v8 Q |; _ - NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);5 z+ b1 {- P# L/ b6 }( i6 @4 r6 t, n
3 W2 e) }) c4 `( @- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);3 e2 D8 H* S A! o1 M" Y
- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);" H( K0 Y7 i; m; T$ Q* y+ S( C
- NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);6 `( c+ H1 y& ?( D
- NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
% G* p' C( L* r - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);8 R o6 m. U+ N& u+ `
- NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);- x" y: F1 Y3 J
- NRF24L01_CE_HIGH;
9 i/ f5 S! D* L8 q) M3 a - }0 ?" d& |% G5 Z
2 U$ e+ d7 c% V0 W. x( w0 N8 d- uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
@6 @0 R0 a) [ q - {
3 x& o) v5 g! H6 X - uint8_t sta; O( k+ }: B$ J# T, m% H3 O7 d. k2 ~
- sta = NRF24L01_Read_Reg(STATUS);
& m1 s! N& z+ k' B! T$ Q% }# a4 [ - . f- j5 q1 ^7 p1 W; i" Y& o6 U
- NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
1 |+ O5 M* G# c -
8 x( A9 `% q$ y0 f3 |% w5 r6 r: V - if(sta & RX_OK)$ i- N5 }( G, s) R6 q- {2 {
- {
$ _ Y4 B6 F, D - printf("sta = 0x%x RX_OK.\n" , sta);
0 e$ y% Y; Y; O! D- W - NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);! M. _' a+ J; M! Y3 p7 U c
- NRF24L01_Write_Reg(FLUSH_RX , 0xff);
0 N/ t) A- X9 X: n - return 0;. d3 u% S- V# w5 K+ x* ^& ~* u0 {- L
- } ) q6 ?) A3 f/ G1 ^# w! l
- return 1;
$ A; ^' D" n+ X, D1 | - } " G( R7 i' d8 s; n# s4 E
- + \) ^5 e7 I$ V3 b7 H
- uint8_t NRF24L01_TxPacket(uint8_t *txbuf)$ m0 @6 @) `. v% J/ g, H3 d
- {
O+ ]6 T% P2 R8 U8 [4 E - uint8_t sta;! e1 w& `9 h: ]( F0 w& `5 p3 w0 x) k
- NRF24L01_CE_LOW;
/ w" t2 y1 {9 X5 d1 I: @& { - NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
* k b9 I! b. W. a7 l. _ m4 o6 R - NRF24L01_CE_HIGH;( N# Z" W2 y$ h$ t
- while(NRF24L01_IRQ_READ() != 0);
1 D0 _! L1 U- Y# w# v& U) D; D - sta = NRF24L01_Read_Reg(STATUS);3 m% o6 c' |) o$ z
- NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
) Z9 s/ V u& C1 g: \* s0 D - if(sta&MAX_TX)- b$ o8 ^$ p- m' l& w
- {& h# W& Y0 i9 o6 T2 q" k8 o5 i
- NRF24L01_Write_Reg(FLUSH_TX,0xff);
* y" F" C6 q, D; K$ f7 ]; y - return MAX_TX;7 p) S7 R0 d% r* I4 q( E- W1 B2 X0 Q
- }% G7 W( a2 i5 k2 Q% w' N
- if(sta&TX_OK)! q. h3 |5 ^8 F' p( f
- {, `. i# e6 K' W
- return TX_OK;, X( {- h( P# y' i$ P: V
- }# d7 Y' _- V2 T, c
- return 0xff;9 S z& z3 Y, P# g& ~( I# _2 `0 Z |0 e
- }
复制代码
. p `( w4 U- Q |9 y# M我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:9 X$ D% K4 n+ u: }7 F% r! U
. @8 h6 a" _( `% U. v5 R( U. t( q
- h2 P) J3 H2 b/ p看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:* @) x6 F( B! u9 g5 e! i/ H
G9 k6 i1 f( [1 n/ V然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:1 v9 h. G1 Y' H" q0 g
j7 B1 h( ^; E G, O8 U |
. ~- W; \; h K: p0 Y& C- C