虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。
8 j- }8 l! r4 Z/ m6 D3 ~但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
2 l' H- Q d/ m2 h或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。
3 s, O( S- _. x: }此时就需要用到发送完成和接收中断了。
|6 v$ d5 X3 r! \8 F i: a+ {% b& G1 \" |/ ^ I" X7 K+ W/ t; l
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。
; C8 z0 T6 p8 x, P# R9 U4 L! _7 X3 z' z) W) h+ O/ ^! c3 I- G6 _
接缓冲区满中断
- W4 w( V2 k4 p* V6 L新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:
# w/ `3 ?6 T* W- j: I0 ~
7 k4 s- z, L/ V- E2 U% A4 d- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄
/ p. ?( N' D4 Y - 5 E6 `# o, k' H, g; g: f
- void rx_isr(SPI_HandleTypeDef *hspi)
) b9 h' W& a9 Z, D% B- R - {
. O {! Z$ \$ B0 k - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
$ p* L) B* A' a - {
% ]# f; t( q9 o K8 c - u8 data = SPI3->DR;
( J. }: R# o. g G% D( N - printf("0x%X ",data);' j) a# g% q$ ~( z' G
- }
! F7 i9 g& g9 |: W% I; `9 m7 C - }! \# g' {! r* e( N
- void tx_isr(SPI_HandleTypeDef *hspi)3 [: ]; O. U; S* k3 r4 l
- {* S) ^$ J3 l* U3 q1 K: z
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
7 W$ ~) X- p5 H- n7 L$ k+ c - {; ~5 Z3 i1 q+ }6 K" k) U
- ' e5 r" x% G& S+ {0 N1 K) |! C
- }/ u `- L- {9 y: ~+ |
- } D- q0 Y- T# C
- void SPI3_Init(void)( @# t- c& _1 J" }+ [
- {
7 e- F! i, P- B6 \$ v+ A6 i0 f - HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);7 V1 y3 i t5 z7 k% Q2 X
- HAL_NVIC_EnableIRQ(SPI3_IRQn);. H& w: Y- X5 S* v7 h" H5 o
4 z5 K* ^/ {- c9 Z! j1 |: c- SPI3_Handler.Instance = SPI3;" @* v" o/ K0 f y) T3 i# j
- SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
1 Z, a8 _1 ?8 }6 h5 N+ L" d. X - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
+ U# s( q- u1 F4 N5 R+ R8 Y - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
6 ^3 M% K3 x5 j0 ^' q - SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;5 }, i1 |- h1 w
- SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;2 ] ^/ V* N/ `! W
- SPI3_Handler.Init.NSS = SPI_NSS_SOFT;: [1 D5 U$ z8 K% }
- SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;) r$ r# ]7 S- w7 i; `. |3 _
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;9 U. ?$ ?! V7 ]# l! a+ }
- SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
' G; S+ @& X6 `8 C5 K1 ? - SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;$ z3 q, B* a, B; m" k4 y: ?
- SPI3_Handler.Init.CRCPolynomial = 7;4 Z; Y; d% V, Z
- SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;" ~! N" D2 U- B1 t+ M F* t( G8 i
- SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
2 ^. `2 R1 M; I1 M
1 S/ t) q% b+ b# j1 G( s J6 d* Q- SPI3_Handler.RxISR = rx_isr;
4 e/ R! W2 h- H) Z7 r( J& H' T - SPI3_Handler.TxISR = tx_isr;# N+ p+ ]/ ?, c: V ]1 k9 y
-
' F4 l: |5 l& d3 z - HAL_SPI_Init(&SPI3_Handler);) l# F/ D) ]' W; C
- f' S9 l3 u# O
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);2 d& z$ @% i* E: e" {9 @- S" J+ q; K
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);
2 V7 ?. ?5 r- g - ) B" b3 C+ |- q4 t1 t
- }
- f& S: f' w& b9 u& F( D% Y! G# e/ K - void SPI3_IRQHandler(void)3 r/ i3 L" t+ D4 y7 h7 E' V; n+ q: j
- {
; q9 _% t( K) [# f - HAL_SPI_IRQHandler(&SPI3_Handler);
% a+ J g. Q$ J$ y; d - }
复制代码 N8 p& V9 E, |7 N+ |- |
对应的读写操作如下:
& |, P+ s0 o" i5 l; R/ m: a/ P$ z" S
- u16 W25QXX_ReadID(void)
) f0 V$ v- W& { - {
0 E4 v+ z8 C- T5 s3 }1 ^ - u16 Temp = 0;
* E2 A _9 L' H
; n7 G0 C% |7 h5 M- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
l6 W* E5 \! m1 T3 t, S - SPI3_ReadWriteByte(0x90);//发送读取ID命令
/ @. D Y. O* X$ t3 x7 d( E' L - SPI3_ReadWriteByte(0x00);
# [: A" S4 |! o' w4 R7 f8 u v1 m - SPI3_ReadWriteByte(0x00);/ o+ f: J0 L: E" n4 L5 C O
- SPI3_ReadWriteByte(0x00);- u" W) Y g4 y6 {
- Temp |= SPI3_ReadWriteByte(0xFF) << 8;
3 A2 A7 Y f9 W' c - Temp |= SPI3_ReadWriteByte(0xFF);9 Y6 N! d$ S. b4 H) g, k+ Z
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);+ l, ^# j5 l6 ~4 u% M) B ]# d* ~
- return Temp;- B+ k! B- V, z8 q7 O
- }
复制代码
+ \& h: N3 F, x: B( d显示结果如下:
) T: \8 |/ ^/ E0 H/ l k+ \
1 U) a, ~; k: ?9 I! I) J1 D& T R( J- ?( q* ?- B! X
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。: S/ j& C( y8 r* Y" W! {
1 ^! M6 ^! T" S; k, k" f( r
发送缓冲区空中断3 ~% [& U* }6 }! R& w5 l) w
同样在前面使能发送完成中断就可以了:
4 c! }3 Y1 u9 D; X# ~( s. I
& p5 c7 F+ ]6 M. J I- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
, Y# I, K; e/ s6 d7 ?但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。2 e i* f o$ _% ]1 O% i" L
j& f( m: C6 r; i7 W: A9 H" N& }
而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
0 M2 Z7 _$ N* U; `6 U9 y( X+ }/ `7 h+ f6 ~; J7 X' K
- hspi->ErrorCode = HAL_SPI_ERROR_NONE;% X/ z/ Z% s: S: p) A
- hspi->pTxBuffPtr = pTxData;
% G$ p k0 z$ W: v- F. J - hspi->TxXferSize = Size;
" w. Z: k5 l: ?0 }% P. _ - hspi->TxXferCount = Size;
+ h' v/ _* M5 R1 w$ r2 ? - hspi->pRxBuffPtr = pRxData;
4 Z# G: j$ r1 J/ u$ _6 H6 y - hspi->RxXferSize = Size;
& M7 L0 V9 b0 ]4 a+ h0 S, g0 f2 ~ - hspi->RxXferCount = Size;0 s( C2 Y6 [1 q8 W0 w
- 4 g5 E/ W8 S; w. L1 ^1 h
- /* Set the function for IT treatment */
& v; s. ~, N3 `- b. ?& p5 ? - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
/ v+ E7 l! \" U! X% Z% S - {3 f6 f3 n2 Z3 V" s
- hspi->RxISR = SPI_2linesRxISR_16BIT;
4 c- f2 R- g/ `; Z: H2 [2 C - hspi->TxISR = SPI_2linesTxISR_16BIT;
5 @* U2 C/ e/ k0 R - }8 W. S. R# A3 L
- else" Y0 ]* C# ^* S! s5 e7 E% N
- {
6 G9 @5 C. E* {9 r: a - hspi->RxISR = SPI_2linesRxISR_8BIT;
- [+ s5 R: Y) A2 ^" \ - hspi->TxISR = SPI_2linesTxISR_8BIT;
* C2 ?6 ?$ i. C* W - }
4 @, ^* P$ P$ b6 E - __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码
7 R1 z1 ]; a: l7 S' g重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。 {7 O8 J& R) B7 H2 w
4 E( y! X( }3 r: C" w! I/ h4 [! |( d$ V
1 Z0 T0 h1 b. v& I |