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

基于STM32CubeIDE的GPIO原理和底层源码经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-4 23:05
一、GPIO介绍
! S& m$ H& [' t" p8 u/ D        1.1 GPIO 简述

2 b# s& u5 P: q( b5 \9 r        GPIO(General purpose input/output,通用型输入输出),一个引脚可以用于输入、输出或其他特殊功能,PIN脚依现实需要可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO),并多个GPIO一起组合可实现诸如UART、SPI等外设功能。
' v& T+ F6 M& d7 a! R# V8 |. i* p+ G* e. ^
        GPIO是通过寄存器操作来实现电平信号输入输出的,对于输入,通过读取输入数据寄存器(IDR,Input Data Register)来确定引脚电位的高低;对于输出,通过写入输出数据寄存器(ODR,Output Data Register)来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它们。GPIO的输出通常可以输出0/1信号,用来实现如LED灯、继电器、蜂鸣器等控制,而GPIO的输入可识别0/1信号,用来实现开关、按键等等动作或状态判定。$ k! [: ~  w& O* |% ^6 m
) {7 h  k7 p8 u3 T: m/ T
449d07eb68a648aeac94e93fee1899c8.png ; a: c$ d! `' u1 l2 E

2 S; L! R, `0 h
8 y" N1 ]( W+ r6 a* E
       1.2 STM32 GPIO寄存器7 @/ z+ X5 e. M
         STM32中GPIO的寄存器是MCU分配的一个连续存储区域,按存储地址划分出不同功能寄存器,如下图所示,有Port mode寄存器、Output Type寄存器等等。
& V& @) t  y  {7 A
0 j& \1 `0 B0 a% m

2 M! d# D& G0 t; ], V! p7 c9 b a525eff9cbda4bc586eb33d752192f3d.png
9 n+ ~9 G& x# q; W

2 \6 D5 H# X5 X        在HLA库中,这些寄存器的数值(宏定义)通常会放在/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32XXX.h头文件中,供开发者调用,例如STM32L496VGTx的开发板,该头文件具体名是stm32l496xx.h,自8977行起到10008行,具是按上述表宏定义了GPIO各寄存器的各个数据位可设置数据值(偏移(POS)及相应数值)。+ K% _+ S( ?+ x$ ?! E3 L  U
8 P* ]4 m. t) v) ?
f9707b3a86ea43709bbd4febde18a379.png ( E' g  ]& m4 B/ a, ^4 n- T
, y8 A, q: e8 @% m3 H
        1.3 GPIO引脚与标记  {' g2 n4 i$ r* g2 _
         在一个STM32 MCU芯片中,所有引脚本质都是GPIO引脚,只是鉴于全GPIO引脚开发者使用起来比较不方便,于是才通过各个GPIO组合形成针对各个外设的IO接口。在CubeMX中,以STM32L496VGTx芯片为例,可以直观看到该芯片有100个引脚:LQFP100,LQFP是封装,100指的是引脚数。
9 p/ z9 p% h" U5 }& V5 U) M/ F3 N0 t1 E& H, D; p
cd47979d01fe420bbb0a16478916dd41.png 6 _7 m1 k6 d; |

8 K' @5 b2 n1 k: B7 D        STM32的MCU标记一般有两种,直插IC以半圆条口为标记,贴片IC以小圆点为标记,也有缺口及小点都有标记的。通常将标记圆点或缺口正面朝左上角,左上角的下方脚为第一脚,依次围绕芯片中心逆时针计数,在旋转360度以后,左上角右方角为最后一脚。如上图所示,STM32L496VGTx引脚序号如蓝色字体及箭头所示标记。STM32的MCU的引脚标记有三种方式:
- j; R/ Y; i6 H
$ q) ?# d# V. O
        一种是基于上面所述的100个序号排序P1、Pn等,这种标记目前一般是在直接操作寄存器地址或使用标准库中使用,目前HLA库、LL库已经不提供直接地址偏移方式的API了,而是给没一组分组提供了独立寄存器来处理该组引脚;% v$ a+ N& ~( P3 I: U2 k, |  a
) A  L# v7 R4 F" K4 i$ I6 b: e
        第二种是标准库或HLA库宏定义了引脚分组,一般为A、B、C、...,按大写字母次序网线,目前支持到16组类别,每组为PX0~PX15,其标记就是分组名+0~15序号,例如GPIOB+GPIO_PIN_3。' A( l3 b' P/ \3 i' P. b
8 d! B# {, K% [( `4 W7 T3 L
        注意,目前STM32的MCU设计是最大16组类别,支持到256引脚(16*16),通过STM32命名规范可以得知,STM32最做引脚支持到256个,但一般会少于引脚数/16的组数,因为不少引脚在芯片设计时就特别支持了其引脚标识,如VSS、VDD等。另外也不是每组必须0~15序号全用完,分组主要是方便设计及使用时进行引脚区分而已。6 d$ j. n" I/ H5 @' V7 W

! s+ M- h1 Y" v- v8 a2 X1 h; v' X2 E
daa905e0158b4400a1341f3edc6203d3.png
3 k, D& v$ v5 S, B& {5 [. b* k8 h6 K4 j( c+ Z) O
         目前HLA库主要就是这种方式,例如来看看GPIO读取数据的API(HAL_GPIO_ReadPin)实现,主要就是根据引脚序号(0~15)来读取IDR寄存器内对应数据位的数值。
! t: e) F/ [" v7 x/ y- l* W8 k: d8 r6 x5 e" X) M" j. f' G& N# Z
6a026a585a054cb6bd5f0a0bf30d0769.png 0 C& K9 m# [0 X
9 K! Y$ S, E5 o& g
         GPIO分组引脚地址在HLA宏定义数值如下。
8 }. v& p. \# f6 y( ?( K& i  x
  1. #define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */  P( n* a" R5 v4 M4 K6 D5 y# f
  2. #define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */3 [  q& Y& p( U/ R
  3. #define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */5 m# r  T2 |- i1 s
  4. #define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */
    ( m/ H& s  h: R
  5. #define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */
    + t" f$ S' f- `  e6 G6 a# y5 [8 x
  6. #define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */! P2 w3 L" f( c8 ?6 W; u! G
  7. #define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    *// ]) A8 K( R' @* A3 a
  8. #define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */9 A9 U, R, p9 m; J
  9. #define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */$ |4 t7 n0 t0 C' S1 I/ J% i" m
  10. #define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */
    ; O) w4 e) O3 R: G+ ]5 L  ^9 E
  11. #define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */
    ' M+ x( o- Z7 l' f4 B9 W1 o
  12. #define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */
    - c8 x% U" a9 Y5 p7 C# f; d
  13. #define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */
    6 i5 l% ^' G: h$ r2 N
  14. #define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */2 `; N: C  ?1 N8 _
  15. #define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */
    , k1 p: u; r/ @" ?7 C% n& o
  16. #define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */8 g- d* q$ b# O7 Z9 Y
  17. #define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */
