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

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

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

STM32CubeMX是官方推荐的配置软件,而HAL库也是取代之前的库函数的通用库,所以STM32CubeMX+HAL库是当前主流的工程创建方式,HAL库的可移植性也高于被取代的库函数。

之前在[程序员小哈]的公众号中写过两篇基于STM32CubeMX软件的文章,今天对其进行了转载。

今天我们利用STM32CubeMX实现按键(外部中断)翻转一个LED,涉及到的新知识点:外部中断。


2 G2 q4 i% {5 o+ A

软硬件环境
  • Keil 5.14
  • STM32F103RET6核心板【202006每月活动】
  • STM32CubeMX 5.3
  • 按键(PA12)
  • LED(PA11)
    6 w' E0 S7 f( X
6 H! f' i. |& e, K: `' d

. W/ Y! T- L7 t$ S) r7 g( ?5 FSTM32CubeMX创建工程
  • 打开STM32CubeMX软件,从如下箭头所示两个位置可以新建工程。3 R& C6 g7 y  i

9 r/ h: D# P, L3 k. g9 m N(97AYITZ[Z%)Q_QT2%[}G4.png $ N  U1 c! X% E2 Z+ t  _
  • 选择芯片STM32F103RET6,可以在下图左侧位置进行检索,缩小待筛选范围。
    . Q7 U5 X, R' c# `) k
F7BVLUX14[)E3~`S6O)FW0Q.png
2 G' O* Q$ v/ n5 T* y  l
  • 查看核心板的原理图,知道LED对应GPIO的PA11,按键对应的GPIO为PA12。
    # a! j( ]/ Z5 I! Z9 ^2 D
    & E  P  N/ P9 W2 B/ c6 Q1 q
[64Y2R}_`~%M(G4G)~S[4Y4.png ' k$ {" ?. W- j! [
  • 配置PA12为外部中断模式
    % v1 i$ J- r2 `: y/ k2 _

    / T# N1 ?5 o# Y' M
_XJQ4[(FLOP%R7JKPF}RK{8.png
' S, u& L/ f6 ^8 ]2 D# f
  • 配置PA11为输出模式. d* m$ n* R! r6 `; a& G7 x" m0 j
    + \( [$ q0 r) A; ^- y4 }/ A
LT{@13`SWMR3S%%UMZ`@RO0.png
) P; Y" W1 c8 [' f
  • GPIO配置6 h0 ~7 I3 L! r) z" V' C5 J; N: p

    ) \, s3 \7 l6 @8 P, h$ s5 T

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

KL$YQBI8VOOBZRL7`R7XW3H.png . V0 K$ u! L) ?( ~
  • 使能外部中断,注意中断分组# d, H7 |% Y  p

    & C# \, ?6 S5 Q
GCX]M{Z[642N_O)4I_P@{N2.png
6 N( R1 `7 j2 w- N9 z& k& V
  • 配置RCC2 {* y, M0 B) h2 @7 @
    1 L- W9 P% A. ~1 s; o  ]
[C0V`A6RHNWH_(GB`6R~T4N.png
6 p& h* \3 w" p. s. Z, V7 h
  • SYS要如下设置,否则下载一次程序以后将无法再次下载!!!6 \) m3 b% C* e; y& N6 ~
    7 E9 E# q+ k6 S+ q! g  F. ?
B{UK{YHPT7PZCB58@JW]016.png ( z2 W! Z. R+ C. @
  • 配置串口1为异步串口2 Z/ L4 U, @" j2 Q
    & G! K: e: S. p

因为PA12占用了串口1的USART1_RTS引脚,所以串口1配置成禁用硬件流控的异步串口即可。

FFSYMP~LUA7YZQN_H%]TI5M.png
& Q5 ]$ `' |% M
  • 时钟树配置
    ; Y$ P: y6 B; v7 Y4 Q1 U
    3 V( t: Z, W1 g7 R
OCLF}RJ1L19RIMF~ZBSC8BC.png
3 M! @3 R( j% W, F+ z% J: N) ^9 t
  • 工程配置,工程名称:STM32EXTIDemo。5 m' e  y+ _# W$ [  Y3 m9 J
    2 }! `. {. ?' }
(O939L8ZO8M_5N%5]~GK{.png " i9 p2 `, r9 R
  • 生成代码$ Q. q0 W) K. e+ r/ ]

    - `( N" m) e$ K/ V" K0 G9 v
8HWG8W_6$B}L367CN7R${7K.png * n, U, g1 F# f6 H6 ~( ~/ R
4 y' c* o9 c- Q6 Y! y% J
* V* i/ t! B: {( j
usart.c文件中,添加串口printf输出代码8 X8 u( ]" c3 }" @$ S6 ^0 F

: v4 w( f' V( J3 \" v' `2 y8 l9 h )C$X%AXFZ0ZC63$YJ5XCM[P.png
. ~9 E8 G7 L  ], t+ d$ t' V
  1. #include "stdio.h"5 I7 A( d6 j3 x' a1 T

  2. : y9 m$ w- S7 X" K2 T+ ^
  3. #ifdef __GNUC__3 T0 b% e6 i  v9 @; D' K
  4. <i>/* With GCC, small printf (option LD Linker->Libraries->Small printf
    , K3 ]* N& \* b5 j7 d
  5.    set to 'Yes') calls __io_putchar() */</i>! G9 [9 X( Y7 Z/ ~  f; |) j
  6. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)! n9 j4 g: J9 w9 a/ A* W* P6 m
  7. #else
    & m  V# G0 N8 C$ M: T3 p/ I
  8. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)/ T3 Y2 ?3 [. L: ]& B
  9. #endif /* __GNUC__ */5 `2 C7 _  t3 b& {: x; m
  10. % @9 w/ \0 L: P- w; c
  11. ) m* l6 T5 y7 U( l- S% ?8 g
  12. PUTCHAR_PROTOTYPE! Z! c; t" I$ X( q* M7 B
  13. {4 _8 s+ E* }% a: y
  14.     HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    , p8 A, s" m9 N5 p
  15.     return ch;
    ) a& v2 L$ W% n9 E8 Y0 S+ v
  16. }
