上回向大家介绍了如何使用GPIO口的输出功能点亮一盏LED灯,以及使用GPIO口的输入功能读取按键的状态控制LED的闪烁频率,然鹅,获取按键的状态采用的是主循环查询的方法,这有一个弊端,试想当主循环的循环周期非常长的时候,比如夸张点说要1秒,那就得一直按着按键等到程序扫描到按键的输入引脚后才能放开,这个等待时间最长需要1秒,这是很糟糕的,我可没有这个耐心去等,比如在将一个数从1调节到100的时候,那后果是可想而知的。为此,就有必要引入一个叫中断的神奇东西,程序中的中断,会把正在运行的普通程序或者低级的中断服务程序打断,先运行本中断服务函数内的程序,就好比我们日常生活中的突发事件,你正在洗衣服,突然快递小哥到你家门口了,你得放下手上的衣服先去取个快递,总不能让快递小哥在门口等你把衣服洗完吧。中断还有很多种分类,在普通的51单片机中有三类中断共五个中断源,分别是外部中断0和1、定时器中断0和1以及串口中断,而在STM32中的中断那可多了去了,比方说有GPIO外部中断、定时器中断、串口中断、DMA中断、ADC中断等等等等,每个中断都有它独特的功能,而本次我们需要的就是这当中的GPIO外部中断,好了,废话不多说,接下来我们就来研究研究STM32L552的外部中断是如何使用的。评测内容:' Q: k) @9 @( o, B& _
1、使用外部中断获取按键的状态,并调节LED灯闪烁的频率。' z0 M$ f% X1 c# k5 E* g0 H
所需元件:4 z2 V, a, g- }5 b, s x+ m
1、STM32L552ZET6Q;7 ~! I" | w2 }
2、板载红色LED(LD3);
/ Z1 P+ b% M9 V" E5 a3、板载蓝色按键(USER)。0 }+ Y) T* y1 ~! L n; Y8 @0 T$ K8 _
评测步骤:
+ [! x; o: }1 d% `; A6 F: h1、将按键引脚配置成外部中断模式,打开上回创建的STM32CubeMX工程,将芯片的PC13引脚按照步骤配置成下图所示的设置,第五步为设置程序中的引脚别名,可根据自己的需求进行设置;5 O. v% i( c( g& _& H: B
5 ^; b- o j& r& s z2、使能外部中断并设置中断优先级,按照下图所示步骤及内容设置,中断优先级可自己根据需要设置;
: }, F9 k7 w2 z% g. f, v% g8 L% z- L. A& v2 y& W% x+ U6 M" {$ ~7 \
3、保存工程并生成代码工程。
( K$ _9 I$ n5 {1 V, \5 J4、打开代码工程,发现main.c文件中的GPIO口配置函数多了如下两行设置中山优先级和使能中断的代码;
5 W3 k r+ _: {- HAL_NVIC_SetPriority(EXTI13_IRQn, 3, 0);
, l/ F: f1 \+ a( s* Z - HAL_NVIC_EnableIRQ(EXTI13_IRQn);
复制代码 ! N( V; L$ Y! k' s( G
5、在stm32l5xx_it.c文件中也多了一段中断服务函数的代码;
$ ? Z- y+ J+ t% w9 N- void EXTI13_IRQHandler(void)$ ~1 x7 r- l$ c
- {, f4 D, G; }1 i, j& @
- /* USER CODE BEGIN EXTI13_IRQn 0 */5 I# p# F" @$ `$ S
- N$ b- b3 L. x! J. K. j- /* USER CODE END EXTI13_IRQn 0 */5 o7 p8 S1 K; D5 U X" Y* c
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);" U' c3 t1 a- N! O; D2 f3 t: ~
- /* USER CODE BEGIN EXTI13_IRQn 1 */
9 P4 o4 D% V+ D - ' K6 v/ T! m8 C7 z
- /* USER CODE END EXTI13_IRQn 1 */8 ~# T; a4 r3 m3 @3 n/ y
- }
复制代码 6、跳转到HAL_GPIO_EXTI_IRQHandler函数的实现,该函数的内容如下;
( c, _& @, N; d! c2 v& b, |- void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)8 |6 k2 K9 t. F3 K! n
- {. j" V: M+ ]8 W* ?1 ~' O
- /* EXTI line interrupt detected */
5 D1 E) N9 m/ m, K - if(__HAL_GPIO_EXTI_GET_RISING_IT(GPIO_Pin) != 0U)7 T) B% O5 N8 r' b, M* j
- {
: _/ J6 m% j2 @2 G9 }" H - __HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);7 L$ K- |3 k' F+ |( W6 J% d
- HAL_GPIO_EXTI_Rising_Callback(GPIO_Pin);
3 c+ X; o* J' ^* }4 N6 d3 U - }
/ K% Y. n; a1 W; | - & Z3 G* Y) ?. g# c! P* w
- if(__HAL_GPIO_EXTI_GET_FALLING_IT(GPIO_Pin) != 0U)" Y9 q" ] W' ]
- {2 D* T8 f+ t6 I: E# W8 h1 P
- __HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_Pin);
& N* E1 ^/ X( e3 a; Y9 n( ^! P" \ - HAL_GPIO_EXTI_Falling_Callback(GPIO_Pin);
9 |. B1 f3 C8 W0 c; I& X% ] - }" }) }7 k$ C6 g! V" b- p9 H
- }
复制代码 其中的HAL_GPIO_EXTI_Rising_Callback和HAL_GPIO_EXTI_Falling_Callback函数就是外部中断的回调函数,两个函数内分别有如下注释:1 n# z2 t3 a) z) D$ ?
/* NOTE: This function should not be modified, when the callback is needed,
* i, h, Q5 Z: K the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file* R2 {3 ^" M( t; F! k
*/ /* NOTE: This function should not be modified, when the callback is needed,
1 \! _6 k9 @: g/ }; Z6 `( O the HAL_GPIO_EXTI_Falling_Callback could be implemented in the user file+ g- E- V; U+ ~( g. I" B
*/
8 c% m9 U/ X; ^5 ]5 u意思是这两个函数在用户需要的时候可以在用户文件上实现,实现的内容就是用户需要本次中断执行的内容。
( r" `0 N3 z4 j9 N0 U: S7、回到main.c文件,添加如下函数的实现;
+ b3 L, t5 z( H- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
: L# y5 m! W a- ^2 _4 Z6 M( O/ ` - {" f* _9 [/ t) \% ?
- if (GPIO_Pin == USER_BUTTON_Pin)9 {' y7 l' N& e/ U8 a2 e2 u
- {
3 T( d- U1 ?+ j) [: f - USER_BUTTON = 1;
# j6 u; u5 E; @6 K% q - }+ w6 `( l; |6 M; k+ D) e
- }
复制代码 USER_BUTTON为一个全局变量,在文件开头进行定义:_Bool USER_BUTTON = 0;
' v7 g r9 t/ [7 v* R3 i8、在主函数的循环中添加如下代码;! y1 G9 {: {3 ]/ r/ H7 E) S
一切就绪,重新编译连接并
" i+ W+ I5 a" N! ]( r- /*外部中断操作*/
1 d! j) t6 L0 Z. d: e2 N+ J - //按键检测程序& {- i6 |$ ^6 `# u. C3 K+ C
- if(USER_BUTTON == 1)
/ s0 l/ j/ B/ `: ~9 X, G, |! a - {7 j! b# \/ d7 P4 ^8 d
- u_cycle += 10;
5 M5 G. E2 M3 o! P- b4 N6 H - if(u_cycle>=50)8 O5 I6 q% K4 Q- i0 t" w' y
- {4 u Q ?$ J! T6 } j
- u_cycle = 10;6 E2 g- _9 T% @' d
- }# {! k% `+ N+ U. [# v8 R0 G8 Z
- USER_BUTTON = 0;
! N9 j' [, Z4 D" p. c* n - }
" w% Q' V: Y4 c( E1 q* }9 N - //LED灯闪烁程序/ T$ U+ Z1 y/ J1 z
- u_cnt++;* T% {$ H8 S# w& Y2 U2 v# V
- if(u_cnt >= u_cycle)
: J9 Q, ?! b# F1 r6 N - {. V2 z! J% M8 W: o
- u_cnt = 0;- z" b& [' F3 m- `* J% o k
- LED_R = !LED_R;5 i V! d* m# B% F; I
- }9 b y. Z. K3 a0 t. I- b l
- HAL_Delay(10);
9 B. j2 B" p7 n2 X! `" [ U
复制代码
9 p( F, q5 L" w: x下载到开发板上,按下按键观察程序运行情况,还是跟上回的一样,实现了使用外部中断检测按键对LED的闪烁频率进行调节。, l. Q+ {5 ^' b8 `7 ?3 d3 E
总结:' q# `) |0 I7 T- c% b& B0 U
得益于STM32CubeMX的强大功能以及HAL库的完美包装,外部中断的实现似乎并没有那么难(相比于标准固件库来说真的是简单了不少),只需要自己实现一个回调函数就好了,对快速开发是方便了不少。好了,本次评测就到此结束,感谢您的阅读,我们下回再见。3 s4 r0 @1 r2 J! D1 F
, Z) J% x# w |4 m7 v" ]
) s/ ^/ b3 g0 s9 k3 w
% _* u* T" w( c7 r7 G3 ~# n% O" A0 h* f
* j0 P7 J1 V1 ~! T( } |