虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。8 l) a, H* `5 [6 g1 d. \+ [
但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
; p; m/ K; J: {$ }0 j1 f或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。0 {+ H' u( X' P* ?! ^
此时就需要用到发送完成和接收中断了。4 Y$ i0 J! N5 J0 b
$ q* ? ?1 c! F! x6 C1 a前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。
- X f% } l( W3 m" I8 l; u" N+ S" M& b& c
6 z8 ?6 n& t q2 t7 \9 q接缓冲区满中断
7 l5 Y% Y3 [2 R新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:
+ ?2 ~( j2 f3 v$ S: b( g* A& S- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄
3 A0 I) p% t& b
2 ~. j& Y# e* C q6 E2 I; U4 f- void rx_isr(SPI_HandleTypeDef *hspi)
) u1 Z% A! ^0 A# F3 ~2 ~. _8 S - {
* k' L/ v( O3 C5 e$ s0 ^ - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
- a, {1 V4 R* G' M, E" [ - {
9 R8 L5 l# g: l/ O& a# d' Q - u8 data = SPI3->DR;3 m5 @; Y, [+ y; v: C3 k' V; n
- printf("0x%X ",data);
6 O3 f. H' s$ \ - }( w7 k$ v6 l* C5 c y
- }
2 }4 i6 w8 s; w/ ^$ d - void tx_isr(SPI_HandleTypeDef *hspi)
& @# n* c% Q: W0 R! y, l1 f8 P - {& V* E% S, t) j1 I# @ L! p
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1). _. p, g! \, e' L% ?* h
- {
% |* y. |' Y O- B: W
3 L$ q* }7 w0 n4 ?; l- }
- |- b* b* {: p. \" m3 t1 s - }
- ]' x/ }! B5 c, q- T! f - void SPI3_Init(void)
8 G/ R8 j. j; Q( Z# Q/ o/ s - {
6 x2 |+ T6 B2 U. ?: b# u4 T2 }; u - HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
3 B O! N) z" _8 f( O - HAL_NVIC_EnableIRQ(SPI3_IRQn);
$ i' V" _6 R1 J' L: S5 C% f+ B9 M
6 x. ?# r3 X9 P3 f) B' F- SPI3_Handler.Instance = SPI3;4 U6 ]& X0 y. v3 X6 a
- SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
8 f; w8 L4 } p9 I - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;" ` p8 Z1 |# o- G- R, }
- SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;5 {$ t( a# a8 [0 d+ ~
- SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
* C2 K! Y6 v1 Q, ^" F - SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
1 O6 ~+ i1 w! p" l5 y+ c }. R8 n - SPI3_Handler.Init.NSS = SPI_NSS_SOFT;+ Z7 }) E3 X. A$ m
- SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;7 }9 I& E# z+ h5 _1 F
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
- S4 b7 s( A$ T( M( I0 }6 r - SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
- d* ]& H; G4 _ - SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;2 I& l$ `( Z1 O0 \& j( k- i
- SPI3_Handler.Init.CRCPolynomial = 7;5 w: `4 G& P# P4 g1 \
- SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
& D% D$ S) T4 S/ c - SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
2 K/ F- T. A/ A* J$ J - / q1 H& D$ `3 X L M& `" J
- SPI3_Handler.RxISR = rx_isr;
! [- O" E) s8 G - SPI3_Handler.TxISR = tx_isr; ]! h/ ~- q+ i9 _
-
7 X3 X' ~8 i' P) j - HAL_SPI_Init(&SPI3_Handler);/ j- l+ d: s& \( \
, u# K" q- [* P4 c S2 U1 Y' G- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
& @( ^8 G$ E" Y- y% v" E' T" e - __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);8 S; o# g9 i; ]' r4 c. ?' b5 @
# o2 b8 |0 S+ t l/ K- }# Y0 n' m! z" Z ?
- void SPI3_IRQHandler(void)3 Y. Q! Q$ L4 r" w j* k
- {5 i) @; X+ a: P! }
- HAL_SPI_IRQHandler(&SPI3_Handler);
/ p' H9 |3 U* N e* T u - }: E* Q, |( r9 m0 j
3 c" h8 h# d: S ~
复制代码
- Y- s: c6 N3 n" [+ ~: `对应的读写操作如下:) R( e1 L7 E) D# C* y, l
- u16 W25QXX_ReadID(void)- x; g9 j7 {) a; S% }
- {
T7 d, c$ J @/ x - u16 Temp = 0;
8 _& R& r5 R; f. l& a+ r0 O - 7 {1 W2 `# d8 Q9 ]" `* ?( b
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
% y/ A. C" I s8 [# z2 N; I5 z! L - SPI3_ReadWriteByte(0x90);//发送读取ID命令0 I: s8 i E7 M; ]( x' Y
- SPI3_ReadWriteByte(0x00);
5 ^3 C+ ~( F. ?( y - SPI3_ReadWriteByte(0x00);& ~) z% `. ]: _
- SPI3_ReadWriteByte(0x00);1 | C( x* U( o% Q9 H: V8 ~
- Temp |= SPI3_ReadWriteByte(0xFF) << 8;
& L0 u- O( B$ n, u8 s - Temp |= SPI3_ReadWriteByte(0xFF);
C+ r- n1 s P - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
8 W1 W. b' N$ w- u% M! B - return Temp;
& p; f; o8 H# p+ p! p, w - }
2 d/ ?& T. v+ ?8 u5 u: z) B2 G
复制代码
C( J8 v/ f* ^% F显示结果如下:, f& k1 r n& c" G9 z* [
' u5 c$ E. J, {+ [+ ^5 W
+ {: K7 J9 i. w2 A* T+ ^& f$ K+ h! e- A
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。
" r' R0 G w+ g9 ?) n! c! t$ ?1 K* X6 q
发送缓冲区空中断
$ \9 _$ O& m' ?8 T同样在前面使能发送完成中断就可以了:
6 c6 l/ q9 L; ~8 u; a- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
2 y. B g5 x: B8 {" B v- j4 Z1 d. a/ B但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。
# v: w. w( j% l. E# W+ B+ U8 I. U. M
而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
1 |4 X" T" H- A% O( N- hspi->ErrorCode = HAL_SPI_ERROR_NONE;
( [. g, m L1 T6 @" ^9 b - hspi->pTxBuffPtr = pTxData;2 \4 ?& Z& n& S- I) V* s% {+ w
- hspi->TxXferSize = Size;
/ ]4 H* U# t0 u2 ?& C - hspi->TxXferCount = Size;
3 _* e. y1 m& G - hspi->pRxBuffPtr = pRxData;' @8 Z9 l' P0 ?
- hspi->RxXferSize = Size;- _- C5 e/ b4 X1 f# S- F( t
- hspi->RxXferCount = Size;
, F" M# i" b& f6 q - % n5 x8 b$ `$ n2 g# l
- /* Set the function for IT treatment */
5 C% z/ p' d0 @" O/ {9 _ - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
. \7 w( N, t3 \- f9 v5 ]! ] - {
% W: @, T1 t6 N) L8 M - hspi->RxISR = SPI_2linesRxISR_16BIT;
. [# O8 d( h* C4 e# e, F4 c* Z - hspi->TxISR = SPI_2linesTxISR_16BIT;$ c+ {/ ~+ c8 \0 y* A. _9 X
- }
1 v* S# F0 `* n - else
" E- m# w+ j4 Z$ T - {+ d( b- [7 V& H: m5 B
- hspi->RxISR = SPI_2linesRxISR_8BIT;
2 h. y! `0 J( j# T& t - hspi->TxISR = SPI_2linesTxISR_8BIT;
3 q+ Z" t% {8 k, h$ n - }1 l/ f$ k4 x5 a: Q( f. R0 O
- __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
0 C& ~' D; R' F7 L5 {9 d" |+ i
复制代码
8 b- A7 S2 P% K& @5 }重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。
& C3 [& A- p( L9 ^, A; Z# n9 [( F5 X3 T. Z F! X+ {. [
至于HAL_SPI_TransmitReceive_IT的具体过程,先埋个坑……(项目现在没这需求了)$ S) u; O' f( R; }+ M: E/ A/ a
————————————————
5 j8 C& @, [7 i1 S$ C V版权声明:小盼你最萌哒
% F# a1 b( X( u& Z9 K- ?. @. n2 M9 r$ x4 h& m. d, E6 j: [! o
|