复制代码

5 c& K- \, Y, N& _  C 6J8IZ}R2J(GD{IUKZE05N.png " R4 C# g5 F" w4 F7 i  h
  • 添加按键中断回调函数
    , G' y9 u1 E4 `  @. A$ U

    ' W" H. B3 S1 n: u6 d
5WVHQ2~27C[@K{2A3$Y8ALP.png % o) x7 s% y9 b, a3 f5 U4 H
  1. <i>/* USER CODE BEGIN 4 */</i>
    - j) V, s- C  L6 K0 K" u* [

  2. ( I  P% g5 L8 \; c
  3. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)  
    1 s9 s# S3 Z( ?3 P9 v1 n
  4. {9 `1 v& X6 w) b6 W6 j
  5.     switch(GPIO_Pin)( K+ Z& J2 B  X# U  `1 I! ]
  6.     {
    5 h" p1 h) q( f6 {  E# d
  7.         case KEY0_Pin:   
    4 @2 F/ v; v( n! b, J; B; ?/ y
  8.    7 R; }, h# O5 S- f" c
  9.    HAL_Delay(10);" G8 V" Z( T# A1 ~, f) P; ~
  10.   
    5 q1 x- L  v" h3 r* L' q
  11.    if( HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==0) <i>//延时10ms之后再判断是否有按键被按下,防抖</i>, |  J3 i& a' ^- \& e8 Z  E4 D
  12.    {% d, A9 E- a" w% J  l
  13.     printf("KEY0 Press ... \r\n");+ b8 O( m" A6 \( c/ F# k
  14.   
    0 S+ r- q6 E* E+ }8 W! ]
  15.     HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);+ k" a; H+ W) X; H5 a; C7 k
  16.    }& ]' r8 o# r3 p5 M* |
  17.    break;  
    0 c+ a; U/ ^: W/ @$ V2 M" n/ u
  18. . V4 [& W* Y. L7 m( d% u( r
  19.         default:break;! n. A5 P% z% y+ A/ x. S! s
  20.     }
    8 ~( B8 g; A" j: Z! V
  21. }
复制代码
: g; d. @, R* Y- h

其中:

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)    // 输出高电平--灭' t% ]1 u) W8 q- q: E) e

我们为什么添加了上面的函数,然后就能与中断函数绑定到一起呢?

因为这里涉及到一个“弱函数”的知识。

在 HAL库中,很多回调函数前面使用__weak 修饰符。weak 顾名思义是“弱”的意思,所以如果函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。加上了__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak 声明的函数,并且编译器不会报错。

我们搜索HAL_GPIO_EXTI_Callback()这个函数,发现的确有__weak修饰的同名函数。

7[%{S(`73}PN7X)I65XTME5.png
4 I) P7 \! o: l+ L8 e5 c7 h

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

1POVD)JB0C$XG04PIU_(4E5.png
* B. G0 @5 o. }% _6 O; r) K! J: l

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

OH7CGF~LA$_6$U9MP@O2`CK.png
7 P, x  n3 s' k7 r! G0 S) \

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

  • 配置JLINK下载工具
    1 B* A$ n$ N- a' f; {. ~
    ) @& {& k  X) n5 h" M
TS(K$~QEY3_DEADO2U$W2MG.png 8 L' w- w' P7 V% R
  • 下载程序后,复位核心板,按下按键,串口助手窗口可以正常打印预设信息,LED亮灭来回切换,证明满足预期使用外部中断反转一个LED。  v: |" O8 S/ f# `
    + i- M' D" e' k# V
%JOK_]~`TJJ}]PKHE_[Y7.png 8 N7 r- F( a0 e* s$ Q6 n- B/ Z
$ O) s% V/ P! _3 u3 J& Q- ~5 t
. o- @% Q" X4 U/ T/ V& Z; y
收藏 评论0 发布时间:2022-3-17 17:21

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版