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

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

[复制链接]
攻城狮Melo 发布时间:2023-4-4 23:05
一、GPIO介绍
1 o. r. i: x2 J$ U( B        1.1 GPIO 简述
: o& E7 J5 {( B% y" I
        GPIO(General purpose input/output,通用型输入输出),一个引脚可以用于输入、输出或其他特殊功能,PIN脚依现实需要可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO),并多个GPIO一起组合可实现诸如UART、SPI等外设功能。
+ m1 G2 w" F2 ~  u) x5 f9 H6 o
& }6 y$ g2 T6 X& K; c! [6 e        GPIO是通过寄存器操作来实现电平信号输入输出的,对于输入,通过读取输入数据寄存器(IDR,Input Data Register)来确定引脚电位的高低;对于输出,通过写入输出数据寄存器(ODR,Output Data Register)来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它们。GPIO的输出通常可以输出0/1信号,用来实现如LED灯、继电器、蜂鸣器等控制,而GPIO的输入可识别0/1信号,用来实现开关、按键等等动作或状态判定。2 P9 _3 A, C" t' a, p" q: e
  l3 B' n& Q' e+ [
449d07eb68a648aeac94e93fee1899c8.png 2 |. }  X$ d  L0 e
* T5 ~  H$ P- G5 Y0 Y
) {% V9 ?( n0 @* f+ K- r
       1.2 STM32 GPIO寄存器
( }0 B% ?' |1 q! ^  [/ z: S         STM32中GPIO的寄存器是MCU分配的一个连续存储区域,按存储地址划分出不同功能寄存器,如下图所示,有Port mode寄存器、Output Type寄存器等等。0 r, d" N3 D- @! `# a' l) a
. r* m2 z# M0 E  a8 s. a& E3 F
5 U7 _5 q4 }5 z( s% P; t( X
a525eff9cbda4bc586eb33d752192f3d.png
# u& z! n! o8 [6 s: E. U) p* @: \

% F* t$ x& y( W+ a        在HLA库中,这些寄存器的数值(宏定义)通常会放在/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32XXX.h头文件中,供开发者调用,例如STM32L496VGTx的开发板,该头文件具体名是stm32l496xx.h,自8977行起到10008行,具是按上述表宏定义了GPIO各寄存器的各个数据位可设置数据值(偏移(POS)及相应数值)。( \7 S* z' X) S6 }2 f' l

; `2 |1 q7 P3 L4 l( j
f9707b3a86ea43709bbd4febde18a379.png # n; x/ o9 `! I/ O1 ~

( k! a6 g8 _  B# i! {: A        1.3 GPIO引脚与标记+ i/ N  T; z+ l/ ^( A
         在一个STM32 MCU芯片中,所有引脚本质都是GPIO引脚,只是鉴于全GPIO引脚开发者使用起来比较不方便,于是才通过各个GPIO组合形成针对各个外设的IO接口。在CubeMX中,以STM32L496VGTx芯片为例,可以直观看到该芯片有100个引脚:LQFP100,LQFP是封装,100指的是引脚数。; a: W) L) \; d+ a. D

7 c! Q/ f- |# ~3 H( i" R0 o
cd47979d01fe420bbb0a16478916dd41.png
# z+ n1 N# |& m

2 J, I) P5 Y; p$ Y# W  ]5 y        STM32的MCU标记一般有两种,直插IC以半圆条口为标记,贴片IC以小圆点为标记,也有缺口及小点都有标记的。通常将标记圆点或缺口正面朝左上角,左上角的下方脚为第一脚,依次围绕芯片中心逆时针计数,在旋转360度以后,左上角右方角为最后一脚。如上图所示,STM32L496VGTx引脚序号如蓝色字体及箭头所示标记。STM32的MCU的引脚标记有三种方式:
" B4 D6 l/ _, g  r  x) ~8 A+ [& F5 W" l, v6 v$ @/ w* G2 w7 j8 f' |* L4 R
        一种是基于上面所述的100个序号排序P1、Pn等,这种标记目前一般是在直接操作寄存器地址或使用标准库中使用,目前HLA库、LL库已经不提供直接地址偏移方式的API了,而是给没一组分组提供了独立寄存器来处理该组引脚;" U% D$ {6 D; I2 P& o
& T( \  H2 u9 R4 a
        第二种是标准库或HLA库宏定义了引脚分组,一般为A、B、C、...,按大写字母次序网线,目前支持到16组类别,每组为PX0~PX15,其标记就是分组名+0~15序号,例如GPIOB+GPIO_PIN_3。0 s9 U4 P& q/ r( F

7 ]/ c% d$ Z  ~' e3 p# l$ a8 i" p        注意,目前STM32的MCU设计是最大16组类别,支持到256引脚(16*16),通过STM32命名规范可以得知,STM32最做引脚支持到256个,但一般会少于引脚数/16的组数,因为不少引脚在芯片设计时就特别支持了其引脚标识,如VSS、VDD等。另外也不是每组必须0~15序号全用完,分组主要是方便设计及使用时进行引脚区分而已。2 H9 x8 `% [9 Y# x% y

9 t/ U' d% ]4 t
daa905e0158b4400a1341f3edc6203d3.png ) b$ R# \# ~2 i

/ ~  c* a1 S; k% T9 U( j9 q         目前HLA库主要就是这种方式,例如来看看GPIO读取数据的API(HAL_GPIO_ReadPin)实现,主要就是根据引脚序号(0~15)来读取IDR寄存器内对应数据位的数值。) z; c/ h( T0 ~1 a6 e3 |9 t% U3 }

5 {- I) k+ p5 E) G; o
6a026a585a054cb6bd5f0a0bf30d0769.png 0 w, R  h1 F8 J4 t

% C9 g& U) r. C/ y2 w         GPIO分组引脚地址在HLA宏定义数值如下。+ |' D6 y- n( h" U
  1. #define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */6 y4 @. Q8 L/ G
  2. #define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */5 s$ [& w# ]- O7 V  L9 H% D7 C4 d
  3. #define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */
      E* q  P# k* M. j
  4. #define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */  _3 s0 {  F. [' N2 q& q% u
  5. #define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */
    ) [& y$ T% B1 d! }1 v3 s. y  q
  6. #define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */
      T6 V6 P7 E* }; v# ?6 }1 z& o$ o
  7. #define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */$ A3 o& d! b, F7 F7 [& t$ ?+ I- B
  8. #define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */7 P# g8 W* I  K! ^% g
  9. #define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */, ?- Q9 q0 f( [4 y
  10. #define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */: c+ u( s- s+ Y7 V0 v& p1 `
  11. #define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   *// l$ C# T$ M6 F
  12. #define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */
    7 ^- ~* {" w6 L9 j* V
  13. #define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */4 E8 v$ p* g/ W0 P
  14. #define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */! R2 _  n2 T4 E
  15. #define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */1 g2 u' e9 x9 s- F: Z/ L
  16. #define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */
    5 `/ X( ?8 T% p* [3 k7 V
  17. #define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */
复制代码

8 _" n* x+ b9 W        而GPIO各个分组的IDR寄存器为32bit宽度的数据,目前只用到低16位字段。
3 q. O6 p# n; \
  1. typedef struct
    . ]( ]% M4 F' @& s
  2. {1 F3 s. @) b5 S/ A
  3.   __IO uint32_t MODER;       /*!< GPIO port mode register,               Address offset: 0x00      */
    + {2 Y( |0 h9 b* v8 w
  4.   __IO uint32_t OTYPER;      /*!< GPIO port output type register,        Address offset: 0x04      */- q0 B6 U/ N/ i% I7 w
  5.   __IO uint32_t OSPEEDR;     /*!< GPIO port output speed register,       Address offset: 0x08      */% b' r% |3 X# A
  6.   __IO uint32_t PUPDR;       /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */. ?; y( n9 }+ B7 t- o5 l
  7.   __IO uint32_t IDR;         /*!< GPIO port input data register,         Address offset: 0x10      */
    ' ~- F- f+ p* ~( a
  8.   __IO uint32_t ODR;         /*!< GPIO port output data register,        Address offset: 0x14      */
    3 m+ D8 X: K& O4 ^6 z/ I
  9.   __IO uint32_t BSRR;        /*!< GPIO port bit set/reset  register,     Address offset: 0x18      */
    # ?3 H% ~2 D* e/ F+ ~
  10.   __IO uint32_t LCKR;        /*!< GPIO port configuration lock register, Address offset: 0x1C      */
    1 A8 Q3 Y; ^0 O
  11.   __IO uint32_t AFR[2];      /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
    1 s4 r$ h! F* I% f% |0 X) {
  12.   __IO uint32_t BRR;         /*!< GPIO Bit Reset register,               Address offset: 0x28      */2 K8 a0 f% a, o
  13. 4 c% c, U7 }" I! M& c. q9 t
  14. } GPIO_TypeDef;
复制代码

+ h5 i# u# i2 n        第三种引脚标记其实就是在第二种方式基础上,为引脚设置别名,在cubeMX设置引脚mode后,会开启该引脚,在引脚参数设置列表可以设置该引脚标识名,例如下图,设置PE3(P2)为输出模式(GPIO_Output),的别名为LED1。
, p3 Y" e; L& q9 @! ^3 t
8 I- G0 L/ T1 Q/ J' M
1908ec9006fa426faac892a293dd6106.png
( R: A7 }# Z9 b" s1 R' \8 k, r$ {$ L4 l) i  T9 E
         那么在生成输出代码时,会通过#define实现标识名替换。* i. ^( Y& h1 \7 E4 e& L# R
# a  E" m, h- Y" Q. W
b9d7b04778e74d8b80a5ec7608bbc59d.png
3 C) @- [+ n6 d  L- G
/ v9 q) I, m; h- {7 e, R

+ o- A4 ^4 [6 U# T) o         1.4 GPIO原理框图及CubeMX配置
8 W1 y# v  E" P% \& q
        进一步,再看看GPIO结构原理图,它支持4种GPIO输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种GPIO输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。因此才能通过多种输入输出模式组合来实现更复杂的其他外设功能。
; d; D! _, e  K0 v
- N) [8 a! p; f0 _/ a: j
ad01c8e1a5f443f897e519e3299fd597.png
* Q1 p! g) l/ y1 R
/ e6 j$ T2 {% S& h( E7 i         在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输入模式以及其他参数设置。3 B" P7 M* x, `4 N
- @9 m" ~8 M" C4 P7 H6 D" q
cc3f4397f52e4e3191f4f3611e0c0b07.png % g4 s. k/ s; j' u! z6 b6 j' w
. C% T4 h% {- L) |
         同样地,在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输出模式以及其他参数设置。
  J+ k, u( X; f
* _  u+ ~$ M) e
e9a0da7fcdbc4c0dbea4ecc489aaeeff.png # s' z8 K: Z* \6 n' N5 P4 n
; ?) ?' Z- l: Q) R/ @" ?: R8 @/ ^
        另外各种基于GPIO组合实现的外设,也可在GPIO栏的各个外设页面下,单独设置各个引脚的GPIO输入或输出模式。
  M2 p, M9 l/ ?3 ~5 T6 X( n
- W& M& E1 e8 f/ r: t
40f1f5a7010642cdb1fa273713535630.png
$ a& M& _, {& y! O' ]4 R

" `  D8 J) R4 Y( o 二、GPIO的HLA源码分析
& C7 n- f# l' L0 @2 Z; M; T        2.1 HLA库GPIO初始化

+ m) D6 x' m% k4 b( T4 U4 Y        通过cubeMX生成输出源码,如果配置GPIO引脚功能,则cubeMX生成代码时,设置了为每个外设生成独立.h/.c文件时,会在Core源码目录下的Inc及Src目录,分别生成gpio.h和gpio.c驱动文件,否则将会GPOI相关输出函数放置main.h和main.c中。
. F7 J8 }, i4 h7 ~" o8 S% R, Q: k9 U
        在gpio.c文件中,主要定义了MX_GPIO_Init函数,该主要做三件事情,一是启动各个GPIO分组寄存器的时钟,二是对于输出GPIO引脚实现初始值写入,三是将在cubeMX上配置引脚参数写入到参数缓存区域,并依据缓存参数,调用HLA库的HAL_GPIO_Init来实现真正的初始化设定。如下面代码所示。
