虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。( I; F* D/ A# l" M0 Y; B
但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
, I4 J/ t+ [5 d' K7 C @或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。: i& }% p! W; H; N2 x& Y+ z9 z
此时就需要用到发送完成和接收中断了。; [' c$ H0 C2 b: ]6 w
6 E$ ~4 T1 e4 s+ {: `
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。
; Z) [2 F. X+ Z1 \) a+ [% L4 F" w$ T
接缓冲区满中断
, L1 ?! l6 Y \; Z新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:( ~2 M0 V3 _; [$ j) ?- } Z( _0 \
8 A3 Y7 ~9 y7 X% t; G3 ]$ F; U- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄: v3 h, }0 C2 o$ r) k5 h
+ m0 z3 j/ x" O7 ?" @: N- void rx_isr(SPI_HandleTypeDef *hspi)
$ F2 B$ R1 o, H/ r+ Y4 @ - {
6 a4 }0 l0 U: M- b; |5 u - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
1 Y5 M4 |. l: @% ] - {2 ~/ E- h7 r' h9 H" q
- u8 data = SPI3->DR; L6 }) `6 k& Y" U, B3 O
- printf("0x%X ",data);* s6 {5 m) T; C S2 V
- }
5 m/ w! T \# M9 j - }* I/ C8 T* E7 R# S
- void tx_isr(SPI_HandleTypeDef *hspi)) v. ~1 D b# g, h4 [
- {# _* E9 d3 y+ _2 P
- if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1) k' u+ M1 b4 N; K
- {
$ Y* L% z* a, S) Z% W
, G U! @, X- `# n* z- }% A4 w8 C, P/ `$ m6 L4 e+ F9 I
- }
" z4 B3 n- X$ n1 N( E4 F* D% \ - void SPI3_Init(void)6 T6 H6 k2 k5 r2 e6 f- e( _
- {5 W% n( N5 p5 }% Z* H$ m+ L+ w
- HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);+ O6 |$ ^- M( ^; z$ f% o! r% f
- HAL_NVIC_EnableIRQ(SPI3_IRQn);
" V$ r* L0 @* ]. o( M
+ |: I7 J3 T, `, Y4 q4 T- SPI3_Handler.Instance = SPI3;- t- C9 v5 X! P- K* Y0 }
- SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
7 x1 b1 g! ~- @2 Y+ Z+ u( ?! [) ^ - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;) W7 L" \% m9 |3 t7 i( i" u
- SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
3 x% P8 u- {6 h6 p7 t+ r: t - SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;2 {% W0 Y y1 g2 c" C$ \3 ~
- SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
3 k* @3 } n( L - SPI3_Handler.Init.NSS = SPI_NSS_SOFT;
+ `. c) z. w$ q9 X - SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;# ~# r% s: S( a( ^9 X
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;- b) z! z" l. ?
- SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
! S9 Z; b+ s+ w! c6 Z - SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
0 E; r0 a& L0 u) o2 {' g3 ] - SPI3_Handler.Init.CRCPolynomial = 7;
, \4 U% x! ~( |* O" k0 ] - SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
; V% ?7 X$ A$ j$ l6 @ - SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
! k8 {" E/ q; e% D
q0 b1 Z) {! a W- SPI3_Handler.RxISR = rx_isr;! K& b3 u$ `4 S7 ~; S% h
- SPI3_Handler.TxISR = tx_isr;
, o9 p0 z/ {4 ^ - 1 i# W& y" H# X( V
- HAL_SPI_Init(&SPI3_Handler);
+ q0 ~1 i U7 P8 y7 O/ H - - `0 u. ]8 W# A1 I
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
- z K7 T( J- c: L7 R - __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);
: I' G; d( a5 h* d - ( b9 k; @; Q& T
- }
- R' E; z7 j3 c3 g7 G* E* ^( h6 ^ S - void SPI3_IRQHandler(void)
. b, N9 Y/ r) F& z - {; K" T2 k! p. J; A3 v
- HAL_SPI_IRQHandler(&SPI3_Handler);
q0 `: R: b5 Q: l. w* J5 ] - }
复制代码
# L6 H7 L" _# n: \) i对应的读写操作如下:
_7 n, S2 z# D/ r( M m
; M1 s. a2 w. J& G- u16 W25QXX_ReadID(void)
. E4 @3 u3 B% |1 R9 X# _. S H+ U - {
' t: y: y7 X0 p5 c - u16 Temp = 0;
8 a' K% @: L1 I& K) [, s+ @" ]
, m- |5 o: N: t3 D& [- G- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);& L9 w& j% f$ b0 Z( R* |
- SPI3_ReadWriteByte(0x90);//发送读取ID命令% t, W2 _4 l# l8 _/ u
- SPI3_ReadWriteByte(0x00);
1 {& E' s$ U4 P2 Q' ?% i - SPI3_ReadWriteByte(0x00);. k9 u- H2 z7 {
- SPI3_ReadWriteByte(0x00);
5 ~+ j+ B5 x, u8 G5 K; B/ P - Temp |= SPI3_ReadWriteByte(0xFF) << 8;* b, d. X5 t B3 s/ j0 H* s
- Temp |= SPI3_ReadWriteByte(0xFF);
) ]% j% Y) P1 B& }2 i - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);, S( t, v' a) c# ^/ t: R% S+ W& b9 S
- return Temp;! l3 ^4 \7 X$ M- h9 y) h/ I# |$ d1 S
- }
复制代码 7 @- B+ p+ \; Z, R
显示结果如下:
g* n9 k3 s$ k. }4 m/ K0 \) Y, N- x& p' M
`* ^6 F+ u# Q) p/ h! q0 ^
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。
# [8 v5 D) C2 A" } h9 X
( i6 U& Z; \, s1 @) i发送缓冲区空中断* g) |6 I% S5 `3 \5 \
同样在前面使能发送完成中断就可以了: A: p5 D8 z. f2 `
4 K) R* F- G2 k( G2 `$ N! I- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
7 Q1 x. Y5 Z" l- S# P) I- L但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。
- E3 @- V' V& s
: Q; I! r8 U) Q( M, p' e而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:* z4 ~3 a4 r0 t) ]3 {! X( n' s
F! p( n$ P6 Z @/ K; _& `- hspi->ErrorCode = HAL_SPI_ERROR_NONE;9 P1 R) g+ P. `) B! _8 [4 C5 e
- hspi->pTxBuffPtr = pTxData;) w8 p) ?- |" p' U3 {' ^
- hspi->TxXferSize = Size;
6 o8 q; }' m5 u# d - hspi->TxXferCount = Size;, z! Z1 s) v. i1 T0 ?
- hspi->pRxBuffPtr = pRxData;
4 l* E: M; V g7 ~3 l$ ? - hspi->RxXferSize = Size;" l& ^0 _% n- g- \/ } g! D5 N
- hspi->RxXferCount = Size;5 U2 E: `% r2 L$ U+ D
1 O) q: b) d9 ]2 w! [- /* Set the function for IT treatment */
8 I9 T7 f+ Q: m, N8 e/ r& V - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
+ K8 G& w( J5 ^5 b; Q - {7 o: J9 \2 M3 k" Y
- hspi->RxISR = SPI_2linesRxISR_16BIT;
' R# O0 A9 c, X! p# y - hspi->TxISR = SPI_2linesTxISR_16BIT;
# _: t" `! h F7 W; r# P1 c - }5 H I/ h- }+ i) a
- else
3 ?' y+ \. \8 p! } - {& Y1 Q7 _- a1 A* G
- hspi->RxISR = SPI_2linesRxISR_8BIT;' l/ U8 O" D7 k! _5 K8 X7 P) ]
- hspi->TxISR = SPI_2linesTxISR_8BIT;
; c' ^+ r6 P' y' v2 k - }
7 [; e* s# k7 V4 g- Y* s - __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码 1 o4 i1 [' [ z0 V. }5 J
重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。
0 |3 g( `+ w/ t& I7 r5 ]9 V
. P% c: B( `; u3 ~+ i4 `1 p8 ^+ C- M
% J) t( b( w- r3 f7 k9 n, v9 d2 I4 A1 J
|