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

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

[复制链接]
攻城狮Melo 发布时间:2023-4-4 23:05
一、GPIO介绍. J% ^7 C( I( U1 @& Y
        1.1 GPIO 简述

, m0 u( R7 s, d4 B0 L8 y/ x        GPIO(General purpose input/output,通用型输入输出),一个引脚可以用于输入、输出或其他特殊功能,PIN脚依现实需要可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO),并多个GPIO一起组合可实现诸如UART、SPI等外设功能。9 N: E2 m. d- G, g  G6 o
8 b+ @7 d+ m( z
        GPIO是通过寄存器操作来实现电平信号输入输出的,对于输入,通过读取输入数据寄存器(IDR,Input Data Register)来确定引脚电位的高低;对于输出,通过写入输出数据寄存器(ODR,Output Data Register)来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它们。GPIO的输出通常可以输出0/1信号,用来实现如LED灯、继电器、蜂鸣器等控制,而GPIO的输入可识别0/1信号,用来实现开关、按键等等动作或状态判定。$ B% }% `# O6 Y7 X9 c: G  [' o9 ?& _
* p7 K. h, c. h
449d07eb68a648aeac94e93fee1899c8.png
3 \- v% O4 m; i2 j$ H9 Y* t- [+ K) Y; D- E' O" \. B& g7 U# x

4 c7 W" ?) l) {, x       1.2 STM32 GPIO寄存器* S! P4 `5 O9 m2 e- W9 G
         STM32中GPIO的寄存器是MCU分配的一个连续存储区域,按存储地址划分出不同功能寄存器,如下图所示,有Port mode寄存器、Output Type寄存器等等。
/ `! Z2 m4 K+ s3 z8 t, v" n6 }$ z& A" e# g* Y

9 r' i- }5 `! S4 u+ t a525eff9cbda4bc586eb33d752192f3d.png
2 x0 P% K1 Q! \: n- f

+ L4 B9 l! S0 O/ _" J        在HLA库中,这些寄存器的数值(宏定义)通常会放在/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32XXX.h头文件中,供开发者调用,例如STM32L496VGTx的开发板,该头文件具体名是stm32l496xx.h,自8977行起到10008行,具是按上述表宏定义了GPIO各寄存器的各个数据位可设置数据值(偏移(POS)及相应数值)。
# N  G$ V+ {' Y7 h% z' A" X, h7 i* H' X
f9707b3a86ea43709bbd4febde18a379.png - ?& |, v/ L5 H
* L: W) C2 q( i4 e
        1.3 GPIO引脚与标记
4 A, G2 @2 m# k$ g         在一个STM32 MCU芯片中,所有引脚本质都是GPIO引脚,只是鉴于全GPIO引脚开发者使用起来比较不方便,于是才通过各个GPIO组合形成针对各个外设的IO接口。在CubeMX中,以STM32L496VGTx芯片为例,可以直观看到该芯片有100个引脚:LQFP100,LQFP是封装,100指的是引脚数。0 Y0 u0 `) U2 Q/ |. ^, e
- O* H5 Y* l  W6 _
cd47979d01fe420bbb0a16478916dd41.png $ Q& ^6 x6 F- ^

7 O) f0 k" X: T8 D        STM32的MCU标记一般有两种,直插IC以半圆条口为标记,贴片IC以小圆点为标记,也有缺口及小点都有标记的。通常将标记圆点或缺口正面朝左上角,左上角的下方脚为第一脚,依次围绕芯片中心逆时针计数,在旋转360度以后,左上角右方角为最后一脚。如上图所示,STM32L496VGTx引脚序号如蓝色字体及箭头所示标记。STM32的MCU的引脚标记有三种方式:  d7 _! Y9 i$ Y7 x. I9 v  v. v
- n0 \7 ]% N2 h
        一种是基于上面所述的100个序号排序P1、Pn等,这种标记目前一般是在直接操作寄存器地址或使用标准库中使用,目前HLA库、LL库已经不提供直接地址偏移方式的API了,而是给没一组分组提供了独立寄存器来处理该组引脚;  h/ x# P$ ]" x% \. u

