|
STM32Cube HAL库中断处理机制,回调函数实现原理 STM32Cube HAL出来六七年了,还是有很多初学者没有适应,今天就分享一个读者问到的关于中断处理的问题。 很多人都知道STM32CubeMX这套工具的一个目的:减少开发者对STM32底层驱动的开发时间,把重心放在应用代码上。 但是,STM32CubeMX只是生成了底层驱动的初始化代码。所以,我们还需要掌握:应用层代码如何调用HAL库函数(API接口),以及HAL库中断处理机制等相关知识。 HAL库牵涉的内容较多,下面简单描述一下HAL库中断处理,以及相关的回调函数。 1 HAL库中断处理机制 之前使用标准外设库开发时,中断程序(函数)由我们自己实现。 而HAL库的中断处理函数是按照HAL处理机制来实现,如USART1,统一由HAL_UART_IRQHandler来进行处理,如下图: 其它大部分外设(TIM、SPI、CAN...)中断都类似,HAL进行统一处理。 也就是说,HAL已经帮我们把中断处理函数写好了,我们只需要调用相应函数来编写应用程序就行了。 HAL_xxx_IRQHandler里面做了哪些处理? 我们以STM32F1的HAL_UART_IRQHandler为例: - <p class="MsoNormal"><span lang="EN-US">void HAL_UART_IRQHandler(UART_HandleTypeDef/ E" \) T- x4 p. g/ t5 x! W
- *huart)<o:p></o:p></span></p>
* P0 r$ Q- g! @
1 x4 i/ @; O* m5 m6 j1 W( Q/ P- <p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>. D$ R, h" V {5 [; A
- 1 y" w' R: f$ [/ q
- <p class="MsoNormal"><span lang="EN-US"> 9 P, L! x- }- G. @
- uint32_t isrflags =1 `) W P( u# ~1 G! ^& q0 Q) k3 R5 o1 G
- READ_REG(huart->Instance->SR);<o:p></o:p></span></p>
5 h6 @# C" Y. \7 T! d! t - / h$ C7 z) a# s$ v
- <p class="MsoNormal"><span lang="EN-US"> $ H$ y( p( g3 ^$ [
- uint32_t cr1its =) u: {# b( c* Q7 h# ~
- READ_REG(huart->Instance->CR1);<o:p></o:p></span></p>
$ x! A8 L+ I, _1 _( y$ M
8 \) R, e# F8 R; `7 E3 N1 T/ }- <p class="MsoNormal"><span lang="EN-US">
8 C) p0 U1 S, ` @8 k - uint32_t cr3its = Z M! V0 o5 E2 ?
- READ_REG(huart->Instance->CR3);<o:p></o:p></span></p>
& q4 n- a1 @) z" A2 J - 9 R z& w9 H7 d6 H
- <p class="MsoNormal"><span lang="EN-US">
' @- F7 N# M5 Z$ i H - uint32_t errorflags = 0x00U;<o:p></o:p></span></p>
: @4 m/ B. L7 E$ m3 y0 m
$ ~% H& r% `, {) ]# c: z- <p class="MsoNormal"><span lang="EN-US"> 8 }- T, D, [4 `6 l" I
- uint32_t dmarequest = 0x00U;<o:p></o:p></span></p>3 z8 f, T4 ^. q+ l& M6 T+ w
: c, s! k' Y; F6 }. t& n- <p class="MsoNormal"><span lang="EN-US"> </span></p>
) h D; H m) K5 A! V) a
8 v0 Q$ c% u ?' ^( D9 x ~: `+ p- <p class="MsoNormal"><span lang="EN-US"> /*
/ L Y' a# k% C' n+ d0 H7 T - If no error occurs */<o:p></o:p></span></p>
4 R9 L6 Q& \! i; C! @# g9 J6 Z
4 k6 ^3 K( H" B; U" ~" `# K- <p class="MsoNormal"><span lang="EN-US"> 4 N9 y# R5 k8 L, k8 k7 |
- errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE |/ u% A$ M6 n: m; p
- USART_SR_ORE | USART_SR_NE));<o:p></o:p></span></p>
. x, C& }+ Y; z+ Y - : s$ q3 }; F: R7 N1 ^
- <p class="MsoNormal"><span lang="EN-US"> 4 M, L! ?3 c6 q6 y" K. M+ \
- if(errorflags == RESET)<o:p></o:p></span></p>7 T# M7 J; u' }" M" U8 `8 B
- D, \7 a2 i' L6 e/ l# n7 R- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>, |# A1 J7 {& |" p: |+ Q% ^; `
- % B$ X$ ^4 Q! _
- <p class="MsoNormal"><span lang="EN-US"> & v" P0 Z6 Y7 _, F: R
- /* UART in mode Receiver# P( a: r9 {2 }; [+ X
- -------------------------------------------------*/<o:p></o:p></span></p>" G# m# W) M* ]& {2 H( c
- * \# o( }: ~$ C) i: m
- <p class="MsoNormal"><span lang="EN-US"> ( x/ J2 o+ a5 F+ d* V3 }9 E0 i; x
- if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its &
' a! k2 y. P' a, [! f - USART_CR1_RXNEIE) != RESET))<o:p></o:p></span></p>6 X& {! p2 h8 D$ Y6 n0 h% u! S7 R
- # y$ ]# }1 [, J# y
- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>
/ d' c# r. s( j5 W6 o3 S9 S; X - & S+ P/ d, ^% v1 j" I$ e
- <p class="MsoNormal"><span lang="EN-US">
: E8 e: f% ^2 O1 q - UART_Receive_IT(huart);<o:p></o:p></span></p>
8 C/ F# U% _4 X C0 ? - 8 u' U- C" M+ B5 t1 |- c& o
- <p class="MsoNormal"><span lang="EN-US">
7 R, N# W6 b, S5 Y" s( Z0 ^ - return;<o:p></o:p></span></p>
: J Z' F l9 w$ m" i4 y - , }3 J. J5 F- p
- <p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
. w% _/ D' @. z1 `$ A G - ( N. { z% e1 o: k+ Z
- <p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
* L* B' h! w) c6 O/ X3 k4 }# R - ) B' Q$ f+ A2 X( Q; P
- <p class="MsoNormal"><span lang="EN-US"> </span></p>: g4 L) P; p" h1 w9 p
6 R; G: L) b2 c6 s4 ?! g- <p class="MsoNormal"><span lang="EN-US"> /*
6 q5 E8 t0 Y; Z# J - If some errors occur */<o:p></o:p></span></p>
0 R Z2 I4 O O
" x7 Y- }5 d2 O( ~; ]# y) Z- <p class="MsoNormal"><span lang="EN-US">
% [& W! ^. W# R# p$ @9 Q - if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) !=4 S* D/ {6 G5 w/ `/ ^8 b. w
- RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))<o:p></o:p></span></p>. P" d B+ T2 ^" h; b. ~
- 3 Z$ F. A3 ]7 A1 H0 N- S
- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>
2 [$ Y5 @; a- b4 G - 7 Z% j# T8 K$ t8 }4 y- v$ T
- <p class="MsoNormal"><span lang="EN-US"> /*<o:p></o:p></span></p>
! @0 h- D6 N5 G- v; ^
3 ^* W% P! U6 |0 Z, V- <p class="MsoNormal"><span lang="EN-US"> ·<o:p></o:p></span></p>! c8 V7 D5 K) C. j
- , p/ W3 a* K, v5 d; ^0 U
- <p class="MsoNormal"><span lang="EN-US"> ·</span>删减了部分代码<span lang="EN-US"><o:p></o:p></span></p>7 b; P$ l( y; N- A
& T/ E! H: p5 a* P- x& G+ a9 F$ Z- <p class="MsoNormal"><span lang="EN-US"> ·<o:p></o:p></span></p>8 V6 g% o/ J% ~: y( P' k$ f a
- ' t/ Y8 r( u1 ]+ k% U. D3 V, I
- <p class="MsoNormal"><span lang="EN-US"> */<o:p></o:p></span></p>& g. h+ g$ U; S# w5 `9 Q
- ( |, s! s* c1 C6 ^% s; V
- <p class="MsoNormal"><span lang="EN-US"> }6 ~, V1 h& g9 G" l9 V% g' l
- /* End if some error occurs */<o:p></o:p></span></p>
* ~+ W5 L2 W8 @# i
$ `( @" b) g4 x! E: C- <p class="MsoNormal"><span lang="EN-US"> </span></p>
t x% D! \& e9 U: S
2 ?+ i x0 ~ M/ M- <p class="MsoNormal"><span lang="EN-US"> /*
( _* J9 A0 y/ d+ }( y) U, w6 L0 r - UART in mode Transmitter ------------------------------------------------*/<o:p></o:p></span></p>
/ g$ U. W& p/ t* L; v* I1 {
( E& g" D7 T& a- <p class="MsoNormal"><span lang="EN-US">
. r) k i+ l. S. I; a# v/ ]* H - if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its &4 h1 W }; J; K& o/ n
- USART_CR1_TXEIE) != RESET))<o:p></o:p></span></p>
6 ?9 J* D+ k3 j* k/ @ - ' `( W9 [: _8 Y* C0 r* q- x
- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>
" i0 E6 a* {) J# l. p0 f - 8 b$ `: `2 I. l/ ~. r& V6 W! X
- <p class="MsoNormal"><span lang="EN-US"> - F) d" e! H- j0 N5 [" o3 u6 g% k" v
- UART_Transmit_IT(huart);<o:p></o:p></span></p>
9 A, @. y5 u4 z& Y
P+ }) F) m- I0 E- <p class="MsoNormal"><span lang="EN-US"> " a6 G. S) v1 i. x6 G6 J
- return;<o:p></o:p></span></p># z! ^1 }" i5 u" A2 V
- 3 t! k' t5 }# @4 C
- <p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>4 b: c* J. Y( e0 _ T
- - A# V8 K1 V# E0 f3 V
- <p class="MsoNormal"><span lang="EN-US"> /*1 P; }% c3 Q: }
- UART in mode Transmitter end --------------------------------------------*/<o:p></o:p></span></p>3 X+ v- K- D& Y; E8 K3 j# _
$ z! X! }4 j0 w+ Q0 `- <p class="MsoNormal"><span lang="EN-US">
" s, b, D# @' h; f - if(((isrflags & USART_SR_TC) != RESET) && ((cr1its &8 X6 P. ?9 N. f f
- USART_CR1_TCIE) != RESET))<o:p></o:p></span></p>
} A2 p: }4 K. w- ^3 u- }' d - 6 |. u+ O7 t- I4 Q& Q2 V( z
- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>1 k T7 ]3 d! _: T2 x5 [2 f( Q
- ( h% t7 [! a- k/ F. n- t: X$ {
- <p class="MsoNormal"><span lang="EN-US">
. z; Q2 M. p" x6 R/ V7 g; m - UART_EndTransmit_IT(huart);<o:p></o:p></span></p>. v2 ^5 N; t4 i9 Y
6 M+ Z% R; H$ v1 Q6 Q- <p class="MsoNormal"><span lang="EN-US">
$ F8 v) \4 h! C2 k- j - return;<o:p></o:p></span></p>
7 Y0 E; w% Q$ F$ f - 8 @2 {* F3 J# N3 n* i, n
- <p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
% y( i7 e& Y' s: v2 S- m - + E+ n, k0 {* Z! c& K
- <p class="MsoNormal"><span lang="EN-US">}</span></p>
复制代码
- d2 [! B5 `. `' H7 h2 n 其实,大家认真看一下代码应该能明白,这些和我们编写的中断处理函数是不是有类似之处? 这是无非就是接收中断、发送中断、错误中断等一系列处理。只是这里又进行了再次封装,比如接收中断UART_Receive_IT。 当然,这个UART_Receive_IT接收中断实现方式又可能存在不同。像F0、F1...就是直接调用这个接收中断函数来进一步处理。 像L0、G0...是通过执行指针函数RxISR来进一步处理。G0的接收中断处理为:huart->RxISR(huart); - <p class="MsoNormal"><span lang="EN-US">void HAL_UART_IRQHandler(UART_HandleTypeDef
, {: C7 e3 D: j( f, o - *huart)<o:p></o:p></span></p>; b# n+ Y2 Z% C( i e: [0 Q' O& A
- ; J( X3 F- c2 A" f+ N
- <p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>- s7 b1 Z- c1 ` z: a
- % f! m3 \& J! ?
- <p class="MsoNormal"><span lang="EN-US"> //</span>删除了前面代码<span lang="EN-US"><o:p></o:p></span></p>2 B0 W$ q' H! N O+ m
- 5 }! X2 _. G* K. S1 m
- <p class="MsoNormal"><span lang="EN-US"> /*
. F1 F0 c! {; X9 A0 z' S* j2 X - If no error occurs */<o:p></o:p></span></p>
& N% P# Y& ~1 }6 u0 w, L2 ^2 P0 s - 3 E6 N/ n( i1 y
- <p class="MsoNormal"><span lang="EN-US">
8 B, D2 P Y2 I1 ^1 n$ Y) q - errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE |
, J! c2 i3 ^& t - USART_ISR_ORE | USART_ISR_NE));<o:p></o:p></span></p>
1 c4 z% C* y$ h6 I0 S2 S
, X+ D) ~" ~6 w( j+ M: P s- <p class="MsoNormal"><span lang="EN-US"> if8 j; L, O/ t3 A* K& T3 V
- (errorflags == 0U)<o:p></o:p></span></p>
* x1 f6 `; b( f) @; K! S/ _0 v$ A8 t - 4 V7 @' i5 A( _9 }& s8 @+ U
- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>6 P, D) w6 p Y# q
" U6 u. \# ^) c) d9 |- <p class="MsoNormal"><span lang="EN-US">
4 ?! l1 S' }2 f$ A6 { - /* UART in mode Receiver
+ [4 }5 j8 A' ~6 L% K6 _9 v - ---------------------------------------------------*/<o:p></o:p></span></p>' o; e* }7 \+ H4 l
- 1 _. [1 o! M* Z- w$ p6 R2 U
- <p class="MsoNormal"><span lang="EN-US"> ' L* {1 I, L: ]' ~ h8 P' M W
- if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)<o:p></o:p></span></p>/ V! f* |/ w( R( E+ n. s: x6 ^
- # s; h6 E1 A9 G% ]# s, N
- <p class="MsoNormal"><span lang="EN-US">
' V8 N) a; N( _+ R2 a* Q7 U3 y+ b8 H - && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)<o:p></o:p></span></p>
. e4 [$ h* W8 Z5 ]
. D& S, Y$ m) M$ U6 i$ D- <p class="MsoNormal"><span lang="EN-US">
! U# T4 w; V3 Y3 L - || ((cr3its & USART_CR3_RXFTIE) != 0U)))<o:p></o:p></span></p>
7 \% u; D7 }9 N9 |. d ~ - $ E3 }' }$ s/ m( J
- <p class="MsoNormal"><span lang="EN-US"> {<o:p></o:p></span></p>) D8 G3 F W/ D' u; C6 n5 `
- 5 t( R2 W* t* q0 j$ q' y9 g) Y) e8 G
- <p class="MsoNormal"><span lang="EN-US"> / I, `6 p9 U! V: G8 D: A
- if (huart->RxISR != NULL)<o:p></o:p></span></p>
. R# O$ O- d$ V8 c9 H
8 v5 D. t, N: q: R, t0 d- <p class="MsoNormal"><span lang="EN-US">
3 P" ^% I: [6 e) x" C - {<o:p></o:p></span></p>
- K9 p6 W7 v& z- ] - ; y+ o# s7 h' Z$ ?0 |, l; j
- <p class="MsoNormal"><span lang="EN-US"> 1 F5 ~* Z/ M h: e+ `. q
- huart->RxISR(huart);<o:p></o:p></span></p>" g( t7 d; U4 u: a) m
- 8 s" \7 J! b& N1 I& R; S; o4 B/ Q2 f" D
- <p class="MsoNormal"><span lang="EN-US"> . d. P0 I& N1 n6 c x: Y" O& p
- }<o:p></o:p></span></p>& [( d, M2 H/ s& }( p/ x) d( C& n
! `% l2 t6 d3 [3 O7 h# a3 y- <p class="MsoNormal"><span lang="EN-US"> * r; H( i0 ?& O2 e6 X
- return;<o:p></o:p></span></p>5 N# F, T- O* i3 d, Q8 Y8 P
9 E" {/ T! b2 V# a. R- <p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
. p5 \8 y; X! H
' T" R- s; s& m- <p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>7 n$ _/ w! S2 b, W/ ~
- ' |! }2 _/ M1 Q+ \# \2 ^2 d, v
- <p class="MsoNormal"><span lang="EN-US"> //</span>删除了后面代码<span lang="EN-US"><o:p></o:p></span></p>' D) W* s8 N8 T2 g5 s2 N
& f; j5 @4 s% ^7 J/ I" G1 ~- <p class="MsoNormal"><span lang="EN-US">}</span></p>
复制代码 看了上面USART中断处理的函数,大家有没有得到什么启发? 其实,HAL库里面处理机制基本一致,只是实现方式上有所不同。 如果你摸清楚了HAL库基本原理,相信阅读HAL库源码,或者使用HAL库编写应用代码不是问题。 2 回调函数实现原理 在HAL库中存在大量类似HAL_XXX_XXXCallback这样的函数,这些都是回调函数。 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。 回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 ---来自百度百科 HAL库中断处理使用了较多的回调函数,还是拿UART接收中断来举例说明。 初始化配置好UART中断接收,如果有中断请求,就会执行回调函数HAL_UART_RxCpltCallback。 看上面回调函数的定义,通过特定条件调用『回调函数』,这里触发的条件就是中断。 3 扩展说明 这里也简单说几点: 1.初学者想直接使用HAL不是不行,需要有一定C语言功底 针对大部分初学者来说,是不建议直接上手HAL。但是,有部分C功底较好的,还是建议直接上手。 2.学HAL,建议参看官网例程 很多人不知道如何找资源,我不止一次强调,官方的才是最好。在HAL库中Projects目录下就有很多例程Examples。 3.我们追求效率,可以HAL库源码 如果你想修改HAL库源码,允许修改少部分。如果要大量修改,还是别折腾了。 4.实际项目需做一定修改 STM32CubeMX仅仅是生成初始化代码和工程,你实际项目中一般都有自己的软件架构。 特别是项目越大,软件架构就需要更加规范。 比如:生成的gpio.c文件名,你需要修改成bsp_gpio.c. 再比如:函数MX_USART2_UART_Init改成MX_DEBUG_UART_Init. ------------END ------------ 文章出处: strongerHuang
" e2 o/ V- e& K+ r+ ~ |