虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。
* d9 c' t' u3 x& }但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;3 a; `; w1 Q% j5 {# B3 T
或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。 x& ?- {; N# }6 M" A
此时就需要用到发送完成和接收中断了。
% v' ^) O' V5 v8 C4 ]& j% d b0 |+ S- B8 A- S( o
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。' p& d# o5 X8 c9 E& |/ M: i H# e, M
* V8 p8 t9 L) s( r( v T
接缓冲区满中断+ e* E. D, B' ~ _4 n, y5 I
新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:7 G: V/ |2 `) i: L+ x O
# w7 P/ d/ ^! {# Y1 y- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄
/ R! u$ ]" ]- U
2 s J& N9 w6 K3 w J5 t4 o, k9 S, Y- void rx_isr(SPI_HandleTypeDef *hspi)
* H$ U5 H, ?7 N( [/ n1 _; [1 D2 e - {
! r0 u/ O) z9 c. s - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)/ }' i) T; s/ W
- {" T: i* i7 C6 \8 K
- u8 data = SPI3->DR;+ N2 [3 Y. T4 Q- }$ P* X
- printf("0x%X ",data);
1 E4 U4 }! T& c# s - }
5 |- S* I0 J) E7 n7 N& D - }
$ s% a/ w5 c0 a; i - void tx_isr(SPI_HandleTypeDef *hspi)6 l; X: e4 l( a1 ]$ B: s: i3 E7 T
- {5 L/ F* [+ y1 P* W* h5 ^' H
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
" G9 F5 l, t6 g/ u* x. W4 [+ J; ]/ ? - {
' n( p7 Q6 N( E6 X
8 b% d( p9 m3 F9 h2 J- }( J$ F! F; _* `* y) k' q: d8 H
- }
' _1 Y. P3 E( v0 C/ ?% u/ ~ - void SPI3_Init(void)
2 E% L+ o+ W; ?9 e - {6 x9 T$ @0 S. N- S; N
- HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);9 J1 _+ r C( I* O* V
- HAL_NVIC_EnableIRQ(SPI3_IRQn);
4 N' E: n d$ Y0 Q, }' l" T - " w& L) m+ J- m5 O6 @' Z. F! H
- SPI3_Handler.Instance = SPI3;
3 [" k' c0 B: Q - SPI3_Handler.Init.Mode = SPI_MODE_MASTER;) E% d' J) m! y% S
- SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
, |# Y; z0 ]+ W, V - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;( }# y6 I4 L x/ k/ M2 Y
- SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
% _* @$ `" R' ]. k2 A - SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
* N% f8 R4 n' B - SPI3_Handler.Init.NSS = SPI_NSS_SOFT;* K# ?& w2 X' q9 }6 [5 o
- SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
( d0 n: i4 S: n+ G - SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
0 m6 n/ \- |+ m - SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;1 t0 F! L4 P( S7 L9 G) l' u* b
- SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;8 C; Q3 m$ Y K" \
- SPI3_Handler.Init.CRCPolynomial = 7;
( K2 ~3 n. Q( L1 ]. o - SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;( I+ L8 ?9 l9 k N
- SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
/ E/ ]. a/ |* a# n, k, {4 D
! u) U5 M/ K/ H! b" W6 J3 }8 J8 X* ^- SPI3_Handler.RxISR = rx_isr;
2 F3 [7 y5 ]1 D* O$ q h - SPI3_Handler.TxISR = tx_isr;
6 J% T8 [; h. C \* b- f' r -
1 O4 o. q+ P+ d" f7 V) U - HAL_SPI_Init(&SPI3_Handler);6 P% ~" }( o8 W l5 ]
5 J3 H6 { u: u! H/ E- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);' J# L8 t, @1 W) R
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);& a* k0 U/ d- Q+ R, l# L
9 T( W( H* X% e+ R' ~- }8 m. V; j, d+ m2 r2 @, ~1 C) P- o/ F" S
- void SPI3_IRQHandler(void)
5 |* V5 r4 v+ p& a9 } - {
. I5 ~# d# u% @" E/ J w" H' V4 B - HAL_SPI_IRQHandler(&SPI3_Handler); ^ m( l/ ^4 C1 c5 J8 C* m
- }
复制代码 0 f( D5 R4 ~5 H$ ]( [4 A
对应的读写操作如下:
6 s S, K9 @6 b: b$ y% P0 i- H" {" V6 T; _! o& ?) F
- u16 W25QXX_ReadID(void)
) p6 ~3 A9 _# t" Q0 C: u - {, j) ~7 w2 M+ }. Y
- u16 Temp = 0;( M! `/ |4 G+ I- h8 O* ]* {
- % @% N5 {2 {! t9 s+ c( a
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);) r4 e+ o0 {; O" Q; n) A
- SPI3_ReadWriteByte(0x90);//发送读取ID命令 y: ^2 ^9 v0 w
- SPI3_ReadWriteByte(0x00);' T; E* n7 F. }% R* g* A2 z
- SPI3_ReadWriteByte(0x00);
3 c5 {7 @. \: S - SPI3_ReadWriteByte(0x00);
- Y6 q. U5 {8 a* k7 y7 K+ D- [8 o - Temp |= SPI3_ReadWriteByte(0xFF) << 8;
7 P# j# U! T1 n$ q& P" J$ P0 m9 F - Temp |= SPI3_ReadWriteByte(0xFF);( ^; k# |5 Q! F9 l
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);8 D1 _ o/ t7 i! q( A
- return Temp;
7 e7 Y" Y8 Y2 S7 l4 i) F - }
复制代码
$ ]) s/ A& b% |% {显示结果如下:0 m7 M9 E( _/ g% Q! k0 Y+ N9 w
4 U K/ l8 R* Z) _6 ?( p' N: n" f7 x* s4 ~
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。1 j+ I, r4 O( C6 A
& t( ?0 R/ ?1 y: ?: l# x/ |' ^/ Q3 o3 X发送缓冲区空中断
+ v4 T# `6 ]" K2 R# W同样在前面使能发送完成中断就可以了:
7 ^1 J' [9 V$ c
1 g8 d$ [. h$ d1 O' j4 u- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码 4 n/ x) u# S$ M' S2 n
但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。: x. m9 H7 }5 ]" `, k
b8 A3 @0 j5 D. @5 F0 ?3 N而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
7 Z R+ {& S4 r2 z: u
; b3 a3 E0 N( f- hspi->ErrorCode = HAL_SPI_ERROR_NONE;
& @ g3 m, ]+ t" s8 w! q - hspi->pTxBuffPtr = pTxData;+ _3 Q- F% j2 K t0 {; _
- hspi->TxXferSize = Size;! e* ?5 p' j6 h0 C! D V
- hspi->TxXferCount = Size;; i- e( U; J/ m* [: X! X0 T" q# ]) S
- hspi->pRxBuffPtr = pRxData;
% P9 t4 p6 I; l- e1 k - hspi->RxXferSize = Size;' Z2 w8 E. C! g. S
- hspi->RxXferCount = Size;
# H: z; y% W }8 T9 R1 N& ^ - $ T: s; _( A3 l$ L" e. w8 n5 S- e
- /* Set the function for IT treatment */
* a) I6 m0 `5 J( u& a8 R1 {! m; N - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )4 O& j! e3 L! f1 I7 R3 i9 S( c s
- {3 ?; x+ d- e/ |- E
- hspi->RxISR = SPI_2linesRxISR_16BIT;
" I/ s* r3 x) \& a' j- V$ t, Z - hspi->TxISR = SPI_2linesTxISR_16BIT;# j2 g! t1 p5 _/ t
- }0 n, x; `' E% P( X% U
- else4 j. v, i" R+ E% j' f
- {
1 @, W( d3 y5 J. @# ?0 k - hspi->RxISR = SPI_2linesRxISR_8BIT;6 g0 Y' I$ X& v
- hspi->TxISR = SPI_2linesTxISR_8BIT;7 W/ f# T0 {9 O9 ?* Q
- }* g. ]; F* l. B1 ]" [+ ^4 C
- __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码 + g' F2 r( G/ d3 m# U7 m
重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。
1 B5 a( c& B5 }5 ^) b- C/ e- y- Q; b/ I: j, Q# x4 Y6 F# O# a5 x
5 t. @" X! @, r1 R: b" q
. o* l7 U J" X: F. f$ ^/ [ z! w" c |