上回向大家介绍了如何使用GPIO口的输出功能点亮一盏LED灯,以及使用GPIO口的输入功能读取按键的状态控制LED的闪烁频率,然鹅,获取按键的状态采用的是主循环查询的方法,这有一个弊端,试想当主循环的循环周期非常长的时候,比如夸张点说要1秒,那就得一直按着按键等到程序扫描到按键的输入引脚后才能放开,这个等待时间最长需要1秒,这是很糟糕的,我可没有这个耐心去等,比如在将一个数从1调节到100的时候,那后果是可想而知的。为此,就有必要引入一个叫中断的神奇东西,程序中的中断,会把正在运行的普通程序或者低级的中断服务程序打断,先运行本中断服务函数内的程序,就好比我们日常生活中的突发事件,你正在洗衣服,突然快递小哥到你家门口了,你得放下手上的衣服先去取个快递,总不能让快递小哥在门口等你把衣服洗完吧。中断还有很多种分类,在普通的51单片机中有三类中断共五个中断源,分别是外部中断0和1、定时器中断0和1以及串口中断,而在STM32中的中断那可多了去了,比方说有GPIO外部中断、定时器中断、串口中断、DMA中断、ADC中断等等等等,每个中断都有它独特的功能,而本次我们需要的就是这当中的GPIO外部中断,好了,废话不多说,接下来我们就来研究研究STM32L552的外部中断是如何使用的。评测内容:, n; S( F w- u
1、使用外部中断获取按键的状态,并调节LED灯闪烁的频率。
! q( V% H) O0 ~/ R( ]所需元件:
' M7 M: C; A5 E( t4 [/ Q/ c" [7 g1、STM32L552ZET6Q;! W8 t- h A2 p; V& | ?% ^
2、板载红色LED(LD3);) C& n; M; L$ j
3、板载蓝色按键(USER)。3 g( O; X8 w/ H0 F! z
评测步骤:
4 c" d6 K( ^. D$ U; Z1、将按键引脚配置成外部中断模式,打开上回创建的STM32CubeMX工程,将芯片的PC13引脚按照步骤配置成下图所示的设置,第五步为设置程序中的引脚别名,可根据自己的需求进行设置;/ Q- u' Y- o5 }9 n0 A
, }. R" l% H: G2、使能外部中断并设置中断优先级,按照下图所示步骤及内容设置,中断优先级可自己根据需要设置;
# z: s: F9 S$ D" U8 r% K6 A
: B4 H' i) c2 Y% B# ^3、保存工程并生成代码工程。* c( C! u7 M; n' L
4、打开代码工程,发现main.c文件中的GPIO口配置函数多了如下两行设置中山优先级和使能中断的代码;) `$ G! n% ]* A- v/ o5 Q8 T
- HAL_NVIC_SetPriority(EXTI13_IRQn, 3, 0);& `7 z9 k( {: G/ {$ O. G- [# M
- HAL_NVIC_EnableIRQ(EXTI13_IRQn);
复制代码
, b( A8 y& W4 ~" {. |# n5、在stm32l5xx_it.c文件中也多了一段中断服务函数的代码;2 P2 ?0 I# ?6 h+ t- c
- void EXTI13_IRQHandler(void)
7 J4 Y% y5 L. S" M4 K+ K - {
$ |9 u: c1 ~; M) H5 C- N; b - /* USER CODE BEGIN EXTI13_IRQn 0 */) \, S0 l7 \* h1 Q- [" n
- 9 b: f8 `' }6 K. r- r8 Y
- /* USER CODE END EXTI13_IRQn 0 */
5 F% L) Y, E; c% ]- Z8 d3 ?* f' E" y - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);, n: ]. d* B6 R: S% ?; N5 r! v% u
- /* USER CODE BEGIN EXTI13_IRQn 1 */
6 g) t* q; J. Y, K) S& X - 7 S9 Y D9 O' X; ]: X% n' T& D4 c
- /* USER CODE END EXTI13_IRQn 1 */
! s; H& v- W3 g; M, q0 h' q/ k - }
复制代码 6、跳转到HAL_GPIO_EXTI_IRQHandler函数的实现,该函数的内容如下;
4 g6 I7 d% F# e/ D- void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)9 L) n4 z; V# i4 J+ R Q9 ^+ u: |+ C
- {
' M. d4 Y- W' N: V, b; m - /* EXTI line interrupt detected */
$ F2 N- _! T# S* g - if(__HAL_GPIO_EXTI_GET_RISING_IT(GPIO_Pin) != 0U)
d3 q3 H9 r% \3 T, ] - {
8 F9 }1 ^0 s$ I( F5 d$ b. F6 z - __HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);0 G2 ]; r, D K% Z6 d: O+ W
- HAL_GPIO_EXTI_Rising_Callback(GPIO_Pin);
4 `! G2 A% u1 M* D! H# H - }
) K+ j" {4 ~7 K( v/ {- a
2 T! s. U! v, j: \- if(__HAL_GPIO_EXTI_GET_FALLING_IT(GPIO_Pin) != 0U)
+ f7 h( S" C! q. h/ D& h7 b6 y - {4 ?6 E7 ^: d) A0 @3 \/ B
- __HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_Pin);& u3 Z3 ?% R" g- H7 i" A& d% L ?
- HAL_GPIO_EXTI_Falling_Callback(GPIO_Pin);2 w. ~8 \( U! a! D r: @( ^
- }) B k" q9 a1 b0 u, E3 P# Y+ U/ Y! @: g
- }
复制代码 其中的HAL_GPIO_EXTI_Rising_Callback和HAL_GPIO_EXTI_Falling_Callback函数就是外部中断的回调函数,两个函数内分别有如下注释:
5 W) {& E9 t3 b! G) x0 x/ B+ f1 X/* NOTE: This function should not be modified, when the callback is needed, }) F; h% C' ?' o* y6 n& g' _2 ]' {
the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file
# b1 R& E5 i$ l1 x% z$ e: d */ /* NOTE: This function should not be modified, when the callback is needed,& I. }1 I% _$ E% c
the HAL_GPIO_EXTI_Falling_Callback could be implemented in the user file( \" K/ w8 ?7 N* y
*/
. r0 [# R0 u( E2 v意思是这两个函数在用户需要的时候可以在用户文件上实现,实现的内容就是用户需要本次中断执行的内容。/ p v: n' c( u e+ p: o5 o/ P
7、回到main.c文件,添加如下函数的实现;9 y5 Z4 W5 F: D- T
- void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)" h g- S V9 T3 r9 f% V8 _8 N
- {
$ _2 t3 ~ S4 r9 { J - if (GPIO_Pin == USER_BUTTON_Pin)
- b: m5 h2 a3 y! a+ b- W - {
6 Z) s+ c2 V \" p b( ?) h - USER_BUTTON = 1;3 M P6 \5 e$ _* `
- }
w4 j( T2 z$ P5 I5 r - }
复制代码 USER_BUTTON为一个全局变量,在文件开头进行定义:_Bool USER_BUTTON = 0;5 c( R' p" B6 t% q6 W. N |
8、在主函数的循环中添加如下代码;! S% o% h0 z1 f+ p! c* e3 ^4 P4 Q
一切就绪,重新编译连接并
, y& }8 [% `" C" b- /*外部中断操作*/2 |5 p1 ^: A$ d: X9 C* J; S6 h
- //按键检测程序 g8 f/ {3 f; @2 [, I
- if(USER_BUTTON == 1)
. A6 Z/ }7 q$ d9 \1 L - {
+ j8 F, E! d( M& f# g8 l# P - u_cycle += 10;3 {" P+ b' w# m$ q* m
- if(u_cycle>=50)
9 P# f) _5 \ j9 U* m - {
1 R0 J9 {! x5 s' g! N' H" ]' r, a - u_cycle = 10;
- p/ I4 U! {* U( r( s - }
, I+ i. A& ^. n0 d8 C" i* T - USER_BUTTON = 0;( t6 j# V# S) Y6 t1 W n2 v- E7 F
- }
& v$ o! n% o ?6 @, d0 A: \: Q - //LED灯闪烁程序- B" E: W0 ^# B0 Q" q+ e. N
- u_cnt++;
6 X [7 v8 ?, S+ {% A3 H; e - if(u_cnt >= u_cycle)0 |: a5 N; C* V. M) P( k3 i
- {/ `! a+ v# W7 o* r4 c
- u_cnt = 0;
A6 a" q5 v0 S- i) t) G - LED_R = !LED_R;2 d E: D. N$ k0 \' a: m
- }
# W1 F2 C+ a4 j3 Z- S4 x1 A - HAL_Delay(10);
" W+ C! z" s0 r6 L
复制代码
) Y: A' h, b' Y& e i下载到开发板上,按下按键观察程序运行情况,还是跟上回的一样,实现了使用外部中断检测按键对LED的闪烁频率进行调节。
9 R' x! H' x0 I3 d总结:/ C! F5 @& F7 n/ K& R7 Q( P
得益于STM32CubeMX的强大功能以及HAL库的完美包装,外部中断的实现似乎并没有那么难(相比于标准固件库来说真的是简单了不少),只需要自己实现一个回调函数就好了,对快速开发是方便了不少。好了,本次评测就到此结束,感谢您的阅读,我们下回再见。
. u& r0 O. F. U; b0 W) a; ~' V1 h
( E2 t- W6 S# ~/ q) h
& m6 T. ?6 F3 k
( ]* w' k6 w0 o
2 b2 B, i4 i& K& g) A |