虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。5 \6 w1 ]" Q Y8 \3 M
但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
7 O; Q- T8 H* d9 d' B2 v或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。* L0 Y- W% r1 u3 i6 z, j! b" z, `2 L/ c
此时就需要用到发送完成和接收中断了。+ E7 d6 V+ s0 D0 b+ Q) e
* `1 Y4 O, _% u
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。
; t# F* C0 l% ?- J
: R9 L, |2 T9 B6 E# n' t接缓冲区满中断, L, s2 [" D2 A$ K: `, p
新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:( g7 ^ U, ^8 ]' n3 m% s% u9 j
5 \9 p. @# Y) L& q) v
- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄
7 Q/ t& w$ }4 M x# Z8 A# K, I - $ z1 `! p6 X! o; p3 N
- void rx_isr(SPI_HandleTypeDef *hspi)
% E% v D4 s& m - {
~, x( R8 L U2 I% H - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
: v( m2 i9 V0 Q! u9 A - {. i6 ^# f/ Z% ~' v6 `0 g4 H
- u8 data = SPI3->DR;! \+ J' c. J! K6 P% h2 w
- printf("0x%X ",data);( e; R& z1 u, n
- }/ S T9 a. J! W& v# o- a, F" i
- }- Q: p, F2 N# Y. R0 h3 _% a' R
- void tx_isr(SPI_HandleTypeDef *hspi)
( {; e7 S+ \0 U/ l2 p7 |+ ?4 c - {
8 y5 Z5 [5 }5 I - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)7 S2 @; F. Y" v% ^; H X
- {
/ {# A2 ]$ J a& X5 `( h; e
" n" f9 Q7 d) M" o- }# Y, D; Z* ?! d0 r
- }$ ^, X& q" N( F G& E/ }" |
- void SPI3_Init(void)% [2 P6 k, f4 L" y# A1 i
- {
. o' ^$ ]6 M3 h5 b% _, y5 E; | - HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);+ R& [2 \" \3 b3 X8 q4 K
- HAL_NVIC_EnableIRQ(SPI3_IRQn); R* P! h3 V: I. i: y! n$ y
- 4 X7 t- E, U6 N. j# p/ r* q; V
- SPI3_Handler.Instance = SPI3;( w! {$ [8 b# E4 I
- SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
- Z8 D% K7 [, h: u - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
3 W5 v# `1 p' K, i9 _' T- S - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
/ k' @4 \! b! c* Q) _ - SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;. i# ~6 l# q/ y
- SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
4 j% M8 r1 S2 h, L& B1 w3 K - SPI3_Handler.Init.NSS = SPI_NSS_SOFT;
. `9 s, f' z6 o8 d2 X/ S3 C - SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;+ @4 n6 P( ?# ?# \
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
5 B; L) m( x9 K/ } - SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;; Z$ ]& z/ S; V3 h4 d k& w
- SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
% m4 J& M2 Q3 s - SPI3_Handler.Init.CRCPolynomial = 7;) M2 l# U T! S9 B8 k1 P2 |# e8 M
- SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
* }! |9 V& U2 F' f2 E6 l1 { - SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
! o- {) \! R7 L
& b9 N/ Y4 m! m- SPI3_Handler.RxISR = rx_isr;
+ G Y- e: f# c4 V- `: g: l8 _ - SPI3_Handler.TxISR = tx_isr;( `6 d( @0 _- y' j% i; L
- ; Z: l/ ?8 d+ m! T; m |
- HAL_SPI_Init(&SPI3_Handler);
?1 I9 H& H' K# ]# ~( _ v - ( W+ j) o0 q+ [, L1 L; V
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
/ K# W4 z7 b9 z3 T2 V Y9 d: K - __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);
5 e4 c- B) K. a
! _# p |: D& f: k- }9 {6 }1 D9 w$ J' ^% ~
- void SPI3_IRQHandler(void)' U2 G& ^4 h2 s* \# j' T7 _( @
- {
; H9 t7 K9 U" n5 h" Q, n - HAL_SPI_IRQHandler(&SPI3_Handler);
: [: F: E! A; B1 F - }
复制代码
6 a8 f3 D0 |7 i z( S W+ u对应的读写操作如下:
/ ^! p% K9 W9 k/ x4 R2 x* E# o
# { L: M; e, s- u16 W25QXX_ReadID(void)9 P. H# e5 f. X0 N9 q/ v' W
- {
& J `; B ^1 [8 j0 l. g9 c* N - u16 Temp = 0;1 u J. W" q1 c3 u& y. }4 }
- ! r$ y8 P# ~ y, h: Y; ^) c" E
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);! n! z# I# X% p2 i( w N
- SPI3_ReadWriteByte(0x90);//发送读取ID命令( A e; B6 |" r, P6 t m/ u3 D. n
- SPI3_ReadWriteByte(0x00);. C) Z8 e4 a, d5 `& D! z
- SPI3_ReadWriteByte(0x00);% t. A; p6 P3 W8 q2 i0 j
- SPI3_ReadWriteByte(0x00);
+ i6 O3 A& y5 n p* T: M/ W - Temp |= SPI3_ReadWriteByte(0xFF) << 8;0 H! A# X( m5 M- t
- Temp |= SPI3_ReadWriteByte(0xFF);( x7 n, F" U/ T- a& K: F" A- i6 ]
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);; }9 J2 {2 R: D, C3 M
- return Temp;
# X" K/ B3 y' c/ v& g" e - }
复制代码 ( A( H4 M. E5 Z3 U6 [
显示结果如下:
9 t. Q; C. E! r$ H8 y) J% x8 P) G
0 w8 H& ?1 [& n& I其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。" R/ X2 X [; C
7 Y0 [7 _0 Q" k4 F发送缓冲区空中断* `8 A5 \, B; v
同样在前面使能发送完成中断就可以了:$ Q/ z$ L4 o5 |: N; m2 l- K
6 c4 ?) `& Z9 X
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
- x$ t- ~% A6 _6 Y但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。' ^$ U8 w3 ]" K6 N
) O6 u/ @& X6 b9 [- {, k而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
/ ^5 R/ v: T+ q5 V7 Q
' T- b, E+ K1 K- hspi->ErrorCode = HAL_SPI_ERROR_NONE;9 y* g. q, t1 ?& r7 ^
- hspi->pTxBuffPtr = pTxData;. J$ }8 i1 e6 ]' M# R
- hspi->TxXferSize = Size;7 _4 J7 z# j/ a+ V3 D
- hspi->TxXferCount = Size;
[" {/ q( }* {6 n8 ?4 F$ a: s/ Y - hspi->pRxBuffPtr = pRxData;
: ]- S6 G; V, K5 X9 r, t5 d) x - hspi->RxXferSize = Size;. Y' i2 w1 p l/ k# g$ r
- hspi->RxXferCount = Size;* c0 ]0 h2 {! x# m
' t+ X; m( G/ J; K- A- /* Set the function for IT treatment */
5 i$ M3 r# `6 j - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
. M0 A5 n9 Y/ t; g9 o5 @ - {
5 F' P* h5 U9 O1 s - hspi->RxISR = SPI_2linesRxISR_16BIT;
$ E2 r8 b+ a2 } - hspi->TxISR = SPI_2linesTxISR_16BIT;/ e: C& }6 V% I) B5 N3 |
- }" L+ H' @8 t# I' G r9 _
- else
6 y. d# x! J4 c* {6 a( A - {
0 h2 U3 J$ ]$ _4 l$ H1 ~ - hspi->RxISR = SPI_2linesRxISR_8BIT;, X8 O6 X; E* B- ]* |
- hspi->TxISR = SPI_2linesTxISR_8BIT;
; `4 V: j( L* j2 n$ f1 k - }' a7 k8 F2 A8 }: }1 O8 \
- __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码
' | n/ W$ b: M! ^5 J" \重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。
: H" U4 Y4 x6 {* S% R" P+ S5 N/ X8 X' W8 u- R
" |. R, ^9 `3 H' p2 K# n
( J7 w6 p$ i7 H# i+ f |