. F, u/ Z; c! s2 d+ D3 p- R3 T) G7 E        第二种是标准库或HLA库宏定义了引脚分组,一般为A、B、C、...,按大写字母次序网线,目前支持到16组类别,每组为PX0~PX15,其标记就是分组名+0~15序号,例如GPIOB+GPIO_PIN_3。
9 Z5 z0 S) L6 ^4 m5 c7 p' n; J' P3 R
        注意,目前STM32的MCU设计是最大16组类别,支持到256引脚(16*16),通过STM32命名规范可以得知,STM32最做引脚支持到256个,但一般会少于引脚数/16的组数,因为不少引脚在芯片设计时就特别支持了其引脚标识,如VSS、VDD等。另外也不是每组必须0~15序号全用完,分组主要是方便设计及使用时进行引脚区分而已。
+ ?/ l2 ?  P  J. T- O$ @) i2 l1 R" u$ B, v  }8 j+ E' i
daa905e0158b4400a1341f3edc6203d3.png
# b1 [, U  b/ m" H: b3 l9 T7 C6 R  s
         目前HLA库主要就是这种方式,例如来看看GPIO读取数据的API(HAL_GPIO_ReadPin)实现,主要就是根据引脚序号(0~15)来读取IDR寄存器内对应数据位的数值。
0 E' \4 [( J2 g/ W
2 G9 |' R7 c' p0 D2 L
6a026a585a054cb6bd5f0a0bf30d0769.png 0 o% u! j: e% ?# g
* I' Z' P6 s) L: U3 q
         GPIO分组引脚地址在HLA宏定义数值如下。
& ~$ `1 L' H; {" i1 s& C: u/ |
  1. #define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */
    - F6 a6 X/ n3 g+ d4 z' ]  N
  2. #define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    *// B2 f4 L( l/ f, a
  3. #define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */
    - B- [( Z9 ?& R4 ~6 M: F
  4. #define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */8 l7 I! T$ p% d  \! B) P) O- L/ T
  5. #define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */9 e: F# A) n3 m
  6. #define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */% z, u- Z7 }, j) z
  7. #define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */$ o! c# y# B) [9 x/ d
  8. #define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */, N/ y5 R4 D7 {  d5 m0 `& r$ p
  9. #define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */
    ) n" o6 J6 t' s" a+ D0 {- a
  10. #define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */6 x2 h+ w# n$ o7 h
  11. #define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */
    + \, U# [- s5 G. g- X3 e
  12. #define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */1 A1 X9 F( [) v) z  u9 q
  13. #define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */
    ! j7 z. R2 P! P* o" e- i8 s6 V; _# V
  14. #define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */
    ' }8 `1 O, E  J' q: ?
  15. #define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */, Q, [% q  n- i( o+ H% F' ?
  16. #define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */
    " f" ?& t9 y2 S# J# U4 L" J
  17. #define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */
复制代码

5 `8 f( j. G+ @9 T        而GPIO各个分组的IDR寄存器为32bit宽度的数据,目前只用到低16位字段。  C8 l3 y: ]! t5 l
  1. typedef struct: C, h5 u3 X% a* W! G- R
  2. {3 C# P# d- q- s
  3.   __IO uint32_t MODER;       /*!< GPIO port mode register,               Address offset: 0x00      */
    ) p" X# l0 X8 g7 O% _1 @7 `
  4.   __IO uint32_t OTYPER;      /*!< GPIO port output type register,        Address offset: 0x04      */
    $ U* E- H" Y& `# \, S1 e, x2 t
  5.   __IO uint32_t OSPEEDR;     /*!< GPIO port output speed register,       Address offset: 0x08      */
    7 L+ |- D9 Z! I; e8 u' o& n- l) z" t
  6.   __IO uint32_t PUPDR;       /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
    9 N* p, @  G2 Z/ d: n
  7.   __IO uint32_t IDR;         /*!< GPIO port input data register,         Address offset: 0x10      */, d" J9 I$ p6 ^( I( A4 s2 I. a
  8.   __IO uint32_t ODR;         /*!< GPIO port output data register,        Address offset: 0x14      */
    / k- F) z$ ^0 r/ b# ~) {) A
  9.   __IO uint32_t BSRR;        /*!< GPIO port bit set/reset  register,     Address offset: 0x18      */% z0 k$ H9 I* A, b- y
  10.   __IO uint32_t LCKR;        /*!< GPIO port configuration lock register, Address offset: 0x1C      */6 r" y* e5 \, y
  11.   __IO uint32_t AFR[2];      /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */: @% @" O5 q) S4 R& J5 r' ]
  12.   __IO uint32_t BRR;         /*!< GPIO Bit Reset register,               Address offset: 0x28      */
    7 V$ M/ I# v3 h9 F2 Q( U2 w
  13. ) ~! q, w: [) n3 q/ t- h
  14. } GPIO_TypeDef;
