虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。( Q- b9 x; H8 n: Y. L, n
但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
& ^( Y% ?, H2 g2 C0 R7 }或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。5 z8 `. e; ]) f4 @% {
此时就需要用到发送完成和接收中断了。# R \( ], P+ |% L4 ~" [4 r1 `
* f0 P% y9 [3 I. s. ^4 V& c) n" h前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。0 F) w9 ^! \9 o( V, s
5 f6 s/ Q) ]/ b8 E( S
接缓冲区满中断
7 }" a$ e: l; s3 K. k$ y3 W新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:8 ]+ \# I6 N: v# G+ V( ]
$ M3 x. _2 F, Y; K9 L. D& X0 r6 M: o/ v
- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄5 k* l0 s# W9 A1 \/ q
4 N5 E4 h( |& C% t! x- void rx_isr(SPI_HandleTypeDef *hspi)
9 `3 T/ t! d7 ^* s" F g9 T - {
3 B. M# O0 c' Z0 t0 J ^) s - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
) y, i4 }- B9 Y, r |" }' P - {1 [- X [$ q3 k% A+ B9 r
- u8 data = SPI3->DR;
; ~& c; b3 o! y! Q3 O - printf("0x%X ",data);/ D! @, E* W5 W8 ~/ ^
- }
, s) Z) W6 G4 R* u# R& }3 P' H - }
: z. ^# x9 _- D( a. _6 Y9 q - void tx_isr(SPI_HandleTypeDef *hspi). y$ E. q* d. b1 I
- {6 h, F6 n r0 g
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
2 E$ C5 c Y9 n" W$ g - {( w% P9 G; g8 ]3 c- I. a j! v
- 9 s/ ^' J8 s7 f7 |+ ~
- }
|. K. D4 T) t% } - }
; J2 r! n: C0 \& Y - void SPI3_Init(void)2 }8 i" r; d: C( o/ I( }& G
- {
6 w9 N6 m, z5 ?- x1 E. C9 S1 V - HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
4 u- `3 b) w% X ~) j - HAL_NVIC_EnableIRQ(SPI3_IRQn);. Y: s) b+ \+ ?
& D$ i3 m) o; J9 A* e& }; ^; V. l" U- SPI3_Handler.Instance = SPI3;5 H# y) t, X% U/ J! W) Y7 P; z
- SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
3 U. j! c0 d8 @ - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
) M, h6 c2 c5 @) t - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;3 k! F3 U! L( m! O
- SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
2 a9 {4 `& ~/ S5 C$ |7 I2 C - SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
: Y$ b: ?4 A9 `. W: ?8 O$ x) Y3 C - SPI3_Handler.Init.NSS = SPI_NSS_SOFT;# X+ f& L5 X4 z5 x
- SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;9 g7 R9 v1 h0 S
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
0 B3 X$ g! d5 ^) p8 V - SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;( j# p; e# T6 g9 P
- SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
: `/ D4 V1 d/ D - SPI3_Handler.Init.CRCPolynomial = 7;
3 d# w2 @4 F% L - SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;- g, q1 d/ E/ s- N; K& Q5 w
- SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;, X7 p9 u9 t( x
+ N9 I# q$ C r- SPI3_Handler.RxISR = rx_isr;
: O x0 e5 F m. A* t: ^ - SPI3_Handler.TxISR = tx_isr;# u4 D Z3 w: S+ o
- # n' b: m4 i p! ]9 d; A2 b9 Y
- HAL_SPI_Init(&SPI3_Handler);3 y/ m" a# X5 y" ~
- 2 w/ C# n1 `0 l" _4 e
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);' b4 d! v3 y. R) U* {4 T
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);
2 S+ q0 s i6 S7 h
( W5 x, x& D4 c. a9 ^, |/ [- }9 z& T2 u( a8 E! F# l
- void SPI3_IRQHandler(void). f9 `1 E7 u6 T6 c
- {( o5 a8 |+ s. ~1 y! X5 H
- HAL_SPI_IRQHandler(&SPI3_Handler);
: k: W3 c7 a0 ?# w( \8 P - }
复制代码
8 Y$ `# I6 @" v& J- [. z, q& B对应的读写操作如下:
6 B. T8 R8 K7 S+ k* W! C& h* J8 H9 n; f+ L0 p9 ^; H) W5 W
- u16 W25QXX_ReadID(void)
* `2 T$ r$ i8 R$ @; Q. y - {
3 w; k" J2 [3 S8 g3 c$ x8 Z5 M - u16 Temp = 0;
9 v6 ^! D" n) A d% A% _2 \
+ P. R/ A& `" t7 n7 b. B8 A2 J- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
" I' N5 [& C+ Y0 K; Q - SPI3_ReadWriteByte(0x90);//发送读取ID命令
* B2 { j7 o9 p. u' M) q - SPI3_ReadWriteByte(0x00);
+ }1 Z( N) g* n5 i7 Z9 ~1 n - SPI3_ReadWriteByte(0x00);
7 Z7 ~/ y; Z$ ?5 e6 a - SPI3_ReadWriteByte(0x00);
9 w+ g9 r: L% a4 u - Temp |= SPI3_ReadWriteByte(0xFF) << 8;
: X- e/ j+ m. C, `0 m - Temp |= SPI3_ReadWriteByte(0xFF);
4 Q* F7 h! E5 ~9 ?" n6 P - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
- |* D0 K' W; u; k1 G+ k$ _7 Z - return Temp;8 y0 Y+ q J# u
- }
复制代码
8 y# ?' A- n. b2 ]7 F3 M/ C& Y' g% m: t显示结果如下:
6 v6 R, B( f, B$ m3 p" f0 y" n x# V3 d z
6 k$ f) z a/ t! p. Z0 }
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。6 T# x0 @1 {; M; y
6 j& v j% v$ z5 d# R
发送缓冲区空中断
/ [3 `; F& s/ |同样在前面使能发送完成中断就可以了:
( H ^% o" u8 m0 |' @' Q) N2 T, w, |: ~7 ]; r7 G/ M+ E& _
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码 5 y, t! f' ]: h3 h7 s7 n# p4 s+ h% k
但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。! W) i7 R0 {; Q
/ P% u/ H8 E; I
而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
' _1 t* z* u. Z+ E, M* x" c
2 N, |7 \5 j/ S e8 |2 F- hspi->ErrorCode = HAL_SPI_ERROR_NONE;
8 S8 M3 j, k& M% q/ `& B( F - hspi->pTxBuffPtr = pTxData;
" h Y6 n3 ?0 n' C6 D - hspi->TxXferSize = Size;4 f8 N0 {* a; @7 g# Y, y9 ~( G
- hspi->TxXferCount = Size;
! B; e* V0 Y% H$ d - hspi->pRxBuffPtr = pRxData;1 t% B- e' q1 F; R9 m
- hspi->RxXferSize = Size;
! |' J: h9 i3 r5 x9 N: ^1 {- m6 F - hspi->RxXferCount = Size;
- C2 [& S( ?! @( \! w9 Y" E
' w- y1 t/ @8 a3 n+ ^- /* Set the function for IT treatment */
: r( k$ R8 _) I( p: ^! m7 J( ] - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )" x3 R7 h( D. C7 H) w0 L, ~
- {
) W% |' K- i" H/ V$ u - hspi->RxISR = SPI_2linesRxISR_16BIT;
! n* H/ y+ j r8 t - hspi->TxISR = SPI_2linesTxISR_16BIT;# G- E% b, a% Y# p" D0 }: n
- }
1 f) S6 ^+ _- i" Y% _ f - else
$ r0 @; }0 \2 F# F2 {! Z - {
5 {3 M/ ?; r7 h6 r7 C' \$ @/ y9 w - hspi->RxISR = SPI_2linesRxISR_8BIT;
: x+ P7 |" Y; Q - hspi->TxISR = SPI_2linesTxISR_8BIT;6 X6 j$ }9 x8 n
- }
+ H4 e+ o4 c' t5 J; c& \$ t& E - __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码
2 m. e. x6 h: T J% e6 Q重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。& H( B$ ~; J/ u; v" z2 ~+ l
: [* o, ]# N9 P% y
1 J- V" t4 q+ O y+ f
7 c5 e) H! ]) d1 G& n+ ^2 R |