虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。
4 s" u9 n3 k2 u# h8 a* v/ N/ z/ `* @但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;
/ [* I5 h" t7 l5 Q# w* ] i或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。" `" _! y4 t v" k; ^" V1 ^" ~
此时就需要用到发送完成和接收中断了。
3 G9 Q2 Z2 q L
3 I# ^! B$ j$ S: N- O前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。) `* Z" b+ c( ]
. }) r" y3 X$ z4 Z5 b" d) C8 A) ]; _4 `7 M1 ?& p
接缓冲区满中断
- ] E" O' \ i1 p& t3 S. O新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:8 \- l6 r$ e& D1 g& z
- SPI_HandleTypeDef SPI3_Handler; //SPI2句柄, c- E1 S, o3 k' n2 f/ B) O
9 G- t" R$ t! Z) r* ?2 E+ B7 Q$ Q- void rx_isr(SPI_HandleTypeDef *hspi)
% n! [0 H/ |7 O( V7 w7 q - {
m! \+ n$ u/ i8 x: T0 l* J - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
* i d! `+ j1 e# Y& J6 i+ a+ [ - {' X9 _9 ]& l* K/ [) ^% O
- u8 data = SPI3->DR;; m& q( g9 w8 r, C
- printf("0x%X ",data);' G: {8 K5 I/ T* [1 w' g
- }
; Y' b, Q+ f3 [5 l3 r: b) l - }% F4 ?, S- r9 H
- void tx_isr(SPI_HandleTypeDef *hspi)
0 _. x9 j) s1 x0 j5 K+ [ - {
5 ]7 i; M6 Z9 A/ i - if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
5 T) s& E$ K7 S; Z: ~ B I - {6 T! @6 {) a f7 o- v
' z4 m3 q, n1 t- }
$ K; ]3 |* R( m1 d# }& ^0 T6 d% o - }; w5 | i7 }, D9 H# s
- void SPI3_Init(void)4 \; N9 t4 q8 Y/ @5 @# ?" q
- {) Z6 Q7 N9 |8 w$ K7 ]9 ]8 G
- HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);' c# O o+ x1 m# I
- HAL_NVIC_EnableIRQ(SPI3_IRQn);/ @9 U1 v0 T, _) \8 s/ M6 S" l% M; o# S
3 x/ X) D4 d: o- F; c& K/ _- n; F7 Z- SPI3_Handler.Instance = SPI3;
; q4 i' V# w* {0 W - SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
0 k/ R+ K& n3 m" ?1 v - SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
" a8 I( M* T0 o* N2 s - SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;( h9 l" t, U. _$ ^7 y [
- SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
2 K* K) o! F6 P( ]9 }0 N. ` - SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;5 D: i# Y. ? {7 Y" c; s h
- SPI3_Handler.Init.NSS = SPI_NSS_SOFT;
- [" {( Q$ f7 a# _- d1 F - SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;* n& h9 Q2 `0 `' \
- SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
- }! U/ |+ w5 O7 E6 S) [+ u - SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;; b r2 a0 o: v% r. |- @" E
- SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
" A4 D$ Y! J" b5 q3 d - SPI3_Handler.Init.CRCPolynomial = 7;
- T6 W8 m9 _: |) [2 b1 F - SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;% R* W2 @ Y& F( z
- SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;. P6 G9 C* P; z
& U, m$ U: a# g& u" D1 j( o- SPI3_Handler.RxISR = rx_isr;
; ~3 I, \& u7 M' m) e8 H7 [ - SPI3_Handler.TxISR = tx_isr;
& v# s9 g& ~5 H: U& W8 J -
) u! e) h# h: t( a* q - HAL_SPI_Init(&SPI3_Handler);
- _" [7 e) {' O' U( I C; ?( ? - 7 K. g1 B/ Y. j, P" ]) {
- //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);, G' \" q2 B/ E( T- b, Q( y
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);
' K; M/ K) C4 I" {5 _! E - ' i% i/ W q( O0 @6 ]
- }6 D; C i: x- L& q+ I
- void SPI3_IRQHandler(void)$ S/ Y* T F/ @( i/ J8 d6 h O! U
- {% J# P* t2 k* o+ ~: y
- HAL_SPI_IRQHandler(&SPI3_Handler);0 J2 b/ h/ Y; Q, s, s2 C
- }: w7 ~; S) b6 G: n$ Z0 ?
- v/ @) S8 D* ^) g
复制代码 $ f9 _. @% P. y0 C, c0 x4 v
对应的读写操作如下:
' p+ } w: Y) X+ c* F- u16 W25QXX_ReadID(void)
6 ^/ M+ E; L' K$ X4 _4 Z& v* k - {) F+ I) L2 r' D/ ~% }: J! A% j
- u16 Temp = 0;9 Q/ ^! L: ^, D m& J5 Z
9 k+ q2 b8 |9 N m; H3 p1 p- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
$ A* i/ t* a5 d7 q$ y9 r$ ] - SPI3_ReadWriteByte(0x90);//发送读取ID命令
* M3 `3 @ r+ J2 j U - SPI3_ReadWriteByte(0x00);
, I4 {, D' D3 J7 h c, A - SPI3_ReadWriteByte(0x00);
9 e* n$ b, v$ }" c - SPI3_ReadWriteByte(0x00);
2 f, W, z3 r& x* K0 T8 _ - Temp |= SPI3_ReadWriteByte(0xFF) << 8;
s3 A" Q1 B5 H - Temp |= SPI3_ReadWriteByte(0xFF);
. R* k) h+ w, i( T4 X$ [7 P( p! j - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
- F/ N( i* i% f" L8 ^! |( I* ~ - return Temp;
2 R/ @" d# ~7 R- a4 l$ { - }
+ E: I$ [6 q2 ~4 G4 w
复制代码 $ `: b2 M' k8 t. X" K3 b5 {
显示结果如下:3 ~' e/ O S) f' v" x+ B3 F( Q& i
. B& M" g9 A8 O' `! l+ ^
2 F9 f$ U7 c s5 @: k( U: }
% u# O& v7 n2 C G* ^9 @% `
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。# c ^, u9 @7 O {+ H& }% T
" ?: ~) l6 m% _2 H
发送缓冲区空中断 _' p. Y# v0 M+ H
同样在前面使能发送完成中断就可以了:7 O% C C( t' c- A2 E
- __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码 4 V7 ] k; m! j( q& E
但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。- F- L7 R8 |3 W7 C$ k* I
- o: ]0 W. L' D而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
7 m8 W9 ]! V4 }, p- hspi->ErrorCode = HAL_SPI_ERROR_NONE;
- d( G* V; I9 I& W7 z; ]9 t - hspi->pTxBuffPtr = pTxData;" w. k3 b: Q& R$ U" H2 z
- hspi->TxXferSize = Size;1 O, M7 O% J) V" `& A; D% n
- hspi->TxXferCount = Size;9 F: ~- O" A4 [' b9 F3 d
- hspi->pRxBuffPtr = pRxData;+ H/ \) i: p! j; ]7 A. |, {8 u
- hspi->RxXferSize = Size;
7 J/ y* E! E! v x' I - hspi->RxXferCount = Size;
+ A1 e- E/ l, J$ t* t8 x - 3 ~. ^6 k7 W3 [( S5 S" K
- /* Set the function for IT treatment */
) |0 p7 e; x" E - if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
0 E% F" z5 s- j- j - {, O6 r* n4 ?/ O& i4 A7 v9 V
- hspi->RxISR = SPI_2linesRxISR_16BIT;, V/ Z- v6 A; d7 d& V5 f
- hspi->TxISR = SPI_2linesTxISR_16BIT;( [% q! D; s/ }' r6 p# P
- }! X0 w9 g" R& a/ q
- else7 R: B4 d6 r0 F
- {
5 p+ s+ |0 d8 D0 ]. E9 Q9 ~ - hspi->RxISR = SPI_2linesRxISR_8BIT;
/ _: a: s8 {5 @) d: J - hspi->TxISR = SPI_2linesTxISR_8BIT;7 P, D; d5 ^9 a0 n p
- }
8 L- b3 b. }9 H5 h5 ?4 K* R - __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));$ Z) A! @: \; S/ j
复制代码 & P' u5 B8 _0 P+ W# l8 P5 Y" T
重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。4 h" r. j$ o/ P+ V3 B4 w* [ r
+ ]$ e) y* h6 c0 j9 u! u+ Y至于HAL_SPI_TransmitReceive_IT的具体过程,先埋个坑……(项目现在没这需求了); c& ]5 v0 V/ s( ?
———————————————— r6 f# n9 U$ v. c+ a1 t
版权声明:小盼你最萌哒
) A; o; z8 p1 P3 _7 x2 N' U: r8 p. R/ f% q( s5 B
|