|
STM32CubeMX是官方推荐的配置软件,而HAL库也是取代之前的库函数的通用库,所以STM32CubeMX+HAL库是当前主流的工程创建方式,HAL库的可移植性也高于被取代的库函数。 之前在[程序员小哈]的公众号中写过两篇基于STM32CubeMX软件的文章,今天对其进行了转载。 今天我们利用STM32CubeMX实现按键(外部中断)翻转一个LED,涉及到的新知识点:外部中断。 $ e9 h% Z$ {$ Q. O! d2 l
软硬件环境- Keil 5.14
- STM32F103RET6核心板【202006每月活动】
- STM32CubeMX 5.3
- 按键(PA12)
- LED(PA11)
' j ~- Z4 ?$ [% h i9 a
% u. k) U! O6 p- N9 A: G Q& X6 ]1 M2 \( g5 s: J
STM32CubeMX创建工程- 打开STM32CubeMX软件,从如下箭头所示两个位置可以新建工程。; J4 w1 N( c/ t2 U* n9 q1 A
$ c4 N% C, E* P& Q( y6 q2 v- U
# z E, F+ h7 p( F- 选择芯片STM32F103RET6,可以在下图左侧位置进行检索,缩小待筛选范围。
X* `1 l! F, A+ _" U
7 D' Z& [& A* q- 查看核心板的原理图,知道LED对应GPIO的PA11,按键对应的GPIO为PA12。
9 v; V5 Q; H- m7 S
( v/ m. n9 l6 r/ M; c
9 b) B! O( x4 s: R- 配置PA12为外部中断模式/ y) W& ]5 T% [$ g
- d5 e m) Y# C/ u2 [+ ^
; u6 u3 C3 ~: F2 z8 `; Z
- 配置PA11为输出模式& }" R" m5 P/ M0 l
T! ?2 C2 K( I6 f0 w+ J4 s% }
$ u% R6 y9 @2 T6 _2 A* w
- GPIO配置
5 \, H6 @3 o$ ~/ U, j% ^
3 _% `; W3 L1 R J3 ^4 U8 f+ Z9 F
注意:因为下面按键中断的回调函数中我们加了延时防抖功能,所以此处必须是下降沿触发,至于为什么?大家可以想想哈,大家可以在留言中交流一下。
0 x0 `, Z! j4 F- 使能外部中断,注意中断分组
4 I3 |8 |. A0 H; n/ L k
' `$ Z# K. t2 ?1 ]: O' g& e4 `) r
1 b4 v2 Q* j, m2 E; q- 配置RCC
: Z; ]+ O; d& E, y% T' h" M' l" e0 m c2 \/ w1 H. S6 Y
; q' u& W1 P z
- SYS要如下设置,否则下载一次程序以后将无法再次下载!!!3 x: \6 p; p9 U; V4 q# w; _6 i3 N$ D
) W/ Q! K; ~ r+ B
0 Q4 x6 Q; G7 N0 X2 H: }( K- 配置串口1为异步串口% z/ W* g$ C1 \( A0 P* a
! o, ~6 ]0 s! F+ h# P/ z* p. b9 V q
因为PA12占用了串口1的USART1_RTS引脚,所以串口1配置成禁用硬件流控的异步串口即可。
& a, F" X/ i6 S* }* W% q- 时钟树配置
+ ~+ S# f0 p, X* h$ e& Q6 r& j2 Z8 r9 i9 @& b- S; Z; i+ F6 j2 b
' q6 H8 Z C1 ?) K- 工程配置,工程名称:STM32EXTIDemo。
$ h G: Y' M! d5 }- t" D) B1 t5 T
! `3 S, `2 o9 a- ?/ p c- x
- 生成代码$ W' [1 D) M" U
9 v; x# ~$ u7 R( Q) r
' T1 a) @; ]5 r6 B: `8 w1 n8 D& ]6 _
. E& }: I2 f- Pusart.c文件中,添加串口printf输出代码
+ f4 C1 s& a% G# }7 I P2 m! R9 H5 J: S$ i
5 Y9 Y! t. B. E6 x( J- #include "stdio.h") N+ k \, Q! n2 N
- 9 Y. L I8 q; |# y
- #ifdef __GNUC__3 O% l0 s, p" H: ~, W
- <i>/* With GCC, small printf (option LD Linker->Libraries->Small printf# `# g% a" n: n3 u+ }0 }. l
- set to 'Yes') calls __io_putchar() */</i>
# `5 M9 s E1 Y5 s' p O - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)9 g& E" \& x9 \1 ?) F
- #else
( [; ~+ j: R: P8 Z0 {/ v5 x% \. d4 ]9 M3 l - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)+ a3 n: ^1 e, H/ U5 {$ e5 u$ h' R
- #endif /* __GNUC__ */) _, J1 V5 ] h; }2 q4 ]
2 h9 Q! E" z, @- ) Q/ n. _6 c1 M/ ]* r4 t- F
- PUTCHAR_PROTOTYPE e0 C2 R( r1 C$ l
- {
, X _4 `1 Q: X. e0 G - HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
( V3 d5 }6 F; |* l5 n+ v) v - return ch;
( {% |: p' t. G& W3 K& k' b. u9 C5 [ - }
复制代码
c3 P' W( T7 Q
+ t- d/ D% n3 ?0 F+ d% l9 W; _) \
- 添加按键中断回调函数3 g0 v+ y8 Z- _5 d j$ u
$ O9 a+ f* O5 I1 p
3 D2 N# ~3 m* M6 P- u' Y% P
- <i>/* USER CODE BEGIN 4 */</i># V6 T% p( L# P1 l
" l. `5 E( Z7 J6 f/ r5 L0 a" }- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 2 S! z% o: f7 @4 P6 U
- {+ z# i7 q" s5 A8 \
- switch(GPIO_Pin)+ i& @/ r% N: N; j9 ?( q
- {
. \2 V& O4 j0 l) {# \0 | - case KEY0_Pin:
2 N% U, T/ H$ a$ F2 s& h1 W -
, g) {8 j9 I) J8 A7 L - HAL_Delay(10);
J R) q+ S' m- E' ` - 7 b, ~/ W& o; v' J8 z( J
- if( HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0) <i>//延时10ms之后再判断是否有按键被按下,防抖</i>
2 ~5 {/ b& S1 v% C6 ^7 ? - {
5 `9 l% s( K8 H% [+ g - printf("KEY0 Press ... \r\n");$ l5 M4 i) D% t" x4 D
- . B: I9 C6 l d; W( k0 L: h
- HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);; a9 A; o% C+ B, {% S% W5 }: o
- }; i- s5 \% r% s
- break;
4 _3 }. L1 F/ f
& K9 |' B$ }4 J. G" c# ?. i. }: p8 i- default:break;
, j* l% x1 _; O7 c9 A2 P- G - }% ?5 F! `2 J- w. a6 p
- }
复制代码 " q- R& H4 G) u+ c8 G
其中: 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) // 输出高电平--灭
! w# I- ]7 F+ N* c( v" i0 } 我们为什么添加了上面的函数,然后就能与中断函数绑定到一起呢? 因为这里涉及到一个“弱函数”的知识。 在 HAL库中,很多回调函数前面使用__weak 修饰符。weak 顾名思义是“弱”的意思,所以如果函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。加上了__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。
我们搜索HAL_GPIO_EXTI_Callback()这个函数,发现的确有__weak修饰的同名函数。
y. y. B8 ~/ u这个函数在stm32f1xx_hal_gpio.c文件中的HAL_GPIO_EXTI_IRQHandler()函数中被调用,该函数对中断标志位进行了清除。
1 N0 s- M; S `9 X
而上面的函数正好在外部中断函数EXTI15_10_IRQHandler()中被调用。
A9 _3 i- G- q7 A5 B6 c( H由上可知,当GPIO发生外部中断时,我们只要在回调函数HAL_GPIO_EXTI_Callback()中,添加逻辑代码即可。 - 配置JLINK下载工具
. N) C2 x1 w$ ?* }- d2 f+ i$ u+ Q# i G6 d
" p1 f. ~7 I. j# }5 L; a( j
- 下载程序后,复位核心板,按下按键,串口助手窗口可以正常打印预设信息,LED亮灭来回切换,证明满足预期使用外部中断反转一个LED。
. a: \4 y6 D6 p8 P i
" E$ I& p: Y" ~( Z
; w$ a/ D' [+ X& s' l0 Z
: L t2 i* Y6 T9 t% X* f) \# C1 s0 z
|