, |# b- j8 g# [# l! }7 X) d( p& T! ~) M8 O5 I8 K( p2 A1 Y
  1. //main.h* ^2 O! ?$ r5 e$ U
  2. /* Private defines -----------------------------------------------------------*/+ ~2 a6 t& d, d
  3. #define LED1_Pin GPIO_PIN_3
    % c7 d; |& K# I
  4. #define LED1_GPIO_Port GPIOE( E+ s! B3 M. c, k4 i5 S3 z. Z
  5. #define KEY2_Pin GPIO_PIN_10
    5 P) X" v+ H7 _; U2 a) a$ j2 S
  6. #define KEY2_GPIO_Port GPIOE
    * [# z7 C# V, l! q' B' f
  7. #define KEY0_Pin GPIO_PIN_11
    9 P9 U/ }) j# _* n8 r& L
  8. #define KEY0_GPIO_Port GPIOE% w! ~% [$ q1 Q  ^8 c  _" O: U7 w
  9. #define KEY1_Pin GPIO_PIN_14
    ) O+ i8 V5 a' p
  10. #define KEY1_GPIO_Port GPIOE2 I6 @( s7 w: Z5 W6 E5 K, ^6 C
  11. #define LED2_Pin GPIO_PIN_151 }7 Y% [: f9 t! T- S
  12. #define LED2_GPIO_Port GPIOD9 Y, t, f4 w4 }' D
  13. #define LED0_Pin GPIO_PIN_6# ^) {7 _6 Z7 k' O
  14. #define LED0_GPIO_Port GPIOB
    " ]( k7 f7 v5 C& m# L/ l
  15. /* USER CODE BEGIN Private defines */% p4 f" ?2 ^; w: O4 q* ?
  16. //gpio.c. ?0 S( H/ E4 d& L5 ?
  17. void MX_GPIO_Init(void)/ D; k# \& G8 M# e* a
  18. {$ \3 k. p7 t6 l' q4 R1 a
  19. - E/ {9 j. z" L  M1 g2 ?
  20.   GPIO_InitTypeDef GPIO_InitStruct = {0};: x! J& r* ~# c: O! M- _$ n

  21. 5 N$ D) j6 a. l4 I; `
  22.   /* GPIO Ports Clock Enable */) k: O% e6 t: A) `$ |0 W: P4 ]
  23.   __HAL_RCC_GPIOE_CLK_ENABLE();/ a( z; |8 N  ^' ~! V1 `
  24.   __HAL_RCC_GPIOC_CLK_ENABLE();) U& B3 q1 H( N. f/ F: Z
  25.   __HAL_RCC_GPIOH_CLK_ENABLE();$ Q) h8 t: H% e6 \6 B* h; B) a
  26.   __HAL_RCC_GPIOB_CLK_ENABLE();
      o+ `, h; u6 \
  27.   __HAL_RCC_GPIOD_CLK_ENABLE();2 q( b+ q: g& G, Q6 |' t
  28.   __HAL_RCC_GPIOA_CLK_ENABLE();
    + r  K1 F, Z% @: I: H( b- q0 e

  29. 7 x3 }0 A0 \$ n  V' J
  30.   /*Configure GPIO pin Output Level */: b' a5 `( o. z
  31.   HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
    " p9 V  V7 S7 ?+ l5 D7 }: n
  32. 7 s+ m' y7 R0 b* F9 ]
  33.   /*Configure GPIO pin Output Level */
    2 Y* R0 O* o( m; t/ x
  34.   HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);8 p1 Z) e, Q) {  I! v  f% O

  35. 2 r+ G' o, Y1 U1 E
  36.   /*Configure GPIO pin Output Level */$ O: t$ c" W! O6 C; [! p
  37.   HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);+ K8 Z: ], _. z) T" X% I( F
  38. 6 j4 t9 K# O7 O5 B# }$ u
  39.   /*Configure GPIO pin : PtPin */
    / V, o( K$ n) t! v( v0 p$ r
  40.   GPIO_InitStruct.Pin = LED1_Pin;+ f  X: ]8 m1 x3 l+ w6 t
  41.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    7 U7 t6 _9 [$ y6 x1 ?( c
  42.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    0 S2 V* g% [  Z' O  j+ h; x
  43.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;$ _6 X" I8 C8 t9 P, z5 L: V" k/ `
  44.   HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);6 V& \8 S9 |  Z* `7 P( m4 X
  45. . M/ j; n& y6 q" R
  46.   /*Configure GPIO pins : PEPin PEPin PEPin */
    9 P6 k2 ^' H8 y# E/ k! U$ x5 w
  47.   GPIO_InitStruct.Pin = KEY2_Pin|KEY0_Pin|KEY1_Pin;
    , Z8 y$ K' t- U" h# \
  48.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;: c7 M8 D. A0 M" q1 ]/ i. y1 A
  49.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    3 I0 x8 z6 O1 U
  50.   HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    $ d$ S2 `: C5 ?

  51. 6 V9 ?' d" E7 @- q1 [5 A% l
  52.   /*Configure GPIO pin : PtPin */1 T3 L4 b: P2 z  X
  53.   GPIO_InitStruct.Pin = LED2_Pin;
    0 R; {6 b9 l5 b9 s/ o! p
  54.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;6 N2 @2 X' p6 V# h
  55.   GPIO_InitStruct.Pull = GPIO_NOPULL;$ \6 R2 m( R* M' k( t9 U
  56.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    6 k2 B5 y- ]1 \3 x5 O& k9 [" k
  57.   HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
    6 t7 B' J8 b. P5 _3 F
  58. ' h  ~% w6 ^- B. B( x
  59.   /*Configure GPIO pin : PtPin */
    # o) q5 E2 X5 a* N/ a/ r
  60.   GPIO_InitStruct.Pin = LED0_Pin;1 s2 C; t! s0 U$ N
  61.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    : Q; r' e# X* ^- O$ ?# ?& v$ ?
  62.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    % J4 U* Q2 \- y3 R
  63.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;3 e* b1 m+ W) }
  64.   HAL_GPIO_Init(LED0_GPIO_Port, &GPIO_InitStruct);
    2 B8 A2 F  I1 g

  65. ( r6 A0 m' f( ~9 B' |
  66. }
复制代码

0 T% x, |8 [: m! D: P! J        在stm32l4xx_hal_gpio.c源文件中定义了HAL_GPIO_Init函数,它做以下事情:1)诊断先前缓存配置参数是否合规,2)再将缓存配置参数写入到GPIO的寄存器内,完成GPIO的初始化设定(GPIO 的Mode、Pull、Analog、Alternate、Direction、EXTI等)。! y4 q* H" _4 {; r4 ?- g& d1 X9 G
, _2 W5 g- e% Q8 ~
a6544e520b0d46f9b58ac56b87ac4c1a.png
# U+ i0 N+ O5 `- n# R9 M2 x6 P# G  k
        2.2 GPIO的开发应用接口API简述
: s; K4 p7 N, x4 o5 c5 x        除了提供GPIO初始化API外,STM32的HLA针对GPIO还外开发这提供如下API:
$ ?  L+ c0 A/ w# N4 \; a( s% F
d2a594213a664287863277625ef6c4c9.png
0 Y3 u. x3 X! u6 Y8 c5 j6 }! C! z8 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。0 I' D& l+ L- d

. ?. i- m* y6 M. X        关于外部中断回调函数HAL_GPIO_EXTI_Callback,该函数是弱函数! }/ K5 k: H. q  ]
& w* P# H( ~3 w: z0 m3 s
4003e2f80e2f4b69ad20a5d7d7d78398.png
& \, |2 s8 z# v7 K1 J# n; Y
# h7 {9 u; Q- K: b: o! B        若需要使用该函数,使其生效,首先需要在cubeMX配置界面,将GPIO引脚调整为GPIO_EXTI类型
6 x( c( j2 h! @& I* {' ?- h6 }
% a5 o; {1 N* \9 D9 r6 B( }3 O
f7622ff6361c46139b2ce314069d95ce.png ; F1 E! `: p9 Y3 g' A$ l! J8 s, c
7 l& U! K) q2 c  n# X/ p
        并开启该引脚的中断支持
6 T8 Z2 i. m( N4 }* }: o
* I9 h6 b0 p6 @! Z
c22186f18cca4e1d9d30f35b2add8333.png , J( a/ o, R! J! k& ]/ L' G3 b
2 E- W, G. m: m" ^7 Z
         就可以重新实现stm32l4xx_hal_gpio.c文件中的HAL_GPIO_EXTI_Callback函数来实现GPIO外部中断回调功能,例如设置如下,则实现按键KEY0按下异常,触发回调函数HAL_GPIO_EXTI_Callback调用,从而实现LED0灯状态反转(点亮或熄灭):7 b7 f" m( F) D( u. W7 r8 \  M5 |
  1. /* USER CODE BEGIN 0 */
    : ]. E  ?3 }5 z" I, w
  2. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)3 A6 J! c2 l! I# R2 l. U- `  I' g
  3. {3 k1 O* n' A5 _: w+ [1 p
  4.         if(GPIO_Pin==KEY0_Pin)" k7 w% i" T! T' v
  5.         {
    4 k& C5 ^* m3 m
  6.                 static uint32_t key0_count = 0;4 u5 f1 i( t: P' F
  7.                 printf("this is %lu count for HAL_GPIO_EXTI_Callback!\r\n",key0_count++);
    # `1 w4 Z5 t0 T  z; W) u  B6 R
  8.                 Toggle_led0();//LED0等状态反转一次* G4 Y0 q  |' R
  9.         }
    & N) a1 |6 C4 L, L1 s
  10. }3 B* v, i9 D" O9 ~4 W( `
  11. /* USER CODE END 0 */
复制代码
; B5 }5 }8 c7 }( q
         同样地对于外部中断请求函数HAL_GPIO_EXTI_IRQHandler也可以类似地进行调整实现GPIO外部中断触发器调用,从而实现我们需要的业务应用。
& ~* O2 N  h( z: N6 n) ^8 J# ?
7 i& x+ C9 Y! _* u( Z, {# y
        GPIO的HLA库中,HAL_GPIO_LockPin函数,主要是操作lock寄存器数值的,lock寄存器会针对GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR等GPIO寄存器配置对应的状态标记,而其他寄存器操作时,会先去lock寄存器读取其使用状态来确定是否能进行相关操作,从而确保防止冲突及达成一致性。
: c+ Q) s6 z+ ]0 r# ~7 ?: O1 N' ?————————————————, I7 r6 a' e- B. h, `4 o
版权声明:py_free-物联智能
# d( V8 [$ r# R, F: ]5 T; d如有侵权请联系删除
) t; j4 Y# K- i6 Z
赞 收藏 评论0 发布时间:2023-4-4 23:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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