虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。
& A. U) @7 G+ u, l/ e6 b: h但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
+ n% d- A8 [0 @! p7 T# D" Q或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。% _5 R/ i8 I. O# O/ p
此时就需要用到发送完成和接收中断了。
7 w" s$ W% C) u1 E
, W' @- a6 O* o1 ] L- N7 `+ v6 k8 ~前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。
1 a9 ?/ }2 z/ u0 _8 B( n4 D8 \6 \) N7 K# S: ^) V
接缓冲区满中断" i& S. L9 @1 P: m9 T s
新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:
6 ~& K' r' n9 E1 l* X6 N
3 a& v6 P6 f/ l8 M; P6 L% \ P- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄
; ~4 V% ]( O& G, z+ e; t7 j - 1 z- a/ o) N& ]6 s# l7 B5 I `
- void rx_isr(SPI_HandleTypeDef *hspi). t7 x- v, X3 k
- {) u, d: B# ?$ |& G+ I5 ]2 m& n( w
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
% e6 ^8 X6 @. c; G9 W& q+ V7 C4 U - {0 X6 v/ E9 o' W/ s8 U+ m& @
- u8 data = SPI3->DR;/ Z4 p \) ~, m; |% V7 q% @
- printf("0x%X ",data);
+ `9 d& b# i2 b$ T1 Z, M - }. R; I0 X1 p3 w
- }& c6 q v# ?! |% f: H
- void tx_isr(SPI_HandleTypeDef *hspi). `# T* _. H$ @, j1 ~8 J: S& c
- { J4 D3 M: b% \1 W0 K8 W
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)1 m) `1 ]" E8 |4 F, q- J& W
- {
* K# _" O9 v( Z& Y1 r8 c5 T
: J1 O G2 h9 _4 Y$ g; J- }
+ m/ z. P {2 k+ g; {0 b; m3 R! I - }- J: y4 u% g. N) V. i& {
- void SPI3_Init(void)
* s! J) E" ~& s2 o* P - {
/ B5 S+ |7 y; I2 y3 E - HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
# q" d9 U6 Z$ O' V$ q - HAL_NVIC_EnableIRQ(SPI3_IRQn);
% Q( D$ N8 b* n4 K4 f; P- [: w - l, @6 n4 C4 D. ~
- SPI3_Handler.Instance = SPI3;4 F7 `1 i3 M& ~8 E+ B
- SPI3_Handler.Init.Mode = SPI_MODE_MASTER;) r+ D0 b* h* s* X3 k7 c+ C% R
- SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
1 V. Q: i1 b9 g; B* J! y - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;# k& H# j$ W) J9 r. Y: }( A
- SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
6 P- G% G& B* s/ ^$ S8 W- } - SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;/ Z4 Z/ n6 A" k- U" W
- SPI3_Handler.Init.NSS = SPI_NSS_SOFT;) P3 g9 T T$ s9 z" w$ Q2 q$ p, E
- SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;5 L$ W8 i* {0 a; i0 a1 m b8 p! B
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;% ^) W# O- L6 B0 J# a
- SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
( a7 e5 H+ u& H- v8 u$ e - SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
# x& q4 y r) }. E+ s0 O. f - SPI3_Handler.Init.CRCPolynomial = 7;8 T2 T9 m' M+ G
- SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
* y3 q, X/ S: a6 V$ Q- N5 ]8 m. ^ - SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
5 c( Y9 g" U7 n - ' J5 G3 f8 _ v
- SPI3_Handler.RxISR = rx_isr;
7 g7 e( [. p9 n4 V6 s1 n! G - SPI3_Handler.TxISR = tx_isr;
! Z) }" [6 A* F3 O - 1 c1 D" r# ^/ k S( z' _
- HAL_SPI_Init(&SPI3_Handler);$ O( `4 e& C/ E) p6 w$ `
- . i- |3 u2 C9 h! P
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);" K, j- {( }" M% R$ e% l) k; E8 p
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);9 }) ~! }$ l4 {
' C& K! Y4 @4 R6 `, ?3 u' B2 \- }
+ i% z/ b4 k' }, w& q0 ? e - void SPI3_IRQHandler(void)! O- U" N! h# M
- {# ^& Z6 U- s5 H8 W: s
- HAL_SPI_IRQHandler(&SPI3_Handler);
( `! P' L7 w* V3 }5 t - }
复制代码 0 z2 L' A4 p" h T; z7 [
对应的读写操作如下:
u; s6 p% `3 E$ B _2 L, k+ d- D5 q7 s% B
- u16 W25QXX_ReadID(void)
* F5 V g# ?8 ~: T - {9 p9 v* `; F9 H
- u16 Temp = 0;
$ N5 r7 x( A, v5 A; V1 M
2 \% q( Q7 [3 x8 O- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
: H% ?: m3 P$ B - SPI3_ReadWriteByte(0x90);//发送读取ID命令
% n3 b% u+ j+ ~1 V7 v- f - SPI3_ReadWriteByte(0x00);4 U) u: ]& O/ s% V
- SPI3_ReadWriteByte(0x00);
) t I9 l& S5 R- j' D; U - SPI3_ReadWriteByte(0x00);2 S! b+ T# a' e3 `1 m0 z0 C3 m
- Temp |= SPI3_ReadWriteByte(0xFF) << 8;6 A( }0 [9 y) F+ b& E
- Temp |= SPI3_ReadWriteByte(0xFF);
I! O, W8 S$ w# p' H8 T3 Q - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
3 U; s B: o: K3 T: g/ w - return Temp;
. { Q* S7 s, D* g- I3 X7 m - }
复制代码 2 g" ^* K" ]& g9 _
显示结果如下:
3 P/ _$ {9 _4 E# @1 m( R
5 `9 |$ t, S( _) ]' R8 j7 r2 |2 k. V- _3 _9 r
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。
! r9 {7 n, k5 D- V) _4 |7 k; h! i% B& D. S$ E7 I
发送缓冲区空中断
5 y; W' r* L: @" |- X O& O同样在前面使能发送完成中断就可以了:' W& b4 g/ e1 T( l X9 P
5 e& S; j7 i7 v
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
( g" [# h+ f) C' ~0 T7 p但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。
# V: G( k8 v# }+ P) R; F* |% \* @4 L0 F: c
而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
# B# }& I2 j2 v$ B& [8 ^) e5 w8 o# k" C' t& F( j" M" h
- hspi->ErrorCode = HAL_SPI_ERROR_NONE;2 U0 |8 L0 o" j6 v/ ]
- hspi->pTxBuffPtr = pTxData; H. G' b" Y7 Y& G5 W
- hspi->TxXferSize = Size;
. X* {! e/ t' I1 s8 i! z - hspi->TxXferCount = Size;
1 I1 u% U1 \5 T c0 w/ N - hspi->pRxBuffPtr = pRxData;
( f0 O" L) u# x2 b - hspi->RxXferSize = Size;+ d% R/ b$ t; r. @% u5 H. d) b
- hspi->RxXferCount = Size;
4 q. _2 u* J+ J# e4 @. {* K. C1 | - 5 T' y" O. N4 X4 J, b
- /* Set the function for IT treatment */
0 I' P3 F- O0 }/ ~1 ?4 \1 P/ n9 J - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
, |+ M# U8 Z$ S- i- E+ e- h - {' T e6 ~: @7 b9 W# P& f
- hspi->RxISR = SPI_2linesRxISR_16BIT;
9 \$ B5 G( ?8 O8 ^4 }& t - hspi->TxISR = SPI_2linesTxISR_16BIT;
& i4 C: {; Z& d- _& r - }; n6 A3 F' H" o6 j
- else! c( M$ n' g M: m9 s# b
- {
2 D, s, Y( g0 O+ w - hspi->RxISR = SPI_2linesRxISR_8BIT;
6 E- |/ |7 `$ Q6 t5 a - hspi->TxISR = SPI_2linesTxISR_8BIT;
# B! H4 Y7 F7 k - }
- R7 v& Z2 u" m( Z7 I - __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码
( i" c ^/ {+ l! \/ m重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。
9 U8 b6 y) f4 g, P& u+ a; N1 Q- c. C H( g: g
# s' ]; w# v% P4 o4 G& h0 M; R, H2 b% E
|