虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。0 H) V) U, @0 C: C" X0 k
但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
" i2 U) k! ]- l: q或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。+ Y9 c3 w2 z& l+ ^( c
此时就需要用到发送完成和接收中断了。" w: K, I& {/ e
; S" h' M% g, R# G5 S1 Y
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。
8 m% v- k$ }( m1 x
! F9 m5 k' Y6 l( @4 T% z9 I, m接缓冲区满中断
( @6 s. E; i4 |9 T# Y新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:
5 W. Y0 o! G2 e6 x. g9 z3 d! f7 s0 [. n- B) Z" z6 u
- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄1 h/ h! O0 c! O- z
7 x( G# Y# H4 K7 b0 ^6 V' T: g2 ?- void rx_isr(SPI_HandleTypeDef *hspi)
& `$ a$ p( B/ c# x- C/ Q3 M - {6 U8 v4 v+ M! d& S: a: a9 n/ ]
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
2 l* l; I, {4 A8 ^- F0 C p - {' O8 @# s F. m: ?
- u8 data = SPI3->DR;
; k% f) t' m% q8 j; m$ O- O - printf("0x%X ",data);
1 Z4 _% M H3 { - }
8 J4 U% j, P+ V5 z - }
* j% N, s+ D$ [3 v2 ^( H* Q9 E - void tx_isr(SPI_HandleTypeDef *hspi)! }/ }: H. k. p* P2 r H: ?: t
- {1 I1 n1 s9 @. l7 V3 Q
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)& L+ r5 P! v5 @, p! M8 `) s
- {
6 W! \7 R( B, y$ f" T - . I# u* I6 ~+ Y3 t+ a+ C; a+ l
- }
4 r, M/ ^. s4 b" E b b" M, g- s - }1 f, M j# i4 _' q/ |! ~) _
- void SPI3_Init(void)
" O# y( e8 t# ]: t0 _* q - {( o0 s' {1 _- h% P
- HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
5 a5 ?$ ~+ \9 n. O4 |0 k - HAL_NVIC_EnableIRQ(SPI3_IRQn);
. G* R) O H# U
1 X2 J. L& J. `7 K2 o i j" M0 m- SPI3_Handler.Instance = SPI3;
: A9 Z( o) \/ W7 \6 n, R - SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
0 H/ ?) L2 A0 M2 A% D1 q - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;) m9 {9 G% }# ?7 x* F, D6 i
- SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
- Y- y, Z. R, m) _, r( ?1 v4 @6 X0 Y - SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;/ ~$ i7 @, |1 A# _ e1 B! U( j
- SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;4 }4 {/ Q7 w. ]3 k4 E8 k, i, ~ l
- SPI3_Handler.Init.NSS = SPI_NSS_SOFT;7 r1 M1 B: \0 `7 g! N8 h S0 D
- SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
' L& j$ a% z3 e' P* E' K* [ - SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;: S0 T& X- X' ]# v9 Q
- SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;% i I0 a& q/ Z& @# ]1 ]
- SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;: t% Q E" g; |: ~( L. r% E. k
- SPI3_Handler.Init.CRCPolynomial = 7;
' b7 g4 K ^ l- y; v0 P6 m: V - SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;1 _1 n9 ` g( V
- SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;, |1 O1 q' u9 {7 Q+ N, R8 c
, D3 E* d2 P1 b: E8 F, C- SPI3_Handler.RxISR = rx_isr;
3 }3 c+ o& I3 ]- } - SPI3_Handler.TxISR = tx_isr;9 B+ m$ t3 `* C: d$ o; m/ {8 f
- ' P- \4 P7 o( `2 b: Z
- HAL_SPI_Init(&SPI3_Handler);6 W7 S# Z1 }6 G+ k# T) z
- / I. z* ~! I# G
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);# |$ i$ V0 F" Q# y' o
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);' B+ T8 p& Q& {" T
4 D# y) x3 @8 \/ |* E- i8 ~- }
6 N0 n9 D4 {4 F; {: f - void SPI3_IRQHandler(void)
5 `% T7 v# u2 m# y - {
5 o; u; X: D) d9 S3 o' I4 K - HAL_SPI_IRQHandler(&SPI3_Handler);8 e$ g# D+ y5 ~$ x3 e5 Q7 ~
- }
复制代码
. Z0 y- N0 H4 L% e3 f) v. {" H对应的读写操作如下:9 B J$ `$ Q- |
( [ z) {+ K" h% m/ n/ V$ l0 x
- u16 W25QXX_ReadID(void)
: z& S3 O! S3 K: b$ s - {
* p7 C2 H2 u* O3 B - u16 Temp = 0;( j8 d4 v# ?/ l0 v3 |5 O
% @1 S* x' _6 |+ j0 _- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);+ ~3 M0 S( p- H
- SPI3_ReadWriteByte(0x90);//发送读取ID命令3 t% D' \9 d7 V0 y# Q) a9 _
- SPI3_ReadWriteByte(0x00);
7 D5 _0 Z& k) z! ] - SPI3_ReadWriteByte(0x00);
3 k% l! o" j! O1 {& [; [ - SPI3_ReadWriteByte(0x00);1 Y1 @" |' Y1 S+ Q& X7 x& u
- Temp |= SPI3_ReadWriteByte(0xFF) << 8;' \; |7 k" u5 `9 g: x4 D% E
- Temp |= SPI3_ReadWriteByte(0xFF);9 [! c- ?) r0 m. K5 d; L U. T
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);0 F2 ?: i1 j8 N9 p: k; Z
- return Temp;" }6 s: b9 [2 }8 ?: s
- }
复制代码
' E* E* H: n; o显示结果如下:$ O; x `# i! U/ V& w5 r
0 A% D' Z' T7 A% Y
6 [2 G. V7 k, p, p% c& {2 B" S
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。, W4 |! k+ H$ H, w6 i
- I. u: _, E9 D3 M, w: m发送缓冲区空中断
: y" U/ Q- W6 u( j/ s同样在前面使能发送完成中断就可以了:: K! g0 n6 Y. v9 v& M' O
R5 c2 C3 o" ]% @4 |8 @- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码 - h: [- i0 z* Q1 l
但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。3 R4 [. v$ K" H% f
+ ?# e6 e8 C1 J; R# j6 a
而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
6 g# v" G3 L- K+ U5 u; G' i, L6 F& d P2 L7 ]$ O- z+ x0 }
- hspi->ErrorCode = HAL_SPI_ERROR_NONE;4 I1 Q4 T; W y1 _0 f
- hspi->pTxBuffPtr = pTxData;
3 f7 @. V, L( P; c, G - hspi->TxXferSize = Size;
' |! Y, f q6 i% q - hspi->TxXferCount = Size;) K1 I/ d$ F* p. |. u
- hspi->pRxBuffPtr = pRxData;! g9 h! ~/ q( { y, u
- hspi->RxXferSize = Size;
, j3 P6 `1 M. x3 T - hspi->RxXferCount = Size;, h: V4 @! `; \! O" o
- & \ s6 }2 G& V. [3 n9 Q8 _6 S
- /* Set the function for IT treatment */
* L% H6 l8 H' M7 p' R1 j* o - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
; b" m. `8 h+ {& ` - {
0 G' M6 J* j$ c8 [9 U - hspi->RxISR = SPI_2linesRxISR_16BIT;7 i1 M8 p3 x+ F2 x" K) H
- hspi->TxISR = SPI_2linesTxISR_16BIT;8 K$ j5 s4 D7 C F5 i
- }
9 L0 |1 J1 b3 E7 R' X - else7 Z, ^4 j$ w: j- ~6 {* H# ~- |' T7 ?3 k
- {0 v- C" S) f8 ^+ ~. j4 a, h3 ^
- hspi->RxISR = SPI_2linesRxISR_8BIT;
; Z* W$ d2 w9 \+ z" q2 g: X - hspi->TxISR = SPI_2linesTxISR_8BIT;! m' `2 ]- F7 |, R+ ]$ N1 Q
- }) _* K7 z) a& O3 M/ y$ X
- __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码
& A) @9 ?$ n& |6 q% L重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。6 L9 [' Z, @- J0 G1 o. S9 {4 y
" }4 Z: n: i$ e* G4 l: I9 a
0 t: a" }, C! Y: C/ i& s2 t6 I2 U2 U/ M8 K# [; C
|