虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。- ]- K4 r$ U0 C# t
但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;& |7 t1 d0 k0 [. y7 _
或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。
# m9 U( A _! r: G, E此时就需要用到发送完成和接收中断了。 f; O4 F: Y! V t
9 P- u9 W$ t2 D
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。7 {4 a/ c8 y( Y
# L% [8 ~* ^ e4 N* s
( G: X* s5 D$ f; \( [接缓冲区满中断
6 N; _- y i( j% o/ F新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:5 H- u; Z, C; A# Q. j
- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄4 p t! e& H) w9 O9 f1 O, G
- % ^5 J3 }$ p! k; Z9 `6 Q5 z1 J* l
- void rx_isr(SPI_HandleTypeDef *hspi)7 E; i5 d- m2 W" n
- {
! c# T* t U' S& {1 n8 A - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)9 r2 t* R7 Y% K: ?" F7 {
- {
6 _7 Z: F* R0 }: k4 z1 P# u - u8 data = SPI3->DR;
9 D2 Y5 h, H; }: ^- B - printf("0x%X ",data);
3 |; I% v o* [, O1 P$ y - }: U- z( U# K7 k3 o Z# x2 r6 Z
- }
7 o+ U* V; A4 c+ L. F- G) q - void tx_isr(SPI_HandleTypeDef *hspi)
9 w6 a- P1 g: e8 p6 I# Z - {5 N: i6 A+ o' P; a+ f! @
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
2 I- \- v/ M3 n - {
# o& v' i+ y- @
& M, @+ ^. T" x2 r- }/ d3 h( z! g0 ? A! P
- }$ c7 r- [$ V$ f% g2 B
- void SPI3_Init(void)
5 C2 N5 i# h! h, y1 ?9 F, Z' q - { c7 B; k4 @0 W( o1 s6 b0 s( Y7 q
- HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
3 e6 J t6 r! Y4 z- k& Q - HAL_NVIC_EnableIRQ(SPI3_IRQn);' H4 G7 J5 e! Z" N6 C
+ Z# F+ y8 p) d3 H5 r: f# K- SPI3_Handler.Instance = SPI3;
1 ]; q. O) ?2 ^0 z0 Q% Z - SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
, R+ N+ [/ U4 m7 }' U! { - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
" k. k. i* N: V$ ?# g+ M1 }* t - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
+ d* K' c8 V5 i$ I3 V - SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
' Q! A3 j G- |) p* P6 Y - SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
; @+ t0 { ^( R* V4 i1 m: z- C - SPI3_Handler.Init.NSS = SPI_NSS_SOFT;
/ j* M3 w* w/ C# {$ l - SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
( Y& z- m3 b. L* `! Z - SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
9 i5 _4 j1 P# v. G - SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
4 @, K* c8 l5 ]3 C# K6 Z f - SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;! s; \) H i0 o3 D1 ]
- SPI3_Handler.Init.CRCPolynomial = 7;
{" U$ a2 ]& c' a - SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;# d: Y" ^' @% x8 o2 e. R
- SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
: M- B1 |; O( M) u, L) Z& y7 ]& U - 7 z$ [/ O9 ^+ f. s% y: U' J' }
- SPI3_Handler.RxISR = rx_isr;- m! Q" J0 D) Q# c7 S
- SPI3_Handler.TxISR = tx_isr;2 }5 ^3 r M$ O, h5 g2 D- b/ V
- * u7 |9 {; E |
- HAL_SPI_Init(&SPI3_Handler);
8 R! {5 n3 d1 y8 W8 T - % B( d7 z" ^. [) t, D) X
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
- M1 R4 P4 P6 j' ^; S2 p - __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);
+ E/ c! A+ o ~+ k7 j: K - # ^5 Z4 t+ c5 S+ R+ Q
- }
* P+ G0 V3 y# p- ` - void SPI3_IRQHandler(void)* Y' [% s6 R3 }( r/ s# @! @
- {
9 }4 q4 f4 B3 g i/ m0 X' x - HAL_SPI_IRQHandler(&SPI3_Handler);! u }- A4 D" j9 _& b; @& v
- }7 W+ W. ?& k& s8 m% \) B
5 G. \% D8 T7 t
复制代码
) ]! I& r% @7 V! H" b对应的读写操作如下:3 D0 X6 k( ]4 M( ?2 W+ K
- u16 W25QXX_ReadID(void)/ ]% y% T9 }4 \, ]8 ^
- {
, {, h1 x& f% @6 f$ k. f - u16 Temp = 0;" P" U* S. ~" l( ^* P
1 t' v/ L* G) W$ c4 e- K- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
9 u* l) \- v1 T - SPI3_ReadWriteByte(0x90);//发送读取ID命令% q0 M6 m. q* R$ `
- SPI3_ReadWriteByte(0x00);% ]1 p& O9 W" M/ M. j6 ?
- SPI3_ReadWriteByte(0x00);% x: l0 V; e0 Y6 `( p$ o- ^
- SPI3_ReadWriteByte(0x00);3 H+ _3 ^ u, M' D# a
- Temp |= SPI3_ReadWriteByte(0xFF) << 8;& @/ P- A7 _" k* S9 W
- Temp |= SPI3_ReadWriteByte(0xFF);
9 I% l8 V3 d4 G/ @ - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);/ m+ }. J3 i1 [# K
- return Temp;" A0 I+ r6 O$ i1 Y; Q) K% p
- }0 O: F; o! u6 G4 S
复制代码 & t6 n2 w' m3 q) y/ P% a
显示结果如下:9 N) |+ O( \ Z2 w
' l1 V) V5 J" M1 Y- o8 B) u# _
# |2 T% L! O6 K5 _: h) n' e
& \4 N! n9 p/ m/ y其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。* w# V4 J% O9 p; o4 D+ S) q
\: w% B2 B+ b5 c, k/ l
发送缓冲区空中断
6 {% H6 x) [3 V同样在前面使能发送完成中断就可以了:
g5 D( z! D. ]. h9 D5 E6 _7 Q- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
' `. @$ R4 X# J但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。
* Z7 p7 c* I' @2 X/ I5 }+ ~( u' R4 E% H
而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
2 E0 H7 D4 m/ g( b' K+ @- hspi->ErrorCode = HAL_SPI_ERROR_NONE;, ]: [9 `. t% X U% R' Z& P" J- z
- hspi->pTxBuffPtr = pTxData;3 h2 f- ^8 B: D( b- I
- hspi->TxXferSize = Size;
2 }* |! l4 q! @1 B0 h, p/ u - hspi->TxXferCount = Size;
$ Z- f, T! I2 R: w; L9 k% Q - hspi->pRxBuffPtr = pRxData;' s* Q8 E! c+ r8 @5 B/ N. t3 n$ M
- hspi->RxXferSize = Size;
4 K3 h$ L' h+ t/ o% [) r5 q, T0 w - hspi->RxXferCount = Size;! V5 ]- Z, ]- n) s+ T
# f4 A4 U& e: l" U% c/ n- /* Set the function for IT treatment */
1 }1 |2 ]% |3 p( Z) V - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
4 ~$ q( i& H4 w. W. P( j5 b+ T, O - {) D, Y( F$ m3 X9 B. i
- hspi->RxISR = SPI_2linesRxISR_16BIT;
% S) F5 T- [" ~% G - hspi->TxISR = SPI_2linesTxISR_16BIT;# {8 a, ^' M; K) a5 f6 E
- }4 ^8 [$ p8 O% U/ ]
- else
9 \( W$ i& B/ G5 c1 l) ^* M/ E - {% `, Z- G8 X' |) G& x g$ r3 f) _
- hspi->RxISR = SPI_2linesRxISR_8BIT;5 `$ P% U6 L8 J$ c& a8 C
- hspi->TxISR = SPI_2linesTxISR_8BIT;! Q8 A e6 ~" P9 E9 u' d
- }
: t3 d* s! K' [ - __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));8 V' P7 c5 i7 D$ a# C1 y
复制代码 ) v( s" L+ Z; r( B$ V
重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。# o0 R$ P! Z c3 g1 m' Z8 H4 v
; N* Z Y. b$ h# K' ]: P
至于HAL_SPI_TransmitReceive_IT的具体过程,先埋个坑……(项目现在没这需求了), @+ N, G! g: ?3 {
————————————————
% C& c- i" @% g( b1 a8 c版权声明:小盼你最萌哒* j8 l7 J$ l/ z% B, M2 S
. V7 {+ H. T3 t3 ], t |