复制代码
( W8 w0 r* Z8 U, D9 E% W5 E
        第三种引脚标记其实就是在第二种方式基础上,为引脚设置别名,在cubeMX设置引脚mode后,会开启该引脚,在引脚参数设置列表可以设置该引脚标识名,例如下图,设置PE3(P2)为输出模式(GPIO_Output),的别名为LED1。+ I5 o; |4 b+ ?& K  b6 E

$ Q' X! K$ j/ D
1908ec9006fa426faac892a293dd6106.png
$ A* `- o% W* M  W
+ j+ G, s8 H0 r3 u# j         那么在生成输出代码时,会通过#define实现标识名替换。5 a$ J5 I- c" V* o% r1 O, w( v2 S

. e$ r) C3 ~! _$ J- w5 m8 r
b9d7b04778e74d8b80a5ec7608bbc59d.png
: M  ?+ p9 o- e1 V& }8 a+ U5 }$ v) z7 P5 C8 O* s

% ~, R6 E$ ^: O: ]         1.4 GPIO原理框图及CubeMX配置
5 H: w5 Q! v6 t9 t; E
        进一步,再看看GPIO结构原理图,它支持4种GPIO输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种GPIO输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。因此才能通过多种输入输出模式组合来实现更复杂的其他外设功能。
8 [, U- I" Z- W3 M' F0 i0 h9 ]5 K: O" t
ad01c8e1a5f443f897e519e3299fd597.png 0 Q: `/ ~8 ~8 R2 F8 E' q

" x9 h: p7 Q' w6 ^5 R5 O* a# _& h         在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输入模式以及其他参数设置。
* @6 }  Y- m- z7 p0 q0 H" ?1 t1 f& F0 y: H2 p. e7 d
cc3f4397f52e4e3191f4f3611e0c0b07.png
7 u0 s: |* v+ _+ s' h( \2 e9 o& s
$ V$ }/ R$ x% X5 q7 G) i
         同样地,在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输出模式以及其他参数设置。: D. S8 x4 R" E- S6 _$ A; y1 F/ h2 m