复制代码

6 C7 _+ U1 l/ U3 v. `        而GPIO各个分组的IDR寄存器为32bit宽度的数据,目前只用到低16位字段。# k4 G: Z+ L+ @  w
  1. typedef struct" G5 w) |/ _: T% Q- _5 ^
  2. {
    0 ?) H6 D$ i% R) m
  3.   __IO uint32_t MODER;       /*!< GPIO port mode register,               Address offset: 0x00      */% i  k: _  {. e5 `
  4.   __IO uint32_t OTYPER;      /*!< GPIO port output type register,        Address offset: 0x04      */
    # Z" i* a  i; D/ G
  5.   __IO uint32_t OSPEEDR;     /*!< GPIO port output speed register,       Address offset: 0x08      */  N) D  ^+ d/ O
  6.   __IO uint32_t PUPDR;       /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */: c* @) K; G$ \8 p& s; k9 P
  7.   __IO uint32_t IDR;         /*!< GPIO port input data register,         Address offset: 0x10      */
    ( v  ], Y9 n" L6 @4 Q' [% k8 D
  8.   __IO uint32_t ODR;         /*!< GPIO port output data register,        Address offset: 0x14      */) ~( \" C" l# _, n
  9.   __IO uint32_t BSRR;        /*!< GPIO port bit set/reset  register,     Address offset: 0x18      */1 F$ M& M& G8 q
  10.   __IO uint32_t LCKR;        /*!< GPIO port configuration lock register, Address offset: 0x1C      */: H- \5 `" r6 y  q2 J
  11.   __IO uint32_t AFR[2];      /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
    3 i+ [8 _/ o( @: M% p
  12.   __IO uint32_t BRR;         /*!< GPIO Bit Reset register,               Address offset: 0x28      */
    - @) p2 x- M  @7 S/ @: E, j
  13. 9 Q- c- k6 ]9 s9 p
  14. } GPIO_TypeDef;
复制代码

/ G$ G' T8 D4 P8 s        第三种引脚标记其实就是在第二种方式基础上,为引脚设置别名,在cubeMX设置引脚mode后,会开启该引脚,在引脚参数设置列表可以设置该引脚标识名,例如下图,设置PE3(P2)为输出模式(GPIO_Output),的别名为LED1。
* ~! G: m5 f6 C- M1 O& u
. z6 P  S% K* e! P% Y6 h
1908ec9006fa426faac892a293dd6106.png 2 W( `% D; P4 i. O9 P

3 n8 ]- L4 r/ p. y         那么在生成输出代码时,会通过#define实现标识名替换。& U- A" A/ E6 p% r
! J' s0 t5 m: y4 Q+ z. f
b9d7b04778e74d8b80a5ec7608bbc59d.png
4 H2 i/ \( E" ?
; V. U+ X! y/ V3 \3 X& J7 Z% c

: w# A) a: c) Q7 \9 t& r         1.4 GPIO原理框图及CubeMX配置
7 U. g. A$ h" R% t0 b1 M
        进一步,再看看GPIO结构原理图,它支持4种GPIO输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种GPIO输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。因此才能通过多种输入输出模式组合来实现更复杂的其他外设功能。/ C, I  }+ i+ [1 W

. M/ P# t& x6 N# Z4 |
ad01c8e1a5f443f897e519e3299fd597.png
2 \7 Q1 x' s1 s& _" k# ?8 }' L* M4 e* s* V# Z5 f! L
         在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输入模式以及其他参数设置。  y$ `; t# e1 p- F
* g: ?9 _! ?2 ~2 a1 k- ]
cc3f4397f52e4e3191f4f3611e0c0b07.png ' f7 w/ w  H' a
: v1 X; M3 s, t1 m. ~
         同样地,在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输出模式以及其他参数设置。
  Y8 a1 D5 B! C5 m
- ~" c% X, H. N3 l+ {/ C
e9a0da7fcdbc4c0dbea4ecc489aaeeff.png
. ?& {6 {% V- {0 B4 Q8 K
5 M6 h: Z- Z# [( O" x  N( r2 k        另外各种基于GPIO组合实现的外设,也可在GPIO栏的各个外设页面下,单独设置各个引脚的GPIO输入或输出模式。
6 e, X. z' g$ z1 R
4 M3 m* B4 T4 N8 u) x3 w% e7 d, ?
40f1f5a7010642cdb1fa273713535630.png
- w3 V9 w7 Z/ A" M/ a+ h, z% {  |3 m4 v
& H) _& Z' p! j2 D4 x
二、GPIO的HLA源码分析6 B& w1 z+ w6 W
        2.1 HLA库GPIO初始化

! P, ^) a# s+ H6 @        通过cubeMX生成输出源码,如果配置GPIO引脚功能,则cubeMX生成代码时,设置了为每个外设生成独立.h/.c文件时,会在Core源码目录下的Inc及Src目录,分别生成gpio.h和gpio.c驱动文件,否则将会GPOI相关输出函数放置main.h和main.c中。' w: T1 @8 a) U/ E7 X+ n- W

3 b  v/ i3 C4 `- |. J$ x        在gpio.c文件中,主要定义了MX_GPIO_Init函数,该主要做三件事情,一是启动各个GPIO分组寄存器的时钟,二是对于输出GPIO引脚实现初始值写入,三是将在cubeMX上配置引脚参数写入到参数缓存区域,并依据缓存参数,调用HLA库的HAL_GPIO_Init来实现真正的初始化设定。如下面代码所示。
7 y, i* c% U5 `! }( i
0 l3 F' U: n! [0 j0 ]  a
  1. //main.h  v6 i( k  Z' G1 n  L
  2. /* Private defines -----------------------------------------------------------*/5 t$ I7 R* K5 C* N0 O( i( |
  3. #define LED1_Pin GPIO_PIN_3
      V) l, g0 Q8 S( G
  4. #define LED1_GPIO_Port GPIOE
    ' m0 t  j! T5 {; J
  5. #define KEY2_Pin GPIO_PIN_10/ U: E6 A* s& y4 m, p1 f
  6. #define KEY2_GPIO_Port GPIOE% {1 f- Z: l5 ^" J5 c
  7. #define KEY0_Pin GPIO_PIN_118 g. ?1 E3 s) c: e
  8. #define KEY0_GPIO_Port GPIOE+ @7 ]# u" {! E: `+ t
  9. #define KEY1_Pin GPIO_PIN_14# d" d) y. M# z2 ]; A# Q* A
  10. #define KEY1_GPIO_Port GPIOE
    ! T1 `$ c7 f# J  t
  11. #define LED2_Pin GPIO_PIN_15. l- i5 b4 X3 O/ d" i4 @  _
  12. #define LED2_GPIO_Port GPIOD7 x* q3 X; U' Y) G! M
  13. #define LED0_Pin GPIO_PIN_6! S% Q. m7 E7 q( }  h
  14. #define LED0_GPIO_Port GPIOB9 d  _2 r+ ^) E
  15. /* USER CODE BEGIN Private defines */
    3 P- d1 ^) g& ^" V
  16. //gpio.c. K5 v2 D9 K* I  M) F- n( D
  17. void MX_GPIO_Init(void)
    5 }7 y+ \, {8 p  w8 \+ e7 y
  18. {
    0 P& S# n9 o' N- ]* D" q- m

  19. + E# B. m. \" L/ k/ ~$ @, A
  20.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    2 p+ V: x6 d' z( b8 Z  c
  21. * S* {8 n3 d: _. ^, p5 M; Q6 V
  22.   /* GPIO Ports Clock Enable */
    2 u( C$ P0 N4 U6 T: q5 c3 B, h
  23.   __HAL_RCC_GPIOE_CLK_ENABLE();- g0 H: d$ G$ R  s8 v/ I! ~- ^
  24.   __HAL_RCC_GPIOC_CLK_ENABLE();
    8 y: Y* m% Q! x
  25.   __HAL_RCC_GPIOH_CLK_ENABLE();0 {: o6 O$ a0 j2 N5 D0 \
  26.   __HAL_RCC_GPIOB_CLK_ENABLE();
    + Q4 X( x" k8 T8 L+ C" }
  27.   __HAL_RCC_GPIOD_CLK_ENABLE();
    / J$ C) `9 M1 k) Z% o' ]9 [
  28.   __HAL_RCC_GPIOA_CLK_ENABLE();
    2 ~# S9 q6 U! H' I4 K0 c

  29. - ^- g' R* a+ o4 v; ]
  30.   /*Configure GPIO pin Output Level */0 L0 d& T+ w9 J9 g9 l. g3 |
  31.   HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
    - x6 E7 q' J. ^1 g$ d% o6 D. m( O6 n

  32. . Y; K+ B' T$ T- A$ G( ]: j$ I* G
  33.   /*Configure GPIO pin Output Level */
    - b1 r! c( L7 Y" f* e9 p3 S
  34.   HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
    / f1 ~' M2 l! I9 Q6 [0 @

  35. + @8 k. j3 L: a2 o$ o& |( ?- v/ l
  36.   /*Configure GPIO pin Output Level */
    3 @# q  W8 m5 c9 A: W2 p: I
  37.   HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);4 Q, m* Y( c) u) G; O6 B% A: S
  38. ; A2 g- x- g6 V
  39.   /*Configure GPIO pin : PtPin */1 m2 i, A" X8 \# x: ~
  40.   GPIO_InitStruct.Pin = LED1_Pin;8 B5 Z. }2 B' F. j( z9 h6 a
  41.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    + V4 }6 j6 h, {$ _2 H
  42.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    9 V1 T" x) S* k' \) C9 C, c$ h
  43.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;# {: z* g. S+ W* O' z; k/ d
  44.   HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);
    - {  j) D. S( V

  45. - U0 s, p( l& T
  46.   /*Configure GPIO pins : PEPin PEPin PEPin */  [( l$ c* w/ q# ~' n& Z# u7 T! Z) w1 M
  47.   GPIO_InitStruct.Pin = KEY2_Pin|KEY0_Pin|KEY1_Pin;, ^( S* y" b  Q2 `" V
  48.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;0 `6 }& |# [! r7 }$ ]
  49.   GPIO_InitStruct.Pull = GPIO_NOPULL;9 z7 i" h/ u: r
  50.   HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);! k: J2 J$ @8 ?# X' ]
  51. 5 @/ S/ R/ c0 ^& L% O
  52.   /*Configure GPIO pin : PtPin */
    1 d( T% I! Y: x9 M- `' @
  53.   GPIO_InitStruct.Pin = LED2_Pin;
    0 W1 o; i/ B- q
  54.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;8 q/ i2 l  s. [  ~, |: }4 `  H
  55.   GPIO_InitStruct.Pull = GPIO_NOPULL;) ?- ~  x4 S/ x, g
  56.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    . `9 @: D9 \2 i$ g
  57.   HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);! a) X5 O/ h+ ^; p3 X' J) O  {, {

  58. 3 Z! |9 Z% g9 U, A4 C, ?' ^
  59.   /*Configure GPIO pin : PtPin */  H- |. }" ]% f
  60.   GPIO_InitStruct.Pin = LED0_Pin;) n5 @5 \" q' E" W" f
  61.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    / n9 n7 s) S" u8 n6 ]6 w
  62.   GPIO_InitStruct.Pull = GPIO_NOPULL;# r: p. s* ^+ Y  ?1 [8 m
  63.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;- a/ Z- d$ J/ `
  64.   HAL_GPIO_Init(LED0_GPIO_Port, &GPIO_InitStruct);
    ( c, r" e  r- d0 Q

  65. . I. x- _/ |" ~. q2 K' n1 n
  66. }
复制代码
& k- H) q/ n1 `, K0 m" D6 n* a
        在stm32l4xx_hal_gpio.c源文件中定义了HAL_GPIO_Init函数,它做以下事情:1)诊断先前缓存配置参数是否合规,2)再将缓存配置参数写入到GPIO的寄存器内,完成GPIO的初始化设定(GPIO 的Mode、Pull、Analog、Alternate、Direction、EXTI等)。/ Z0 i& z7 r6 j1 I4 y( S* y$ i- {
2 ~+ G& {3 {( `$ u' _& T
a6544e520b0d46f9b58ac56b87ac4c1a.png , \5 D. Y: n0 x6 n

+ ^2 @$ a9 e' ?5 [        2.2 GPIO的开发应用接口API简述
, D8 W& L& B' G. Y9 c/ X        除了提供GPIO初始化API外,STM32的HLA针对GPIO还外开发这提供如下API:3 p4 ]6 {  \1 l8 e! r
9 S5 V  B- @! U7 _; @8 I# N
d2a594213a664287863277625ef6c4c9.png
/ L$ X' s% \. W9 S8 [( A6 `0 D: M, q3 Z: q" M, o# D, n0 U, G0 h
         GPIO对数据的读取主要是HAL_GPIO_ReadPin函数,写入主要是HAL_GPIO_WritePin、HAL_GPIO_TogglePin函数,其参数都是GPIO_TypeDef* GPIOx和 uint16_t GPIO_Pin,前者就是前面参数的分组如GPIOA、GPIOB等,后者就是Pin0~Pin15,例如GPIO_PIN_3。
( s5 y( S/ S& o3 B
" i. I# o& o; }3 u* u+ }" G5 J/ C
        关于外部中断回调函数HAL_GPIO_EXTI_Callback,该函数是弱函数
5 J- k9 V. U3 Y5 A/ \5 R2 m
2 ^( T) p0 D4 e) r$ x) t
4003e2f80e2f4b69ad20a5d7d7d78398.png ; Y( Y  F0 s* n( }, J0 q
, K% i7 y' A4 c3 T8 [' d
        若需要使用该函数,使其生效,首先需要在cubeMX配置界面,将GPIO引脚调整为GPIO_EXTI类型
: i3 q9 l  K7 G/ P
  ^$ H# W- H, K1 b
f7622ff6361c46139b2ce314069d95ce.png
3 J; B; T1 d1 r- c3 I7 z9 o; c% ]7 o  l' s- G: l6 @- q  _; Y8 ?8 W# M
        并开启该引脚的中断支持9 k' y) L2 h" I  ]( X* P

& N: f7 A8 N& |: i( A
c22186f18cca4e1d9d30f35b2add8333.png
) Y+ y( a* t* }. P
" d! f- @) b8 n8 t3 c; \- A+ O  C
         就可以重新实现stm32l4xx_hal_gpio.c文件中的HAL_GPIO_EXTI_Callback函数来实现GPIO外部中断回调功能,例如设置如下,则实现按键KEY0按下异常,触发回调函数HAL_GPIO_EXTI_Callback调用,从而实现LED0灯状态反转(点亮或熄灭):
( W2 e3 e2 t# K: p/ j
  1. /* USER CODE BEGIN 0 */2 p/ s6 d. L5 U0 f
  2. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)! {: N; v" {1 g% x8 m+ j
  3. {
    5 _7 |/ |$ e1 A0 f& H( x
  4.         if(GPIO_Pin==KEY0_Pin)$ ^: n2 s; B. [' h
  5.         {
    * Q: {3 ~) `' g
  6.                 static uint32_t key0_count = 0;
    6 t. J+ Y' J8 L' `0 `4 Z
  7.                 printf("this is %lu count for HAL_GPIO_EXTI_Callback!\r\n",key0_count++);
      e" R$ x2 s. H
  8.                 Toggle_led0();//LED0等状态反转一次
    7 \0 w/ R( g' j
  9.         }
    3 g3 F( n" Z8 p
  10. }
    . R# @6 b6 o4 W. u
  11. /* USER CODE END 0 */
复制代码

3 c. J( X' Y& a! l% n         同样地对于外部中断请求函数HAL_GPIO_EXTI_IRQHandler也可以类似地进行调整实现GPIO外部中断触发器调用,从而实现我们需要的业务应用。
. I7 h- H) h: w9 }1 a) l

. t. W6 o% u9 t/ z9 u        GPIO的HLA库中,HAL_GPIO_LockPin函数,主要是操作lock寄存器数值的,lock寄存器会针对GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR等GPIO寄存器配置对应的状态标记,而其他寄存器操作时,会先去lock寄存器读取其使用状态来确定是否能进行相关操作,从而确保防止冲突及达成一致性。$ l! T9 \; {* H" @
————————————————( }6 C9 b7 J+ L9 {3 V
版权声明:py_free-物联智能
, E( b9 |# u# u% n5 F) |如有侵权请联系删除+ u0 S* `8 T. t; p1 @
收藏 评论0 发布时间:2023-4-4 23:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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