你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】基于HAL库实现按键(外部中断)翻转一个LED

[复制链接]
STMCU小助手 发布时间:2022-3-17 17:21

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
N(97AYITZ[Z%)Q_QT2%[}G4.png
# z  E, F+ h7 p( F
  • 选择芯片STM32F103RET6,可以在下图左侧位置进行检索,缩小待筛选范围。
      X* `1 l! F, A+ _" U
F7BVLUX14[)E3~`S6O)FW0Q.png
7 D' Z& [& A* q
  • 查看核心板的原理图,知道LED对应GPIO的PA11,按键对应的GPIO为PA12。
    9 v; V5 Q; H- m7 S

    ( v/ m. n9 l6 r/ M; c
[64Y2R}_`~%M(G4G)~S[4Y4.png
9 b) B! O( x4 s: R
  • 配置PA12为外部中断模式/ y) W& ]5 T% [$ g
    - d5 e  m) Y# C/ u2 [+ ^
_XJQ4[(FLOP%R7JKPF}RK{8.png ; u6 u3 C3 ~: F2 z8 `; Z
  • 配置PA11为输出模式& }" R" m5 P/ M0 l
      T! ?2 C2 K( I6 f0 w+ J4 s% }
LT{@13`SWMR3S%%UMZ`@RO0.png $ 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

注意:因为下面按键中断的回调函数中我们加了延时防抖功能,所以此处必须是下降沿触发,至于为什么?大家可以想想哈,大家可以在留言中交流一下。

KL$YQBI8VOOBZRL7`R7XW3H.png
0 x0 `, Z! j4 F
  • 使能外部中断,注意中断分组
    4 I3 |8 |. A0 H; n/ L  k

    ' `$ Z# K. t2 ?1 ]: O' g& e4 `) r
GCX]M{Z[642N_O)4I_P@{N2.png
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
[C0V`A6RHNWH_(GB`6R~T4N.png ; q' u& W1 P  z
  • SYS要如下设置,否则下载一次程序以后将无法再次下载!!!3 x: \6 p; p9 U; V4 q# w; _6 i3 N$ D
    ) W/ Q! K; ~  r+ B
B{UK{YHPT7PZCB58@JW]016.png
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配置成禁用硬件流控的异步串口即可。

FFSYMP~LUA7YZQN_H%]TI5M.png
& a, F" X/ i6 S* }* W% q
  • 时钟树配置
    + ~+ S# f0 p, X* h$ e& Q6 r& j
    2 Z8 r9 i9 @& b- S; Z; i+ F6 j2 b
OCLF}RJ1L19RIMF~ZBSC8BC.png
' q6 H8 Z  C1 ?) K
  • 工程配置,工程名称:STM32EXTIDemo。
    $ h  G: Y' M! d5 }
    - t" D) B1 t5 T
(O939L8ZO8M_5N%5]~GK{.png ! `3 S, `2 o9 a- ?/ p  c- x
  • 生成代码$ W' [1 D) M" U

    9 v; x# ~$ u7 R( Q) r
8HWG8W_6$B}L367CN7R${7K.png
' 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
)C$X%AXFZ0ZC63$YJ5XCM[P.png
5 Y9 Y! t. B. E6 x( J
  1. #include "stdio.h") N+ k  \, Q! n2 N
  2. 9 Y. L  I8 q; |# y
  3. #ifdef __GNUC__3 O% l0 s, p" H: ~, W
  4. <i>/* With GCC, small printf (option LD Linker->Libraries->Small printf# `# g% a" n: n3 u+ }0 }. l
  5.    set to 'Yes') calls __io_putchar() */</i>
    # `5 M9 s  E1 Y5 s' p  O
  6. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)9 g& E" \& x9 \1 ?) F
  7. #else
    ( [; ~+ j: R: P8 Z0 {/ v5 x% \. d4 ]9 M3 l
  8. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)+ a3 n: ^1 e, H/ U5 {$ e5 u$ h' R
  9. #endif /* __GNUC__ */) _, J1 V5 ]  h; }2 q4 ]

  10. 2 h9 Q! E" z, @
  11. ) Q/ n. _6 c1 M/ ]* r4 t- F
  12. PUTCHAR_PROTOTYPE  e0 C2 R( r1 C$ l
  13. {
    , X  _4 `1 Q: X. e0 G
  14.     HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    ( V3 d5 }6 F; |* l5 n+ v) v
  15.     return ch;
    ( {% |: p' t. G& W3 K& k' b. u9 C5 [
  16. }
复制代码

  c3 P' W( T7 Q 6J8IZ}R2J(GD{IUKZE05N.png + t- d/ D% n3 ?0 F+ d% l9 W; _) \
  • 添加按键中断回调函数3 g0 v+ y8 Z- _5 d  j$ u
    $ O9 a+ f* O5 I1 p
5WVHQ2~27C[@K{2A3$Y8ALP.png 3 D2 N# ~3 m* M6 P- u' Y% P
  1. <i>/* USER CODE BEGIN 4 */</i># V6 T% p( L# P1 l

  2. " l. `5 E( Z7 J6 f/ r5 L0 a" }
  3. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)  2 S! z% o: f7 @4 P6 U
  4. {+ z# i7 q" s5 A8 \
  5.     switch(GPIO_Pin)+ i& @/ r% N: N; j9 ?( q
  6.     {
    . \2 V& O4 j0 l) {# \0 |
  7.         case KEY0_Pin:   
    2 N% U, T/ H$ a$ F2 s& h1 W
  8.    
    , g) {8 j9 I) J8 A7 L
  9.    HAL_Delay(10);
      J  R) q+ S' m- E' `
  10.   7 b, ~/ W& o; v' J8 z( J
  11.    if( HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0) <i>//延时10ms之后再判断是否有按键被按下,防抖</i>
    2 ~5 {/ b& S1 v% C6 ^7 ?
  12.    {
    5 `9 l% s( K8 H% [+ g
  13.     printf("KEY0 Press ... \r\n");$ l5 M4 i) D% t" x4 D
  14.   . B: I9 C6 l  d; W( k0 L: h
  15.     HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);; a9 A; o% C+ B, {% S% W5 }: o
  16.    }; i- s5 \% r% s
  17.    break;  
    4 _3 }. L1 F/ f

  18. & K9 |' B$ }4 J. G" c# ?. i. }: p8 i
  19.         default:break;
    , j* l% x1 _; O7 c9 A2 P- G
  20.     }% ?5 F! `2 J- w. a6 p
  21. }
复制代码
" 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修饰的同名函数。

7[%{S(`73}PN7X)I65XTME5.png
  y. y. B8 ~/ u