0 s8 i/ B8 W2 _* \  x; |2 T
e9a0da7fcdbc4c0dbea4ecc489aaeeff.png ; l( H5 M6 \3 `
; u  S- h; z. E: I
        另外各种基于GPIO组合实现的外设,也可在GPIO栏的各个外设页面下,单独设置各个引脚的GPIO输入或输出模式。; h/ p' G7 t$ w" b
, l9 ]3 b+ j4 a
40f1f5a7010642cdb1fa273713535630.png * Y! L2 t% M/ F9 h

, t$ t7 v4 u) w' X, G( p6 K/ W3 j 二、GPIO的HLA源码分析
, a4 A" R/ v& p. h. }' \0 w6 i; M( N        2.1 HLA库GPIO初始化
: S0 G  w: h3 ?/ ]* G
        通过cubeMX生成输出源码,如果配置GPIO引脚功能,则cubeMX生成代码时,设置了为每个外设生成独立.h/.c文件时,会在Core源码目录下的Inc及Src目录,分别生成gpio.h和gpio.c驱动文件,否则将会GPOI相关输出函数放置main.h和main.c中。
0 `) s: |# Y( K9 U9 u
, w8 E& {6 o' T. F; |2 z: z        在gpio.c文件中,主要定义了MX_GPIO_Init函数,该主要做三件事情,一是启动各个GPIO分组寄存器的时钟,二是对于输出GPIO引脚实现初始值写入,三是将在cubeMX上配置引脚参数写入到参数缓存区域,并依据缓存参数,调用HLA库的HAL_GPIO_Init来实现真正的初始化设定。如下面代码所示。
/ P3 {3 n2 B, O6 w* v* F
$ A) R8 t" O( E' c* Q
  1. //main.h
    ! U! O3 u# t3 K7 H% q
  2. /* Private defines -----------------------------------------------------------*/
    $ |/ J! p0 Q2 `9 G7 g: T# ?% q
  3. #define LED1_Pin GPIO_PIN_3
    ( a. x- e7 F0 x
  4. #define LED1_GPIO_Port GPIOE
    8 N' `1 v7 H- f$ U# c5 t) \* M" J
  5. #define KEY2_Pin GPIO_PIN_10
    4 Q9 B& D* d& ]6 P: P% q
  6. #define KEY2_GPIO_Port GPIOE/ ^% @' M* {$ [4 I
  7. #define KEY0_Pin GPIO_PIN_11; u6 h  J1 N' d% e7 Y7 D: [
  8. #define KEY0_GPIO_Port GPIOE
    7 b/ O  O# P; Q( o8 @8 i2 O" l4 F
  9. #define KEY1_Pin GPIO_PIN_14
    / d, ]$ n$ w3 ]# |8 q5 B& u
  10. #define KEY1_GPIO_Port GPIOE( l+ R, W+ Y9 T1 J) ?, ?
  11. #define LED2_Pin GPIO_PIN_15
    9 ^) }4 m4 G* y: t, N: Z, R4 {
  12. #define LED2_GPIO_Port GPIOD; J1 x7 z/ d0 r
  13. #define LED0_Pin GPIO_PIN_6
    + \+ m& H& r% u
  14. #define LED0_GPIO_Port GPIOB$ @) F2 b4 c+ V9 i7 Q' ?: K
  15. /* USER CODE BEGIN Private defines */
      ^3 T& F6 [. v7 _) W2 b
  16. //gpio.c
    & A* H% ^3 q7 z! R
  17. void MX_GPIO_Init(void)! z. W% ^' B+ H# `! M# r9 ~1 M
  18. {7 U, E' ]: w" r$ v0 O2 u9 C- \: `
  19. 3 O; v. A6 \: a1 y
  20.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    , U' U9 K4 y2 j' _6 e8 `

  21. + o9 M0 O" I! Y
  22.   /* GPIO Ports Clock Enable */
    9 m8 X# N6 a1 C& s
  23.   __HAL_RCC_GPIOE_CLK_ENABLE();
      E1 V+ B8 N" X. C2 _
  24.   __HAL_RCC_GPIOC_CLK_ENABLE();/ U7 n. G& [! {7 Z) U9 r) l
  25.   __HAL_RCC_GPIOH_CLK_ENABLE();
    , \  i! @; c% S4 Q% ^' J
  26.   __HAL_RCC_GPIOB_CLK_ENABLE();% t4 n0 V( W* q8 _5 z, h( |* g' x
  27.   __HAL_RCC_GPIOD_CLK_ENABLE();0 u. P) `3 {0 R" R8 {
  28.   __HAL_RCC_GPIOA_CLK_ENABLE();9 R/ a, K' Y! \- E

  29. 7 v% @+ O$ E' E  p
  30.   /*Configure GPIO pin Output Level */
    7 Z+ l8 @+ k: c- D/ U
  31.   HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);- o9 l0 T& j. L1 H% F7 h* V
  32.   \* F; @- l) @0 z
  33.   /*Configure GPIO pin Output Level */5 |9 p$ t! @; J0 P
  34.   HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);+ z2 {, g8 f' Q# g6 m

  35. , q8 {- B+ t! a( d5 I
  36.   /*Configure GPIO pin Output Level */
    " v4 T' g7 E: U, R
  37.   HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
    : i$ Q/ D; J; q- i

  38. 5 y  S  }9 m7 T' ^6 F4 a: Q
  39.   /*Configure GPIO pin : PtPin */
    : b1 X: |  C* P
  40.   GPIO_InitStruct.Pin = LED1_Pin;
    4 _; j2 Y9 o& l1 P5 v
  41.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    ) e( ]6 `( ]3 z! L. Z3 Z
  42.   GPIO_InitStruct.Pull = GPIO_NOPULL;3 }: e  A8 P2 G
  43.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;% J  \" P1 s( b
  44.   HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);/ D0 t2 f. w' m7 D

  45. ; T5 u; b4 M" P( O$ z/ g
  46.   /*Configure GPIO pins : PEPin PEPin PEPin */
    - ?- T2 o: N3 t! x+ }$ y, {' q
  47.   GPIO_InitStruct.Pin = KEY2_Pin|KEY0_Pin|KEY1_Pin;1 p$ l& @! Z% @4 V/ o* Y9 o& }
  48.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;% F8 E. G& \6 v9 a8 R+ G
  49.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    9 c/ O: C* B# c" K( A9 p4 P1 ]
  50.   HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    5 B: L4 p+ k; c  z( R

  51. " Y, ^: C+ q. J) Y* s4 m
  52.   /*Configure GPIO pin : PtPin */
    3 \" s$ T2 Z& A; q- d" v' }
  53.   GPIO_InitStruct.Pin = LED2_Pin;
    + q6 R5 N: Z2 u5 a
  54.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;' C& I7 h" z9 O& T8 U7 z3 s5 ^
  55.   GPIO_InitStruct.Pull = GPIO_NOPULL;1 c+ a+ z8 X# N5 J' T8 ~# D5 y
  56.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    6 M; {' t0 d+ B. i5 y
  57.   HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
    2 o* `+ C* U% ^, l/ H: y1 [" X/ {
  58. / f; E& o+ j$ j% j, v) k
  59.   /*Configure GPIO pin : PtPin */
    # y6 I$ g: B) F/ v5 y  m" ]$ `
  60.   GPIO_InitStruct.Pin = LED0_Pin;0 T- N$ n- ]8 H4 ?$ z' `
  61.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    7 ?7 [6 j. i! t# P9 i2 D
  62.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    + c* h( M* p$ F; L
  63.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    ' N9 l8 P! [0 h( i
  64.   HAL_GPIO_Init(LED0_GPIO_Port, &GPIO_InitStruct);6 Q% o* a1 M+ m8 _' K" c" Y

  65. 0 e/ q  d# l1 `% o
  66. }
复制代码
6 p3 T- P- |! Y
        在stm32l4xx_hal_gpio.c源文件中定义了HAL_GPIO_Init函数,它做以下事情:1)诊断先前缓存配置参数是否合规,2)再将缓存配置参数写入到GPIO的寄存器内,完成GPIO的初始化设定(GPIO 的Mode、Pull、Analog、Alternate、Direction、EXTI等)。
