|
STM32CubeMX教程-GPIO输入之外部中断 ( p$ z j, x5 N3 O2 `4 t, o
& M' X V6 }! V) d) x
本篇主要讲述GPIO外部中断输入检测,实际物理输入方式是按键,但是实际上更适合外部设备信号的输入检测,物理按键输入因为有抖动,还需要硬件或者软件去抖才比较可靠。这个例子不考虑防抖的情况。1 @3 ?4 c2 E- s) o- a
软件版本:
3 [, Z8 u% A9 h M) Q9 c4 {* E3 YSTM32CubeMX V4.25.0 , O3 ?$ N; Z" M/ L
System Workbench V2.4
2 P. E5 l) l- y( }2 e硬件:OneNet 麒麟座V2.31 @- P* s/ k6 Q* s/ h. g3 Q
在STM32CubeMX中新建项目,选择正确的MCU型号( Z- B; U% l! ` K4 n1 M- ~
设置RCC和SYS,然后根据板子实际情况设置时钟(麒麟座外部晶振是12M,STM32F103x的最高主频是72M)
根据板子的具体连接设置4个GPIO_OUTPUT (连接到LED)和4个GPIO_EXIT*(外部中断模式,连接到物理按键)。- h* A% d9 i4 L, }5 e
2 _: H$ g/ K2 |9 } GPIO OUTPUT引脚设置9 M6 [$ A2 Q2 d4 Z1 y' [
$ c5 W8 Z9 s* w& {: {. U
麒麟座按键有外部上拉,所以GPIO_EXIT*不需要配置内部上拉,检测下降沿(Falling Edge),GPIO_EXIT*设置如下$ F- A" Y$ x3 `7 R Y3 u% J
T( p5 x+ A+ T& G% ^7 R v LED名称标号我用了1/2/3/4,SW名称标号我用了2/3/4/5,实例中标号也未必相同,但是要做好一一对应关系。8 X! N/ a2 p4 r/ J* r9 u6 I2 m7 r5 a- l
在NVIC(嵌套向量中断控制器)中,勾选EXIT Line2 interrupt 和 EXIT Line[15:12] interrupt 使能中断。右边两个选项设置抢占优先级和响应优先级。此处我们选择默认的,不修改。( r( m! {- W5 j5 f/ p8 f d7 A6 M
8 ]5 r8 b4 I, P7 g6 u$ X" |* [$ m 同样修改Project - setting ,ToolChain/IDE选择 SW4STM32
D0 s' o8 b% f( F! N& }
! y$ \) |0 k: e' d" |" U" I( d6 [
勾选这里。
v" m/ y, U" }7 X4 o
+ {# L0 o4 H5 n7 r2 c$ k2 D5 t- P
生成代码后点击Open Project在Eclipse中打开项目,然后在 在stm32f7xx_it.c中断服务函数文件中,我们可以找到EXTI2 和EXTI15_10中断的服务函数。
) ^$ n$ C- `4 H* {' s, c, I* I5 f: }/ x) Z' M
2 L/ d9 y0 V* I* M- n, a- + P: e5 j5 S6 r( X7 [
- /******************************************************************************/
# U9 C3 A! V! ~7 z3 X& E - /* STM32F1xx Peripheral Interrupt Handlers */
5 I F$ m! `3 q2 O3 R! y - /* Add here the Interrupt Handlers for the used peripherals. */- ^, f! r2 I* ]0 g
- /* For the available peripheral interrupt handler names, */! ~, e' E, j1 R* O" Z$ m; O
- /* please refer to the startup file (startup_stm32f1xx.s). */
6 r6 U4 w w/ b* d, @ G+ b - /******************************************************************************/
7 q% {( p/ Q8 o+ g) k/ [ - /**7 {- ?, i6 G. {, P, q
- * @brief This function handles EXTI line2 interrupt.' R% @' E+ _" k5 T& W9 m
- */
) O5 T. P( U2 ^1 {9 l/ D$ u' L - void EXTI2_IRQHandler(void)) o* x/ }: ?6 j8 P
- {9 U9 b3 {8 g! [- V
- /* USER CODE BEGIN EXTI2_IRQn 0 */0 o2 p2 c$ d$ S* B% L L
- /* USER CODE END EXTI2_IRQn 0 */; I: |+ ?0 r- S$ s
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);# S+ N" r3 y/ @' _+ D3 d5 {
- /* USER CODE BEGIN EXTI2_IRQn 1 */
8 |) I/ ]' q% d$ M - /* USER CODE END EXTI2_IRQn 1 */; I* K e3 @0 ]% S
- }' G- v' _3 V; j6 m& U4 Z* ]: E
- /**1 M7 `4 e1 u. Q
- * @brief This function handles EXTI line[15:10] interrupts." @: T5 @, J+ o7 u
- */
" P9 H$ [( A2 B - void EXTI15_10_IRQHandler(void)
) n+ S; ]4 N1 T3 t - {( I: I$ ^3 c5 v8 h7 `
- /* USER CODE BEGIN EXTI15_10_IRQn 0 */
$ e; [1 j' D. g9 T - /* USER CODE END EXTI15_10_IRQn 0 */3 c2 A0 c( U8 E$ e1 V5 ~0 C4 n
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
. s/ Z v, H5 k8 f/ {! X - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);) b5 w+ y# y; M1 A
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
V$ t6 {+ T% | - /* USER CODE BEGIN EXTI15_10_IRQn 1 */
3 Z* I& E3 j4 d& d* L; D - /* USER CODE END EXTI15_10_IRQn 1 */
6 P$ f! \% E# v- z3 J" d1 ?2 h - }
复制代码
9 t5 o! l3 ?+ D7 x3 p, x
, ]1 R0 a5 s; i" k6 Z: c( M, q右键点击HAL_GPIO_EXTI_IRQHandler 选择"Open Declaration"会跳转到如下代码:
" }( t9 b8 W5 r- _/ u& _! W7 Y+ L1 H# m
! U. u4 [4 T0 J# a, X
/ `. E% p8 g$ M: R1 o! N- , `# b8 e7 }/ R4 h7 O& u
- /**
/ ]4 u) i! I1 N9 g* n- ^6 r - * @brief This function handles EXTI interrupt request.
+ [. C& R; x, g X! J& d; v" [ - * @param GPIO_Pin: Specifies the pins connected EXTI line
' J# d5 R- A( R1 {. ~; P @ - * @retval None
# v. M8 p5 ^; I6 ], | - */
U) m# x' k: Z3 Z5 R; L8 Y - void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) ^0 `5 X, R: l' v) p. y
- {1 U. U' E2 u! L) J l
- /* EXTI line interrupt detected */
& h; u* N; }5 z* C; n% S+ z - if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
2 t9 x% `8 q2 }- J- _ - {# C5 U2 ]: c& ?; n7 J3 I! B9 C$ M. j
- __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);$ [& B. Z2 `$ N7 B. s
- HAL_GPIO_EXTI_Callback(GPIO_Pin);* g7 a3 ]+ \: N1 G# m; U R- V9 j
- }
' d) R9 ~# l# o" e# F) X - }1 ]! q! p0 y, W: q6 p9 {
- /**
+ E5 N0 _; K- p( q, ~3 _" ^ - * @brief EXTI line detection callbacks.' S; d' I( i1 M+ g( n
- * @param GPIO_Pin: Specifies the pins connected EXTI line
: ]' \ T6 P+ V2 r! V& d: G - * @retval None/ m8 q4 f$ b5 u4 Y; w0 H
- */8 [4 }) V. }+ k( j A, V
- __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)3 P3 A2 p& h% |+ u4 h; {9 H8 j
- {
, S9 T, B$ R3 V2 m) Q9 P- ` - /* Prevent unused argument(s) compilation warning */3 v) A6 U' i( t, o/ Q
- UNUSED(GPIO_Pin);
' h7 a. N |# c: n' v# b. I - /* NOTE: This function Should not be modified, when the callback is needed,! {) {* O' @+ v' J( J+ p, D2 N$ G# b
- the HAL_GPIO_EXTI_Callback could be implemented in the user file( t" S' z6 q7 M$ g
- */: V7 W1 y* @' g# z
- }
复制代码 ) V" l/ D) u4 w% ]# i2 y& t
0 f6 x7 t# l9 f( N
上述代码中可以看到GPIO外部中断处理函数首先清除中断标识位,然后调用中断回调函数HAL_GPIO_EXTI_Callback()。往下看这个回调函数定义的时候使用了__weak修饰符(关于__weak修饰符, 可以参看此博文),里面没有任何有作用的代码,我们需要重新定义这个函数。编辑gpio.c(或者main.c也可以),进行如下修改:! q1 K( ?/ p+ g3 e3 x& Z
1 |! j, n* ^$ ]
# Z6 M b1 ?3 b q- ' C4 E) x4 e% a' C. B6 I/ n4 p+ t
- /* USER CODE BEGIN 2 */0 j: p& W j$ ?& i
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) \% V/ v5 j, @9 I
- {
* e: d% s/ l+ l$ k3 N- w8 @ - if(GPIO_Pin == SW2_Pin)6 D; P- {; Z, y* c6 x$ s' k' f
- {
' L# N( j( K/ p. o - HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
6 }- A5 ~4 ~. K6 S* ~) K - }$ ~1 W7 R, O i& F- Q
- if(GPIO_Pin == SW3_Pin)
" @- u5 }; P) e8 S" I6 @7 f - {
j; E6 ?/ n6 S8 X - HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);8 U5 _7 O1 M( a& T/ B! Q
- }
8 Y: ~2 e! {+ D" Z2 a# N - if(GPIO_Pin == SW4_Pin)6 r0 W6 V+ r f6 t) `+ S
- {5 f: n1 c1 C2 ^6 x+ e
- HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin);- x" y/ Y+ W, c3 o
- }; _" f" g4 B8 A) C' T9 k! M
- if(GPIO_Pin == SW5_Pin)" B6 [2 l d' s' r6 N
- {# n; ~; G' o. u" a; e; i
- HAL_GPIO_TogglePin(LED4_GPIO_Port,LED4_Pin); i) y5 d. i. \
- }
. i6 `+ z g) V5 @ - }! R7 J, l, u% Y' e5 {9 G4 V0 Z; Z
- /* USER CODE END 2 */
复制代码 + @$ y1 ?' z, p9 h" G: E4 V( B
/ h0 v: B6 _9 v
然后右键点击项目,选择Properties, Run-Debug Settings, 点击右侧的New,在弹出对话框中选择Ac6 STM32 Debugging。
6 _9 R9 w" Z1 d! A% T: ?
: E K% D3 |$ {! V3 F$ L- O然后任务栏上点击Run图,当然会报错的,原因请查看另一篇我的博客,所以需要右键点击 项目名Run.cfg ,给它改个名字,
8 r9 a, \% G! L- C
8 f7 c6 J" L3 k( `
+ Y+ r0 I6 y4 K' J4 t 然后右键点击项目树里面的项目名称,选择“Propeties”,然后在Run/Debug Settings-选择项目名-Edit-Main-C/C++Application那里点击“Search Project”,然后选择出现的默认的elf文件:
: N# M0 D: W0 b6 W- t2 {$ p) f1 T1 I
3 V. a* A' H, N1 ]0 A; R" p 然后在Debugger-User Defined-Browse 那里选择你自己改名的配置文件:* f* K0 J/ E! Z: T: c3 O! j
& W1 I/ t( `1 n- _ V+ k
然后右键点击那个新的cfg文件,选择"Open With - Text Editor", 进行如下更改:
7 X, A# u, H6 ?% ^5 c5 K* F2 |- ' F* h7 _2 \/ c: L2 l. H5 Q( S
- source [find interface/stlink.cfg] 1 K. D) |3 Q! V9 s
- //更改为 source [find interface/stlink-v2.cfg]) w8 u( K% R& b$ z
- L% ^% h$ @2 @# s; p
- reset_config srst_only srst_nogate connect_assert_srst
8 H* J4 a( N6 R" u, u& B - //这一行改为 reset_config none
复制代码
4 h0 {/ J5 d* s B) U3 T1 L
4 K/ c: i( C3 ]4 G; f/ K' n( bRun一下,就可以了。然后再Run一下,就实现四个按键分别控制LED的开关切换了。但是这里没有防抖处理,你会发现有时候LED会闪一下,或者没反应,其实是很快地点亮然后熄灭一次或者若干次,只是由于速度太快电流很小导致你看不到。下一篇我们会通过使用SysTick中断来实现按键去抖扫描。在实际项目中,最好加上硬件防抖,因为抖动产生的反向电压可能会冲击GPIO导致损坏。9 U \7 [3 ^( h) j) c/ i* }
+ N, l, i& O% s: F, F. l) H; r3 @! K6 Y$ l$ T
d% W2 _- d' c1 ?
3 }/ U: |* c& @( F9 F0 p8 d
7 W/ y% M* l0 x; q' {/ i
6 a$ r) I8 E0 e% X; w4 K% h" B6 j; _6 s& M# z( p: u
; Q( T \0 T' R" l/ r% {
) g! T% w& X( x" n) V) J1 g
8 S; o' i5 b+ V L& L: Z r) J% @+ N2 z
|