这个函数在stm32f1xx_hal_gpio.c文件中的HAL_GPIO_EXTI_IRQHandler()函数中被调用,该函数对中断标志位进行了清除。

1POVD)JB0C$XG04PIU_(4E5.png 1 N0 s- M; S  `9 X

而上面的函数正好在外部中断函数EXTI15_10_IRQHandler()中被调用。

OH7CGF~LA$_6$U9MP@O2`CK.png
  A9 _3 i- G- q7 A5 B6 c( H

由上可知,当GPIO发生外部中断时,我们只要在回调函数HAL_GPIO_EXTI_Callback()中,添加逻辑代码即可。

  • 配置JLINK下载工具
    . N) C2 x1 w$ ?* }- d
    2 f+ i$ u+ Q# i  G6 d
TS(K$~QEY3_DEADO2U$W2MG.png " p1 f. ~7 I. j# }5 L; a( j
  • 下载程序后,复位核心板,按下按键,串口助手窗口可以正常打印预设信息,LED亮灭来回切换,证明满足预期使用外部中断反转一个LED。
    . a: \4 y6 D6 p8 P  i

    " E$ I& p: Y" ~( Z
%JOK_]~`TJJ}]PKHE_[Y7.png
; w$ a/ D' [+ X& s' l0 Z

: L  t2 i* Y6 T9 t% X* f) \# C1 s0 z
收藏 评论0 发布时间:2022-3-17 17:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版