* ^! l/ q- |1 k: `
) {# r/ c% h" l- a( O
a6544e520b0d46f9b58ac56b87ac4c1a.png , w$ V, J/ B8 F) p! C( c7 |
2 s7 R9 D9 e+ _4 J0 n" C
        2.2 GPIO的开发应用接口API简述: M- G1 g; L( W7 |/ I8 }
        除了提供GPIO初始化API外,STM32的HLA针对GPIO还外开发这提供如下API:! r- ]) R% l3 ~, D2 l

+ i7 w5 U6 X" z; G' d. j
d2a594213a664287863277625ef6c4c9.png
" J/ t& M* Z" b- p4 ?! b5 [: ?$ z- ?
         GPIO对数据的读取主要是HAL_GPIO_ReadPin函数,写入主要是HAL_GPIO_WritePin、HAL_GPIO_TogglePin函数,其参数都是GPIO_TypeDef* GPIOx和 uint16_t GPIO_Pin,前者就是前面参数的分组如GPIOA、GPIOB等,后者就是Pin0~Pin15,例如GPIO_PIN_3。
1 `/ X- C, O# z4 \. ^/ N* }$ r% u- x

. [# T, _4 G6 E9 c% N# T* z, `0 G        关于外部中断回调函数HAL_GPIO_EXTI_Callback,该函数是弱函数
9 B' ~7 r7 O9 ?" P9 M
- u# m( n3 T+ j& e3 I; q
4003e2f80e2f4b69ad20a5d7d7d78398.png
  j! L9 }0 t# J7 [( G( @7 I( W2 M: T  {" b. A) ^
        若需要使用该函数,使其生效,首先需要在cubeMX配置界面,将GPIO引脚调整为GPIO_EXTI类型: r9 ?/ N; d5 Z, ^/ c: U0 I/ _

