|
STM32CubeMX是官方推荐的配置软件,而HAL库也是取代之前的库函数的通用库,所以STM32CubeMX+HAL库是当前主流的工程创建方式,HAL库的可移植性也高于被取代的库函数。 之前在[程序员小哈]的公众号中写过两篇基于STM32CubeMX软件的文章,今天对其进行了转载。 今天我们利用STM32CubeMX实现按键(外部中断)翻转一个LED,涉及到的新知识点:外部中断。 % x. z1 l) u. I; j3 I
软硬件环境- Keil 5.14
- STM32F103RET6核心板【202006每月活动】
- STM32CubeMX 5.3
- 按键(PA12)
- LED(PA11)
- L L' e6 l& [2 v L7 D6 c, _7 V
g" L) @: [- c7 T+ t; RSTM32CubeMX创建工程- 打开STM32CubeMX软件,从如下箭头所示两个位置可以新建工程。9 ?9 |7 w/ @, r9 t r: r. W, a F
' l3 d0 r% _: h) Y# ?4 }* X
! Q% r+ H5 r8 A* d: v
- 选择芯片STM32F103RET6,可以在下图左侧位置进行检索,缩小待筛选范围。1 x" V6 C/ i( g$ k% {8 F; \
. t8 {* @- `: G5 j, T4 n/ {' X- 查看核心板的原理图,知道LED对应GPIO的PA11,按键对应的GPIO为PA12。. P: P3 m8 j; V3 J9 j
* x2 X* G7 ?9 W% P9 `: S3 H
. t+ x% m# Y& v; E4 e5 K5 v/ @( m- 配置PA12为外部中断模式- l |( S/ Z/ g+ n8 x d" z
$ {, c5 Q, @* J9 N
7 V4 s2 _, ?# I+ B R9 X6 i2 Z2 i- 配置PA11为输出模式% s- |+ w' e- I% g$ S
9 C; Q. `/ j! f8 _: P) C4 z' E
: x1 O ~3 G; u6 T9 V
- GPIO配置
& X( ^$ ?4 `6 c9 V, j6 _; _ \7 }- m6 s# S. u5 z' E
注意:因为下面按键中断的回调函数中我们加了延时防抖功能,所以此处必须是下降沿触发,至于为什么?大家可以想想哈,大家可以在留言中交流一下。
5 H8 h# f. u3 @! Y- 使能外部中断,注意中断分组
% M/ j5 y7 V* G6 Y, w4 K
( U. F5 T L4 D
! R( y Y9 [% a! Q" B0 ?% L, P7 ?- 配置RCC
, n& x/ j, L4 {/ T9 }# R
" ]( D( g: G6 f1 P: g' R
# H+ f' w/ b6 y$ u
- SYS要如下设置,否则下载一次程序以后将无法再次下载!!!+ G* p1 M. w% _7 H' |
0 Z+ U- L9 k4 B* M B/ I
3 K* n3 d4 k; B) P$ m7 F- [
- 配置串口1为异步串口
4 J; G! f) i/ ?" A0 t& o& Y8 H5 r( r; E' t' N
因为PA12占用了串口1的USART1_RTS引脚,所以串口1配置成禁用硬件流控的异步串口即可。
# o+ @7 S% G" j& k- N2 b- o* q- 时钟树配置/ ^ n0 D2 g, W+ f! `4 f
: W: c2 B. ^' c: J
" s9 n' B, @' w" N- 工程配置,工程名称:STM32EXTIDemo。
0 j( ~4 ^0 l* r y# L( R8 p9 m( x# T$ ]9 p; z
: O+ F8 d3 k5 y3 p0 _; Q C- J+ l- 生成代码
4 Q# b0 ~# i! E% e0 l: i! e( b6 f: Q
" f" a( q4 d, l9 F
8 V4 e, N- T. A& I2 x9 ^2 R
; n0 t! I' H' ~$ F- `2 W nusart.c文件中,添加串口printf输出代码2 Y5 {7 Y+ z4 s5 S3 ]
$ J! s4 ~% t' C2 U6 x' F
" h' ]: Z3 O l: E) l& w9 \- #include "stdio.h"
+ h1 ?; `; a' w1 E' P6 N - 7 o7 P2 K6 G7 v# E" G
- #ifdef __GNUC__
& X2 r; G* L. e* ? - <i>/* With GCC, small printf (option LD Linker->Libraries->Small printf
0 e+ U0 j8 j, |2 B - set to 'Yes') calls __io_putchar() */</i>- E5 S/ ~5 k" J2 [) k- G8 O/ [
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)7 k i) T/ l* w) e- A4 _6 `
- #else$ C3 ]+ J$ ~7 J# f% m7 V
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)0 T. H9 P* I! b* ^) W' l- ` }
- #endif /* __GNUC__ */5 D6 x G0 w9 C; Q# O0 |3 R
: B& K, z; f* \) j' i4 ~" G8 d; R! g& m
$ D4 u: Q2 ^% b4 T9 e. b- PUTCHAR_PROTOTYPE; S' a3 x0 Z. i: A6 h
- {& g2 u ^5 I+ S1 H: N
- HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
* j0 i' p% @8 J; `5 Q( d" | - return ch;$ X& S9 Z. D( u: N+ v
- }
复制代码
: f) N& X X% p9 q R
( l9 m4 e( h5 Q, _8 c3 p, A- 添加按键中断回调函数1 m4 B+ D) v1 d
m- P; @3 q$ k2 C0 g$ Y9 Q
# {0 P, D* w1 P4 u6 ?
- <i>/* USER CODE BEGIN 4 */</i>
6 v- M9 [9 L) D- L& _/ b - ( O- y$ |' Z7 A. C# Y
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) ' Y% b2 \7 B- C% p; |7 A) w1 G \
- {
' T D1 b- E7 U- b4 R% L% S - switch(GPIO_Pin)( [8 O1 n+ f9 J3 V8 B! }
- {
0 _1 D6 P# W, E. [ - case KEY0_Pin:
1 W9 K. i: ]7 U9 ~" [* M -
! _: w0 k5 M7 |8 @' }6 G - HAL_Delay(10);
; `6 ^ F4 n+ P7 { - + t' u% Y/ S8 i+ b
- if( HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0) <i>//延时10ms之后再判断是否有按键被按下,防抖</i>
% p1 H5 C& |; Y/ i+ \ - {
1 q. f$ T6 D: ~, `+ @) z - printf("KEY0 Press ... \r\n");" ]5 F1 f- O. t' M( {; l' H
-
" K3 d$ J& O: p4 e - HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);# E3 h, z# G6 y* a% N& G) ?
- }5 f S L2 n' R$ m& y3 ?) c
- break;
0 j f! M6 k2 T
' ^5 {8 B7 D% z# k) a% e- default:break;
, i5 c* N$ l4 } - } C/ O8 h8 k6 R! e( G
- }
复制代码 " W0 b' q1 B: Y( }5 }, X
其中: HAL_GPIO_TogglePin() 函数用于实现翻转 IO 口的电平。 实现同样功能,还可以使用下面代码分别控制LED的亮灭:HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET) // 输出低电平--亮 HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET) // 输出高电平--灭. n' J. |; G! I- B8 C3 @
我们为什么添加了上面的函数,然后就能与中断函数绑定到一起呢? 因为这里涉及到一个“弱函数”的知识。 在 HAL库中,很多回调函数前面使用__weak 修饰符。weak 顾名思义是“弱”的意思,所以如果函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。加上了__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。
我们搜索HAL_GPIO_EXTI_Callback()这个函数,发现的确有__weak修饰的同名函数。
/ y% Y g: U( `6 `
这个函数在stm32f1xx_hal_gpio.c文件中的HAL_GPIO_EXTI_IRQHandler()函数中被调用,该函数对中断标志位进行了清除。
. R! [0 G# d' n9 ?- v6 l而上面的函数正好在外部中断函数EXTI15_10_IRQHandler()中被调用。
( O- ^8 T4 d9 k J. v; a# ?
由上可知,当GPIO发生外部中断时,我们只要在回调函数HAL_GPIO_EXTI_Callback()中,添加逻辑代码即可。 - 配置JLINK下载工具8 }: D) ^' f2 \+ b( Q$ B
; b" z' B: {8 I# @* H
+ L, |3 |" F, L% }) b- 下载程序后,复位核心板,按下按键,串口助手窗口可以正常打印预设信息,LED亮灭来回切换,证明满足预期使用外部中断反转一个LED。
, g5 J8 l1 V# L2 D8 y% Q9 K- Z% a7 k8 @
8 d$ E. D2 V: G# D. T5 b( Y0 n
$ {7 ^: l$ n- H# C
. g: W# l& B5 G$ r% p9 A. ^
+ q6 z6 n* }. g- g: l$ ]/ x |