上回向大家介绍了如何使用GPIO口的输出功能点亮一盏LED灯,以及使用GPIO口的输入功能读取按键的状态控制LED的闪烁频率,然鹅,获取按键的状态采用的是主循环查询的方法,这有一个弊端,试想当主循环的循环周期非常长的时候,比如夸张点说要1秒,那就得一直按着按键等到程序扫描到按键的输入引脚后才能放开,这个等待时间最长需要1秒,这是很糟糕的,我可没有这个耐心去等,比如在将一个数从1调节到100的时候,那后果是可想而知的。为此,就有必要引入一个叫中断的神奇东西,程序中的中断,会把正在运行的普通程序或者低级的中断服务程序打断,先运行本中断服务函数内的程序,就好比我们日常生活中的突发事件,你正在洗衣服,突然快递小哥到你家门口了,你得放下手上的衣服先去取个快递,总不能让快递小哥在门口等你把衣服洗完吧。中断还有很多种分类,在普通的51单片机中有三类中断共五个中断源,分别是外部中断0和1、定时器中断0和1以及串口中断,而在STM32中的中断那可多了去了,比方说有GPIO外部中断、定时器中断、串口中断、DMA中断、ADC中断等等等等,每个中断都有它独特的功能,而本次我们需要的就是这当中的GPIO外部中断,好了,废话不多说,接下来我们就来研究研究STM32L552的外部中断是如何使用的。评测内容:
3 W! Y4 g3 b% P9 a8 E1 {3 V0 z& @1、使用外部中断获取按键的状态,并调节LED灯闪烁的频率。
8 z$ G6 o1 p7 n; @* e2 Y* k所需元件:
5 s# S$ `3 \5 u0 B; T$ U1、STM32L552ZET6Q;
3 k, }' o1 {- t2、板载红色LED(LD3);( ~- E( Z6 a4 j' x% I
3、板载蓝色按键(USER)。
Q' N* I6 H1 m2 \: f; P评测步骤:
% z5 s" Y9 F0 E6 O# {4 |( s; C1、将按键引脚配置成外部中断模式,打开上回创建的STM32CubeMX工程,将芯片的PC13引脚按照步骤配置成下图所示的设置,第五步为设置程序中的引脚别名,可根据自己的需求进行设置;
6 P$ ]9 ~6 ~: j/ t' u
* v" |, Z" L' d4 r2、使能外部中断并设置中断优先级,按照下图所示步骤及内容设置,中断优先级可自己根据需要设置;
# ^1 \6 ^7 u1 {6 M Z
8 ?# o- @8 J9 x% I5 g- z5 ~9 v3、保存工程并生成代码工程。+ N' x! y8 ]8 m j V5 P |% @. P
4、打开代码工程,发现main.c文件中的GPIO口配置函数多了如下两行设置中山优先级和使能中断的代码;
; R5 L4 g- {( g9 V# n8 u# G8 ~3 ]- HAL_NVIC_SetPriority(EXTI13_IRQn, 3, 0);
$ t7 @" N1 c4 f* N& U }! p+ N - HAL_NVIC_EnableIRQ(EXTI13_IRQn);
复制代码
1 w8 y( [ D/ F$ s5、在stm32l5xx_it.c文件中也多了一段中断服务函数的代码;. ?* Y3 ~5 l- }4 e' f
- void EXTI13_IRQHandler(void)
1 L2 H: p, N# x; d8 p' b! N0 V - {1 D$ {0 I/ e- ]7 N( l
- /* USER CODE BEGIN EXTI13_IRQn 0 */
$ J! X4 y- D. |* _" {# |6 B - s; B+ r1 d J$ G" |" B
- /* USER CODE END EXTI13_IRQn 0 */
8 r2 ]+ G% [5 F3 v2 h: } - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);, A& E, I" {9 T# C( u
- /* USER CODE BEGIN EXTI13_IRQn 1 */
: i) L$ r( R7 ?& q- W7 I3 W3 |8 G5 Y - 6 A5 B9 @0 c* i: b( u* q
- /* USER CODE END EXTI13_IRQn 1 */
7 x. n7 h4 h% Y6 _" e - }
复制代码 6、跳转到HAL_GPIO_EXTI_IRQHandler函数的实现,该函数的内容如下;5 U) `* t+ V+ ?/ M/ t! s7 e
- void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)) z \3 n1 P- `+ `# D( Y
- {
3 P% z% d8 L$ I1 X - /* EXTI line interrupt detected */: l8 q) X5 X, l& b
- if(__HAL_GPIO_EXTI_GET_RISING_IT(GPIO_Pin) != 0U) M* x/ K: G% G' G. P: l" G& n
- {
3 n; j+ Z: q$ p' P& T) ^7 l - __HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);) G; { O+ F) _5 }
- HAL_GPIO_EXTI_Rising_Callback(GPIO_Pin);
$ `4 }4 E1 s8 O8 q - }9 G2 `& C. N! o) k7 ^8 v4 }" Q/ A
9 L3 x4 J3 n3 v& [- if(__HAL_GPIO_EXTI_GET_FALLING_IT(GPIO_Pin) != 0U)
2 D. x- ^* U$ R% s# b - {
) c& W" ~& f+ N$ K- Z8 t. ^ - __HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_Pin);
' Z: n) J- }! F" b( }3 i9 D N9 P - HAL_GPIO_EXTI_Falling_Callback(GPIO_Pin);
6 o4 M( \4 j1 G( m) b - }! x8 r K% T- {, e, ?
- }
复制代码 其中的HAL_GPIO_EXTI_Rising_Callback和HAL_GPIO_EXTI_Falling_Callback函数就是外部中断的回调函数,两个函数内分别有如下注释:
: g7 D1 J& U) x f2 \/* NOTE: This function should not be modified, when the callback is needed,
( {6 M. q, O/ M( w" C" B the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file' }: S( ?! q; j, ~
*/ /* NOTE: This function should not be modified, when the callback is needed,+ J6 k6 z) Z2 w+ |$ X f
the HAL_GPIO_EXTI_Falling_Callback could be implemented in the user file: }6 |! D! u2 `! B, }2 @
*/
* q' g6 d+ V* z( @# X: G! Z, u意思是这两个函数在用户需要的时候可以在用户文件上实现,实现的内容就是用户需要本次中断执行的内容。- S: J+ k6 |9 m3 I/ O
7、回到main.c文件,添加如下函数的实现;- B4 A6 e# c- q: u3 }0 d8 A
- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
8 W6 E8 H, x. ^! I% |; w - {/ W6 [3 H) j/ q
- if (GPIO_Pin == USER_BUTTON_Pin): d6 b- D+ z' k# |
- {2 q& w1 {4 e" s, a$ {+ X
- USER_BUTTON = 1;! S0 s4 r& T- b; E8 e5 q; v
- }
1 l$ A7 ]* ?9 r - }
复制代码 USER_BUTTON为一个全局变量,在文件开头进行定义:_Bool USER_BUTTON = 0;
/ o l( `0 r2 r! p8、在主函数的循环中添加如下代码;
- x' X4 g, i" }; R# a一切就绪,重新编译连接并4 w' F8 i* ]8 G1 S$ |$ g( E7 f
- /*外部中断操作*/
* r$ X: K$ `) U$ Y- _' i4 I - //按键检测程序
- s( X6 t+ n3 r, | - if(USER_BUTTON == 1)
3 @; R+ ^6 T, k; N) E n - {
4 ~. l' f8 |8 D" |( e - u_cycle += 10;( U( Z. y* @ o1 T! D3 {5 {
- if(u_cycle>=50) w6 z0 x7 j6 Y" k0 v
- { [4 u H7 s! |
- u_cycle = 10;
0 g, \$ n: ^. S; G - }
, K3 X8 W- z+ ?( Y2 b5 s/ V - USER_BUTTON = 0;
, ^, P5 g3 J1 Y7 K: @: X3 y - }
: c2 {+ W" _: y* Z3 q - //LED灯闪烁程序! l3 e9 O, S- Y9 Q) |9 i
- u_cnt++;6 {1 ?/ ?, R" H
- if(u_cnt >= u_cycle)$ ~* b3 t. q9 n# d" h$ Z1 o
- {
, C3 {6 c& } ^+ W* k' ` - u_cnt = 0;
! m9 O% }' [( P - LED_R = !LED_R;* w: T* v; S. e \& N. B
- }
% F3 ^/ P; A, f' ~9 F% \ - HAL_Delay(10);% A7 x9 e( o7 O6 Z5 E
复制代码 8 Q i7 c$ c7 h
下载到开发板上,按下按键观察程序运行情况,还是跟上回的一样,实现了使用外部中断检测按键对LED的闪烁频率进行调节。
6 C1 I6 D9 r. @' g. \" j总结:! c1 P. P* B/ e+ n- F# Z$ I7 |/ z; r
得益于STM32CubeMX的强大功能以及HAL库的完美包装,外部中断的实现似乎并没有那么难(相比于标准固件库来说真的是简单了不少),只需要自己实现一个回调函数就好了,对快速开发是方便了不少。好了,本次评测就到此结束,感谢您的阅读,我们下回再见。
( ]1 }3 Y) V/ k7 }! u; S+ j: K7 ~/ V" t; Z' _! G
/ O& X! Y e) V
7 i* ^) ~8 w: N+ ^' M5 v( x- m6 U
6 G% _3 a4 _5 @9 c/ {* W3 v |