正点原子H7R7开发板上面的NRF24L01接口是可以接一个NRF24L01模块的,原子论坛也提供了例程可供参考,但是是适配给原子自家的NRF24L01模块的,使用第三方模块厂出品的NRF24L01模块程序需要做一些细微调整,无法直接通用。& F/ I; E3 u; C p8 ]5 m' P, w
0 r5 N7 l2 d7 Z7 @; H, H首先是初始化SPI接口,这个非常简单:
1 |: |* ^6 U& n1 J& H- SPI_HandleTypeDef g_spi_handle;: Y3 J% h1 K; R7 ~
; J- c u, |) s: Q+ ]- uint8_t SPI2_PD3_PC2_PC3_Read_Write_Byte(uint8_t txdata)+ j! O" y: ?9 a3 ?8 V
- {5 [3 H) O, f0 g! J4 Y; _8 a/ E
- uint8_t rxdata;& t/ ^* X- t7 R' C
- HAL_SPI_TransmitReceive(&g_spi_handle , &txdata , &rxdata , 1 , 1000);
* t5 N4 I" j+ b& f' |4 e - return rxdata;' n4 x( V. R- w! ~
- }
0 x7 j+ c* n1 l - 7 C/ a" S$ E8 ]2 z
- void SPI2_PD3_PC2_PC3_Init(void)
: S% `% D% r# ?: \ - {
; |. ~- M' w) f% b/ J - GPIO_InitTypeDef gpio_init_struct = {0};
! o3 u' C }6 C) n& I" f5 T% \ - RCC_PeriphCLKInitTypeDef rcc_periph_clk_init = {0};. d! S; M0 _' y$ f' x* l
0 ?; \9 B/ w6 p1 H+ j) f- __HAL_RCC_SPI2_CLK_ENABLE();
8 k* M4 N, m3 n. t+ b" I. E - __HAL_RCC_GPIOC_CLK_ENABLE();
6 F6 m) L9 J5 f# R' m! n - __HAL_RCC_GPIOD_CLK_ENABLE();
& g( x- i1 k1 f% n0 i - ' Y5 T3 g- L& t# x2 }( @. Q
- rcc_periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_SPI23;, S* n0 n& I/ V% g' E
- rcc_periph_clk_init.Spi23ClockSelection = RCC_SPI23CLKSOURCE_PLL1Q;
4 Y& f6 a: T4 z2 O% ~. X, d: \; H - HAL_RCCEx_PeriphCLKConfig(&rcc_periph_clk_init);: m, y8 J* p" w
- z9 _, q8 J9 E
- gpio_init_struct.Mode = GPIO_MODE_AF_PP;
8 c2 S* q8 B4 Q8 A7 Q) } - gpio_init_struct.Pull = GPIO_PULLUP;
6 p' o8 L( U2 ?2 a8 T2 G4 u+ h: h - gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;0 U* m8 t7 W# H7 G! {2 Z3 ?
- 0 a. j8 o. \! X2 b. G
- gpio_init_struct.Pin = GPIO_PIN_3;/ x8 L: S9 w, b; C1 @9 e, m
- gpio_init_struct.Alternate = GPIO_AF5_SPI2;
) e7 Q* k2 Q# k - HAL_GPIO_Init(GPIOD , &gpio_init_struct);- F; q8 V( r$ Q" ]
) R" {. k+ c% z8 {! w! b- gpio_init_struct.Pin = GPIO_PIN_2;
5 r: @- `0 [. p; h0 W: h4 G - gpio_init_struct.Alternate = GPIO_AF5_SPI2;: L' @8 J# h- M$ P \
- HAL_GPIO_Init(GPIOC , &gpio_init_struct);' b0 \( M1 I) ~- j- H; B7 ^
- 6 h7 w7 r Z/ \* I, `' v3 a7 p, a
- gpio_init_struct.Pin = GPIO_PIN_3;
5 i9 F9 O' s% t E8 p. B - gpio_init_struct.Alternate = GPIO_AF5_SPI2;1 q6 k \& c: `# @- Y4 P
- HAL_GPIO_Init(GPIOC , &gpio_init_struct);4 n& I6 D/ e- T" P
0 i" J+ u( E2 \0 V9 y) t- g_spi_handle.Instance = SPI2;8 a8 A; x! R- n( d8 }
- g_spi_handle.Init.Mode = SPI_MODE_MASTER;; @, d0 d8 ]" ]
- g_spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
; A- s0 m& ?9 | n - g_spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;' b' J0 y2 R# ~( k1 b X2 J
- g_spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
, O, I5 ^! l5 D$ l2 J; }2 B - g_spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
0 p# Y* Z8 j3 X3 R7 j - g_spi_handle.Init.NSS = SPI_NSS_SOFT; 6 A5 |% U3 c- s) L8 p
- g_spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
# ]6 U! W5 f2 O+ C* S - g_spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;2 e* _$ A" r" L6 @0 A
- g_spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;/ d- L* a3 @% X% n
- g_spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;* ^" X+ D% z) E6 O
- g_spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
" ]1 X' K' M, v/ u - g_spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;, T& k" ^9 ] f) d
- g_spi_handle.Init.CRCPolynomial = 7; n, n0 e: ~. X5 V
- HAL_SPI_Init(&g_spi_handle);% W2 ^: c9 W- M8 }# u" ?' n- k$ k
2 d/ _3 }( }- |# r0 j- __HAL_SPI_ENABLE(&g_spi_handle);
/ W C, H) `7 h - SPI2_PD3_PC2_PC3_Read_Write_Byte(0Xff);
U: p& M, y6 P - }
复制代码 这里需要注意的是,H7R7的SPI接口时钟要设置为128分频或者256分频,因为SPI123三个接口的时钟直接挂在PLLQ上,分频太少的话,波形变形的程度使得NRF24L01无法识别,进而无法进行任何通信,然后就是时钟信号空闲时为低,第一个沿变开始传输数据,这个也是NRF24L01芯片的特性,不遵循这个设置无法进行通信。* M2 I, D, l( b8 `# P
# f3 F- {2 m' v* A) D1 a/ Z0 @4 dNRF24L01还需要用CS CE IRQ三个脚,其中CS脚是片选,需要在传输数据时进行控制,CE脚常高表示使能,IRQ脚是发送时会用到:
0 `1 r6 q4 _: C& o" d/ C K: p- #define NRF24L01_CS_GPIO_PORT GPIOM
! w# ]# \% l) [7 @1 t3 [ j, @* f - #define NRF24L01_CS_GPIO_PIN GPIO_PIN_13
8 V# j* Z% q8 @3 X; n - #define NRF24L01_CS_GPIO_CLK_ENABLE __HAL_RCC_GPIOM_CLK_ENABLE();5 R+ t- _5 [# s- `
- #define NRF24L01_CS_HIGH HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_SET);
; n2 x# Y" F& f6 i& x - #define NRF24L01_CS_LOW HAL_GPIO_WritePin(NRF24L01_CS_GPIO_PORT , NRF24L01_CS_GPIO_PIN , GPIO_PIN_RESET);
& O1 t' J9 ]( N# k
( B" m% I$ U, I, ] ]- #define NRF24L01_CE_GPIO_PORT GPIOM. a( o2 d$ _% A4 }7 c0 |9 x0 E
- #define NRF24L01_CE_GPIO_PIN GPIO_PIN_14; n; }( L% e/ A: s4 {$ a2 O
- #define NRF24L01_CE_GPIO_CLK_ENABLE __HAL_RCC_GPIOM_CLK_ENABLE();6 U( G$ a- `0 \2 k2 t* W" z
- #define NRF24L01_CE_HIGH HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_SET);
1 A" f' _: _3 S e! u" X" ~ - #define NRF24L01_CE_LOW HAL_GPIO_WritePin(NRF24L01_CE_GPIO_PORT , NRF24L01_CE_GPIO_PIN , GPIO_PIN_RESET);
0 T3 V' o4 F- p% a1 C - ' G1 Z/ B- B/ [9 \ ^
- #define NRF24L01_IRQ_GPIO_PORT GPIOF- P! g! J% u! D& P6 p, a2 Y1 w0 z s
- #define NRF24L01_IRQ_GPIO_PIN GPIO_PIN_2
' m) w: T M" @- W S$ o% q - #define NRF24L01_IRQ_GPIO_CLK_ENABLE __HAL_RCC_GPIOF_CLK_ENABLE();7 X( C! g; F; g" H. O) D0 Q l8 U
- #define NRF24L01_IRQ_READ() HAL_GPIO_ReadPin(NRF24L01_IRQ_GPIO_PORT , NRF24L01_IRQ_GPIO_PIN)/ a3 s$ `! ?5 J" d
- 3 g6 [, z, c% s
- void NRF24L01_GPIO_Init(void)) r9 c0 ?& _* j8 M l
- {
) e6 ~! \ R7 B" L" a8 U! J - GPIO_InitTypeDef gpio_init_struct;
8 |1 w+ W' v2 k - NRF24L01_CS_GPIO_CLK_ENABLE;, P& H: h4 c U9 G% S# `$ ?
- NRF24L01_CE_GPIO_CLK_ENABLE;
$ o3 ^5 |( ]- u6 I- |8 [8 F A* i - NRF24L01_IRQ_GPIO_CLK_ENABLE;
$ O. c6 g+ {3 C& y( n -
) J. U" `$ ?0 D/ u- q - gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;. e5 S' b+ t7 ^* ^( V# a+ Q
- gpio_init_struct.Pull = GPIO_PULLUP;- z* Z( V3 w3 t; R5 C
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
O' y; }7 {; f% ] -
8 E ?: k) `/ { - gpio_init_struct.Pin = NRF24L01_CS_GPIO_PIN;
* a; u/ ^8 j6 ~. O6 | - HAL_GPIO_Init(NRF24L01_CS_GPIO_PORT , &gpio_init_struct);
! h3 K7 {- s$ s! E6 J, [ - # N3 B! }7 {( C. c5 Q& y
- gpio_init_struct.Pin = NRF24L01_CE_GPIO_PIN;
) ]. b3 [2 v2 @$ u - HAL_GPIO_Init(NRF24L01_CE_GPIO_PORT , &gpio_init_struct);1 l: j9 ^8 N- W
- , Z3 G/ h% ]7 S" n
- gpio_init_struct.Mode = GPIO_MODE_INPUT;
4 \' |9 w! ]# { - gpio_init_struct.Pin = NRF24L01_IRQ_GPIO_PIN;$ L! W' X1 f( X. G6 [4 Z& C: K
- HAL_GPIO_Init(NRF24L01_IRQ_GPIO_PORT , &gpio_init_struct);
9 W. j" w u2 H5 I* }. d" s6 | - - s6 L1 R1 b# @5 M: P2 r1 e
- NRF24L01_CE_LOW;% O& @/ w; G2 R' ?+ Y4 U- }
- NRF24L01_CS_HIGH;- w x0 l2 z/ G# R5 x' _
- }
复制代码 . e, j" E) N0 J$ [) H
/ @. S. T7 J: |: i4 b
& l4 O0 j& G: }. m9 m) Y& }NRF24L01有五个寄存器是可以用来检测器件是否正常工作的:( y9 l$ X- l* j
- uint8_t NRF24L01_Check(void)
* _ D4 H3 U6 X- O9 f - {
' m' |5 L1 I: s+ f5 v - uint8_t buf[5] = {0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
7 U3 A6 k L" }+ g - uint8_t i;1 v# f; d5 L4 Q, y, g5 ^; N) m
- NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
1 Y5 Q, K6 x* M7 C4 u) L - NRF24L01_Read_Buf(TX_ADDR , buf , 5);) p) c3 b9 x) `# f) t) ?& V( A
- for(i = 0 ; i < 5 ; i++)
7 z/ `( Q; h4 ~" w7 g) I - if(buf[i] != 0XA5)
) J. F, N- g9 b+ I' q: p - break; & D p' Y; ~7 Q: ~
- if(i!=5)' e. u, W9 h$ v7 o
- return 1;
4 [# @, b. D$ p {$ M& G9 S" N - return 0;, [; N/ ?- q- r
- }
复制代码 8 M, F8 e, B$ S/ B9 O# b
NRF24L01模块在同一时间只能设置为只接收或者只发送模式,属于半双工器件,要实现全双工收发需要两个模块:
/ _! J) Z. e1 }+ g5 D& `5 u- void NRF24L01_RX_Mode(void)
% ]& f9 Q/ f% d4 a5 Q$ l, u/ r - {
6 O! j, s2 _' E# y/ i7 ` - NRF24L01_CE_LOW;
. j5 C; H: P9 f. {8 A/ l( T. z - NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
5 {- m' L! d4 ]' ?1 H& b - * W) x# c+ V4 n& {: `
- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
) ~0 {+ Z8 c! @" X% s5 P' s - NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
/ n1 A) w; K' B( v0 V) _$ y - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
( R) ^ n/ i- x6 M - NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);8 t$ |2 p7 e9 d |" N0 a9 j& M
- NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
) j- u* W1 a1 }+ O. i0 ^0 ` - NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);4 n4 }& D% n; V! s0 [( A
- NRF24L01_CE_HIGH;' G) W, M* f' I: X: b- p
- }7 R4 `/ A% P U8 H5 _
- , N8 |; p. |$ Z5 z* p
- void NRF24L01_TX_Mode(void)
0 e" c: S. U, Y3 A - { 3 w2 [9 U0 P3 ?+ I8 e1 s; b- c( \
- NRF24L01_CE_LOW;
) \: U: ~6 z2 C+ A$ w - NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);8 h: r' i& H' ^% L/ ~
- NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
. N* b& N. U, D4 F
; N3 F# E/ ?/ \) z9 ]! _ L- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);8 k! q0 {% s8 S) k& `7 |) i$ q
- NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
; E; R$ ^# Q: k - NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
; R T# h8 e& H- P - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
* F0 S) G6 R5 y5 r( z4 F - NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);/ D, k) q0 l4 M2 C3 y
- NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
* q1 x2 n/ a3 k! b9 x3 n' I, f/ i - NRF24L01_CE_HIGH;2 W( i& }3 o3 i. r# i
- }1 ]. l0 C- C k( z$ [3 w" C6 m T
- 4 G. k; r! o2 j) q9 A8 \
- uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
& `" h p" C: X) |# V0 A/ H - {& s0 g# E* D' \+ Q" E& `. G* g
- uint8_t sta; 6 t4 ]5 V# f% B) e. B/ ^( V
- sta = NRF24L01_Read_Reg(STATUS);
# e& Z) A7 o( x. m- t/ ?5 z+ Q - 2 _$ `: L1 {2 K+ _3 F: ~
- NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);4 @; C8 P' H0 q
- 5 A. |- H4 R, {" n
- if(sta & RX_OK) j0 M1 u+ U0 l: B0 G. t1 B
- {
7 c3 {# t8 }; V7 E& L& F - printf("sta = 0x%x RX_OK.\n" , sta);
7 l$ V! F1 }: T: p+ e7 J - NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);7 W& g0 u1 Y, [2 T1 e
- NRF24L01_Write_Reg(FLUSH_RX , 0xff);
: A5 k+ A7 U! F1 D - return 0;" K4 S& |# g% q- V' f
- }
: ?) n3 c; o1 z I/ }! n - return 1;; y8 o$ b$ o* m! v
- }
! e' y7 S. I4 r" U% y
' q6 E/ i- S! O+ |$ g. B- uint8_t NRF24L01_TxPacket(uint8_t *txbuf)0 K) U& ?/ [$ T, H
- {
' v; ?, t# `; X6 {( ^1 ?$ Z# V - uint8_t sta;
! w4 a& a/ a) [' L1 Z - NRF24L01_CE_LOW;. G! y2 P2 }; B. u( V3 D' b
- NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);' r2 _% I# ], a2 B
- NRF24L01_CE_HIGH;) y, i3 }8 |; Z- P. D" k' q
- while(NRF24L01_IRQ_READ() != 0);
' b3 U9 D) ?1 h3 k% i - sta = NRF24L01_Read_Reg(STATUS);
' B p D9 `3 C9 M. S: t, q - NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);- ^) |; r$ T# N: ^/ n6 q
- if(sta&MAX_TX)( D# L: o9 [9 U6 K/ I/ U3 J+ a
- {
( Z4 ?, N5 T4 ^# }( K6 ` - NRF24L01_Write_Reg(FLUSH_TX,0xff);
: E' d" ]6 ^/ _8 F0 k - return MAX_TX;
! M- m# q; ?; P* v - }1 `7 G3 U1 T- G6 w
- if(sta&TX_OK)
7 K' F' _) X$ R% W/ _0 s4 X - {
" h3 W4 V: \* m) S( T. g - return TX_OK;
# k, |" J4 ?6 x. t+ h - }4 o0 [9 T: K e
- return 0xff;0 H' ]' F) `7 E, E. h
- }
复制代码
9 T% o. q6 T/ L: X) t7 U2 x我这里在主界面创建一个flexButton用于控制NRF24L01模块发送一行数据:/ e; K% Y6 g/ P7 K
4 Q! T: ~3 t* ~
, {+ h" N4 k9 e看看发送效果,按下fb之后,H7R7开发板会通过NRF24L01模块发送一行字符串,另一个设置了相同接收地址的NRF24L01开发板就会收到这个字符串:
9 H1 `# U$ M% }3 V# _
/ L0 z0 J7 q# Z$ Y( P然后是接收,接收就更简单了,只需要设置模块为接收模式后,在Tick事件回调函数调用即可:
+ ~# _* O k, V9 k1 f$ Y
; [' o* G4 b+ r& ^8 a% ~ |