" t/ a& ]( b2 X! h( a' v  W7 a+ ]
f7622ff6361c46139b2ce314069d95ce.png 9 F" n/ ^& r$ D" d, ~0 Y
7 h( V- _2 ~9 T
        并开启该引脚的中断支持3 `" c7 m( z  l0 R1 P( ^3 A
: n9 R8 M3 _3 V  ~, ]  k  Y1 m% l
c22186f18cca4e1d9d30f35b2add8333.png ! @/ O4 j, |( v: o3 _

+ {9 o# Y* t( c  n5 g$ A0 U         就可以重新实现stm32l4xx_hal_gpio.c文件中的HAL_GPIO_EXTI_Callback函数来实现GPIO外部中断回调功能,例如设置如下,则实现按键KEY0按下异常,触发回调函数HAL_GPIO_EXTI_Callback调用,从而实现LED0灯状态反转(点亮或熄灭):
0 a) _3 K$ l! g- Z+ V8 Q, _
  1. /* USER CODE BEGIN 0 */
      u# u/ D4 V+ R& [3 a6 ~
  2. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)0 P4 O* @7 F! \- l0 s. v1 ~
  3. {/ _. H* v9 m8 l
  4.         if(GPIO_Pin==KEY0_Pin)% c' q* N7 Q! u8 Y- \
  5.         {
    $ Y& t( C: [; X" B0 v1 l" k* ^
  6.                 static uint32_t key0_count = 0;. E; t& V. t3 B- g6 z+ B
  7.                 printf("this is %lu count for HAL_GPIO_EXTI_Callback!\r\n",key0_count++);+ U$ ^! P% @+ m+ z/ d% X
  8.                 Toggle_led0();//LED0等状态反转一次
    ' j; }" R8 Y/ [" c
  9.         }2 l) ~% Q0 m0 I9 O  Y2 _. u" v
  10. }0 m5 K9 j+ X: {, i# B8 {
  11. /* USER CODE END 0 */
复制代码

  Y. P" u; h+ `/ R4 ]         同样地对于外部中断请求函数HAL_GPIO_EXTI_IRQHandler也可以类似地进行调整实现GPIO外部中断触发器调用,从而实现我们需要的业务应用。; ?4 a. r# h, ?1 Z- C: S

2 C$ A# t! a6 {: ~" v        GPIO的HLA库中,HAL_GPIO_LockPin函数,主要是操作lock寄存器数值的,lock寄存器会针对GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR等GPIO寄存器配置对应的状态标记,而其他寄存器操作时,会先去lock寄存器读取其使用状态来确定是否能进行相关操作,从而确保防止冲突及达成一致性。7 O* p4 |$ i2 r, @; v* U9 x; X: E
————————————————% w  O" \/ M& a
版权声明:py_free-物联智能7 v4 Y) A- {$ q5 \% V& }% j
如有侵权请联系删除
- B( m: N$ q7 `8 w7 t6 ]
赞 收藏 评论0 发布时间:2023-4-4 23:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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