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

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

[复制链接]
攻城狮Melo 发布时间:2023-4-4 23:05
一、GPIO介绍) X( K" K3 a- h
        1.1 GPIO 简述

* [5 C- u( [! v0 o9 X        GPIO(General purpose input/output,通用型输入输出),一个引脚可以用于输入、输出或其他特殊功能,PIN脚依现实需要可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO),并多个GPIO一起组合可实现诸如UART、SPI等外设功能。- D  D7 `' ~& {4 Z
* a% S& z/ ~' \3 c1 Y9 S4 ?5 t
        GPIO是通过寄存器操作来实现电平信号输入输出的,对于输入,通过读取输入数据寄存器(IDR,Input Data Register)来确定引脚电位的高低;对于输出,通过写入输出数据寄存器(ODR,Output Data Register)来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它们。GPIO的输出通常可以输出0/1信号,用来实现如LED灯、继电器、蜂鸣器等控制,而GPIO的输入可识别0/1信号,用来实现开关、按键等等动作或状态判定。; u! y0 k& Q! b4 F8 s
7 j; x+ K/ M; l  K4 \- Z
449d07eb68a648aeac94e93fee1899c8.png ; H/ h$ i4 v, ]4 e3 s
5 e# k$ [8 S$ S0 X

* l" U2 j1 _: Q2 K, K       1.2 STM32 GPIO寄存器" h: \7 f' ^) L; G2 v# y
         STM32中GPIO的寄存器是MCU分配的一个连续存储区域,按存储地址划分出不同功能寄存器,如下图所示,有Port mode寄存器、Output Type寄存器等等。
( Z; }, y7 ^1 y" s7 p9 i# j( Z7 K
: Q" ?3 V  R6 ?7 _% j7 B2 U
0 e% J% q% O  S% o. ~0 d
a525eff9cbda4bc586eb33d752192f3d.png
$ w, T/ s9 x; a7 ]0 p5 j2 v0 e. x
( L- l1 p  h; G' v" b) k; s# a
        在HLA库中,这些寄存器的数值(宏定义)通常会放在/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32XXX.h头文件中,供开发者调用,例如STM32L496VGTx的开发板,该头文件具体名是stm32l496xx.h,自8977行起到10008行,具是按上述表宏定义了GPIO各寄存器的各个数据位可设置数据值(偏移(POS)及相应数值)。  m' T9 n: j/ B* F) }( E
/ r4 }" c" P: y
f9707b3a86ea43709bbd4febde18a379.png
" a4 k) q. z' [: M. |1 f$ d6 ]& D1 g7 [8 N3 j; `
        1.3 GPIO引脚与标记
" I* I, s4 W+ d. w5 x( D2 W         在一个STM32 MCU芯片中,所有引脚本质都是GPIO引脚,只是鉴于全GPIO引脚开发者使用起来比较不方便,于是才通过各个GPIO组合形成针对各个外设的IO接口。在CubeMX中,以STM32L496VGTx芯片为例,可以直观看到该芯片有100个引脚:LQFP100,LQFP是封装,100指的是引脚数。
3 f# j- f! e0 x; B
: ?+ z5 V8 n9 p  e
cd47979d01fe420bbb0a16478916dd41.png ' c1 }# {4 J0 Q

: q- ^; A  b( M; s2 a: ?5 N1 q        STM32的MCU标记一般有两种,直插IC以半圆条口为标记,贴片IC以小圆点为标记,也有缺口及小点都有标记的。通常将标记圆点或缺口正面朝左上角,左上角的下方脚为第一脚,依次围绕芯片中心逆时针计数,在旋转360度以后,左上角右方角为最后一脚。如上图所示,STM32L496VGTx引脚序号如蓝色字体及箭头所示标记。STM32的MCU的引脚标记有三种方式:
) `, n% G, n, ^6 S: B; J! D
# R5 Y2 x2 L( E; m
        一种是基于上面所述的100个序号排序P1、Pn等,这种标记目前一般是在直接操作寄存器地址或使用标准库中使用,目前HLA库、LL库已经不提供直接地址偏移方式的API了,而是给没一组分组提供了独立寄存器来处理该组引脚;
9 I! T# ~$ Z$ @" G5 E- {  c
' m) r$ T! ^0 g( p  ~        第二种是标准库或HLA库宏定义了引脚分组,一般为A、B、C、...,按大写字母次序网线,目前支持到16组类别,每组为PX0~PX15,其标记就是分组名+0~15序号,例如GPIOB+GPIO_PIN_3。
. b7 L% J- j/ f
% @0 X2 B9 i; s5 D* q" `        注意,目前STM32的MCU设计是最大16组类别,支持到256引脚(16*16),通过STM32命名规范可以得知,STM32最做引脚支持到256个,但一般会少于引脚数/16的组数,因为不少引脚在芯片设计时就特别支持了其引脚标识,如VSS、VDD等。另外也不是每组必须0~15序号全用完,分组主要是方便设计及使用时进行引脚区分而已。
) r6 Q. K$ s1 W" _' t5 g3 Y$ x, `6 u7 j$ y
daa905e0158b4400a1341f3edc6203d3.png
' B. G6 \4 N/ s! ?
7 s/ Z1 f, B* T6 H! E* ]0 r5 Q         目前HLA库主要就是这种方式,例如来看看GPIO读取数据的API(HAL_GPIO_ReadPin)实现,主要就是根据引脚序号(0~15)来读取IDR寄存器内对应数据位的数值。
% A; c7 T" ?# F3 k% g7 S' y9 A  i( v8 Q  W6 g
6a026a585a054cb6bd5f0a0bf30d0769.png 4 I% k2 a8 V! T# n- D: d1 C( X7 _
! O3 c' A$ X: t% r# }( J1 ]% h$ ?
         GPIO分组引脚地址在HLA宏定义数值如下。
- \3 H1 o  h6 {% b$ w% b) @
  1. #define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */
    - S% W6 ~, H/ ]6 m+ [' n
  2. #define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */
    9 b: ~, x- q9 L( O1 D
  3. #define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */: h* {" r/ ^' I0 @( ]- d
  4. #define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */. @$ r- f* S' c9 D( Z  \6 C" S
  5. #define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */
    8 r+ s6 W7 j0 V; }
  6. #define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */
    : d1 K2 b% z+ \
  7. #define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */
    0 \8 }7 a  q/ `6 G' E' K
  8. #define GPIO_PIN_7                 ((uint16_t)0x0080)  /* Pin 7 selected    */) J% f9 P* m, X$ v2 }
  9. #define GPIO_PIN_8                 ((uint16_t)0x0100)  /* Pin 8 selected    */
    ; f  L8 m. N1 t' H7 E; l  R5 O
  10. #define GPIO_PIN_9                 ((uint16_t)0x0200)  /* Pin 9 selected    */
    / L. F0 Z  b% D! p
  11. #define GPIO_PIN_10                ((uint16_t)0x0400)  /* Pin 10 selected   */
    % e+ _* k) w/ X3 F  Y/ d* @
  12. #define GPIO_PIN_11                ((uint16_t)0x0800)  /* Pin 11 selected   */: [- N2 C% ~: M0 T
  13. #define GPIO_PIN_12                ((uint16_t)0x1000)  /* Pin 12 selected   */
    , q, _" T. G% m" d, w) j, p( S& @% m
  14. #define GPIO_PIN_13                ((uint16_t)0x2000)  /* Pin 13 selected   */0 s7 ~& I, M" t
  15. #define GPIO_PIN_14                ((uint16_t)0x4000)  /* Pin 14 selected   */1 H9 H# ^, a  F# ]& q! u
  16. #define GPIO_PIN_15                ((uint16_t)0x8000)  /* Pin 15 selected   */! s6 s3 @+ y$ q3 }4 _+ E( i
  17. #define GPIO_PIN_All               ((uint16_t)0xFFFF)  /* All pins selected */
复制代码
6 |1 X( k" v1 u4 A/ f
        而GPIO各个分组的IDR寄存器为32bit宽度的数据,目前只用到低16位字段。
3 R* [) a  q* c' L- q
  1. typedef struct3 {1 P) f* B: |) @! |9 E+ |
  2. {0 f# A) b7 u3 u& P; i
  3.   __IO uint32_t MODER;       /*!< GPIO port mode register,               Address offset: 0x00      */
    8 {6 j9 k; B4 h3 y
  4.   __IO uint32_t OTYPER;      /*!< GPIO port output type register,        Address offset: 0x04      */
    # s0 a! s/ M9 \4 O1 e/ H
  5.   __IO uint32_t OSPEEDR;     /*!< GPIO port output speed register,       Address offset: 0x08      */' K0 O' e! ?. B
  6.   __IO uint32_t PUPDR;       /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */# _- P8 c: @2 {/ u
  7.   __IO uint32_t IDR;         /*!< GPIO port input data register,         Address offset: 0x10      */
    : y6 a8 S1 H( c- J+ \7 i
  8.   __IO uint32_t ODR;         /*!< GPIO port output data register,        Address offset: 0x14      */
    - U3 A! u0 `8 c1 H
  9.   __IO uint32_t BSRR;        /*!< GPIO port bit set/reset  register,     Address offset: 0x18      */9 L( l- q7 d6 s7 u  R! H) Y
  10.   __IO uint32_t LCKR;        /*!< GPIO port configuration lock register, Address offset: 0x1C      */
    4 L5 r+ q0 \/ o. |( h3 s4 K
  11.   __IO uint32_t AFR[2];      /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */) s: w/ O& H8 g
  12.   __IO uint32_t BRR;         /*!< GPIO Bit Reset register,               Address offset: 0x28      */
    ( ?. Z8 d& U: t% R1 b; n" o
  13. 4 k9 r) f6 ~# u
  14. } GPIO_TypeDef;
复制代码
3 F; V3 B  B" r, k. G
        第三种引脚标记其实就是在第二种方式基础上,为引脚设置别名,在cubeMX设置引脚mode后,会开启该引脚,在引脚参数设置列表可以设置该引脚标识名,例如下图,设置PE3(P2)为输出模式(GPIO_Output),的别名为LED1。& d; I" m2 O: d5 h- E$ x3 d

  |& {" @0 {& P% P/ p( n# R, \
1908ec9006fa426faac892a293dd6106.png
3 C7 r/ C/ S, X6 Z7 S- O+ U: s1 j6 d( a, [1 S. ]9 N" j0 `
         那么在生成输出代码时,会通过#define实现标识名替换。
, e' O4 U: N" ]* n) ]* w' R' {  W  ^/ ?0 J2 v
b9d7b04778e74d8b80a5ec7608bbc59d.png # I- m+ W' m& z; O, i
2 k6 k$ T& E: t4 F/ R
4 @0 ~: I3 d% o8 Q& z- T. [& y* [
         1.4 GPIO原理框图及CubeMX配置

! M8 u4 b- X; S7 D7 {; U) X$ O. n        进一步,再看看GPIO结构原理图,它支持4种GPIO输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种GPIO输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。因此才能通过多种输入输出模式组合来实现更复杂的其他外设功能。
" x/ T$ ~' R! {, L! A
. C5 I0 L9 Z, a! d
ad01c8e1a5f443f897e519e3299fd597.png
' Z$ b) K, M7 `6 }$ P. k# g7 Q' k2 e' R( V$ N& u2 X4 \
         在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输入模式以及其他参数设置。
; ]0 M6 }+ L! s4 g. i) s; W, A& s: S" ]
cc3f4397f52e4e3191f4f3611e0c0b07.png
5 ~2 M2 A3 n# a$ v- b8 E+ U) {' g% a
  Z) @' U: x1 C) q1 G0 E
         同样地,在cubeMX中在GPIO配置界面中,可以配置GPIO引脚的GPIO输出模式以及其他参数设置。
4 u3 ?6 B/ k) U2 X) I
% h. f( H8 n4 g/ N
e9a0da7fcdbc4c0dbea4ecc489aaeeff.png
* |' c% s) K& _9 ^" B4 ]: b5 I5 o/ [5 V+ b1 E
        另外各种基于GPIO组合实现的外设,也可在GPIO栏的各个外设页面下,单独设置各个引脚的GPIO输入或输出模式。# g9 ^0 d. M5 A, c# Z& m# n! n  _, z

- d% S5 S/ e9 L# x5 J
40f1f5a7010642cdb1fa273713535630.png
+ T4 Q2 I5 c) G8 O) Q. C) K
8 s0 o9 q% Z* w. n, [% R
二、GPIO的HLA源码分析. a6 [: l) o) r9 G' ]$ ]% E
        2.1 HLA库GPIO初始化
9 b; S6 s- B( C& ?. z) g& r" L
        通过cubeMX生成输出源码,如果配置GPIO引脚功能,则cubeMX生成代码时,设置了为每个外设生成独立.h/.c文件时,会在Core源码目录下的Inc及Src目录,分别生成gpio.h和gpio.c驱动文件,否则将会GPOI相关输出函数放置main.h和main.c中。' N3 D- G% j( w- e" M

# C. @6 a6 F9 P) Q! H: T$ _        在gpio.c文件中,主要定义了MX_GPIO_Init函数,该主要做三件事情,一是启动各个GPIO分组寄存器的时钟,二是对于输出GPIO引脚实现初始值写入,三是将在cubeMX上配置引脚参数写入到参数缓存区域,并依据缓存参数,调用HLA库的HAL_GPIO_Init来实现真正的初始化设定。如下面代码所示。7 q% f0 y4 L+ t" k0 x9 L7 q
3 p  n+ g  `2 @/ T" c
  1. //main.h! ]) n0 l, A' e8 S% F1 U
  2. /* Private defines -----------------------------------------------------------*/# A' }* |) g: B3 r3 p8 x4 z0 {
  3. #define LED1_Pin GPIO_PIN_3; L$ _0 a2 c) J& l  w
  4. #define LED1_GPIO_Port GPIOE- A: T2 z( P6 p; h& j
  5. #define KEY2_Pin GPIO_PIN_10
    ' `2 i* U+ i. u6 u/ F0 b7 r& X
  6. #define KEY2_GPIO_Port GPIOE
    0 K2 V) s- a- j6 ]9 @' F
  7. #define KEY0_Pin GPIO_PIN_116 ?$ S& s/ T! c9 j: Q6 r
  8. #define KEY0_GPIO_Port GPIOE
    3 f5 U9 u- j9 M6 C' c
  9. #define KEY1_Pin GPIO_PIN_14
    & r  k2 D$ ~3 m7 }
  10. #define KEY1_GPIO_Port GPIOE
    ! [: C6 o, S/ [
  11. #define LED2_Pin GPIO_PIN_15; ^2 E$ a& P- ]4 Y
  12. #define LED2_GPIO_Port GPIOD
    3 R& e  X+ x: z& a! D, q( k
  13. #define LED0_Pin GPIO_PIN_64 T. N; c' ?6 Z# m
  14. #define LED0_GPIO_Port GPIOB
    $ Y% |; u. D1 i8 A: G
  15. /* USER CODE BEGIN Private defines */& p8 b1 f1 l) @/ M; ?
  16. //gpio.c& P/ |% I/ H( N. h% }
  17. void MX_GPIO_Init(void)% Y. Z$ S+ v) h; i0 p
  18. {
    4 _+ ?' ~" F' r% G2 _
  19. . ^% p5 _( r7 ]) _! I: {
  20.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    8 {  B" D5 Q) h2 ~, s/ D
  21. - L2 g' m$ N; k, o. T% R
  22.   /* GPIO Ports Clock Enable */
    + }0 F7 d, @' ^: c  X$ I' U, i. P
  23.   __HAL_RCC_GPIOE_CLK_ENABLE();  O# D* V, j# O/ j8 w2 H. [
  24.   __HAL_RCC_GPIOC_CLK_ENABLE();& y. W/ Q. L0 h8 X- [
  25.   __HAL_RCC_GPIOH_CLK_ENABLE();- f( t' t* ?5 M  D4 Q! @- M1 F1 r
  26.   __HAL_RCC_GPIOB_CLK_ENABLE();
    : ]0 f2 P" d4 }+ }) h
  27.   __HAL_RCC_GPIOD_CLK_ENABLE();8 `! Z5 A8 a7 r- J! |" i
  28.   __HAL_RCC_GPIOA_CLK_ENABLE();' D& g+ D) G/ F

  29. 8 }$ J- Y3 }4 d. ?! q) ~) h
  30.   /*Configure GPIO pin Output Level */) W, b4 T% P4 s! x
  31.   HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);0 j$ g3 r$ h* _( E. U& Y1 u  @0 y3 q

  32. ; E2 I, R2 W6 ]1 x% ]9 f8 @
  33.   /*Configure GPIO pin Output Level */
    0 K3 }7 p. W. j0 a
  34.   HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);6 v( c6 c* U) F: t( {: t

  35. 6 N, k2 n! p3 w1 s
  36.   /*Configure GPIO pin Output Level */
    / h" N  e. P5 z0 c5 ]
  37.   HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
    ( E( b/ i) T/ G5 d
  38. ( O# ^: r4 _( W8 F3 A! M: @9 o
  39.   /*Configure GPIO pin : PtPin */
    4 O5 ?  `% r. U" M7 Y. w) L+ J3 L
  40.   GPIO_InitStruct.Pin = LED1_Pin;
    / l# r/ Y  n2 r- f1 C0 r
  41.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    + |, V3 Z4 @: Z6 V7 |7 G, b
  42.   GPIO_InitStruct.Pull = GPIO_NOPULL;6 Q) N1 c( r9 W4 P, {: U( V- P/ T
  43.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    : a6 x9 R6 ]4 v4 a& a/ q7 D
  44.   HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);
    3 t. }9 l0 i' C* T: k

  45. & y5 P6 @% D2 r: N
  46.   /*Configure GPIO pins : PEPin PEPin PEPin */: [! G4 z; z; c4 s; N1 o4 O
  47.   GPIO_InitStruct.Pin = KEY2_Pin|KEY0_Pin|KEY1_Pin;6 z& p  J( I  C
  48.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    + k! T: `- }$ L+ B0 M
  49.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    4 y/ r& X  E; K) c3 S" e  F* R
  50.   HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    9 @: h2 o6 m! I/ f( f" C% R. T3 n

  51. ' h( x* J& h5 E4 X1 D! z
  52.   /*Configure GPIO pin : PtPin */  x4 d$ Z: ^3 J$ h
  53.   GPIO_InitStruct.Pin = LED2_Pin;
    9 P3 Y- c7 {$ d7 g) w
  54.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    " }+ s* i: R& d( P3 Q% @: E6 `
  55.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    - d! n9 A8 k' f$ G. M( b
  56.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;# i0 q' V8 @; x/ `) F) E
  57.   HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
    % `  k0 ~( p5 u8 v: x
  58. ' C- F- o  B1 u( _5 u) W
  59.   /*Configure GPIO pin : PtPin */
    5 v. Y0 U2 J3 k" B# `. ~, ^8 t
  60.   GPIO_InitStruct.Pin = LED0_Pin;
    ! H) b: R9 t, ]) M6 b* c( o
  61.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;7 Y4 w2 O# m$ b' i4 A
  62.   GPIO_InitStruct.Pull = GPIO_NOPULL;
    " g" V- `7 z: E6 t
  63.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;1 _# l/ H( G. V2 ]
  64.   HAL_GPIO_Init(LED0_GPIO_Port, &GPIO_InitStruct);- b# {! [5 y+ w+ q4 @6 ?
  65. 1 h" y$ n; O! D$ T/ R+ `
  66. }
复制代码
" b; ]  v: i+ G5 |# l1 V& d
        在stm32l4xx_hal_gpio.c源文件中定义了HAL_GPIO_Init函数,它做以下事情:1)诊断先前缓存配置参数是否合规,2)再将缓存配置参数写入到GPIO的寄存器内,完成GPIO的初始化设定(GPIO 的Mode、Pull、Analog、Alternate、Direction、EXTI等)。
: z1 D$ k7 V& T1 ?( F/ {( _/ S8 b4 v" X8 y" A
a6544e520b0d46f9b58ac56b87ac4c1a.png , x( q- V3 \& Y! Y: Y/ W" o

& q2 B0 P9 _0 c8 d7 b6 _        2.2 GPIO的开发应用接口API简述
$ }- q3 d% J" y, O7 b9 Z0 F. h        除了提供GPIO初始化API外,STM32的HLA针对GPIO还外开发这提供如下API:
2 z7 \4 ]8 g# Z+ O1 x9 d; Y- N. n# K* Y+ a! v
d2a594213a664287863277625ef6c4c9.png & P  V/ q6 P  C$ a, y9 |. D

6 r2 k( T! D0 ~         GPIO对数据的读取主要是HAL_GPIO_ReadPin函数,写入主要是HAL_GPIO_WritePin、HAL_GPIO_TogglePin函数,其参数都是GPIO_TypeDef* GPIOx和 uint16_t GPIO_Pin,前者就是前面参数的分组如GPIOA、GPIOB等,后者就是Pin0~Pin15,例如GPIO_PIN_3。
& ?8 v7 ^5 _8 v* s
6 W8 |$ p& a! ~% s6 L+ s
        关于外部中断回调函数HAL_GPIO_EXTI_Callback,该函数是弱函数
/ |- v" i2 F5 B; W/ Z& m# o5 ?; `; H
8 M8 ]0 R( k( G4 N' l8 m1 Y& p
4003e2f80e2f4b69ad20a5d7d7d78398.png
' q5 b; q' j% _% `# V3 F- E6 X: E/ q0 k
        若需要使用该函数,使其生效,首先需要在cubeMX配置界面,将GPIO引脚调整为GPIO_EXTI类型
! a6 F  o/ q* ~0 G  l, f8 ^9 ]! j
f7622ff6361c46139b2ce314069d95ce.png ; y' n  H# z5 \- H6 d  r- Z' u
8 @7 d7 i& w& B6 Q( x
        并开启该引脚的中断支持3 Z2 z. s8 t4 T+ o7 q1 B! Q

0 [/ i0 V% H; e0 W* P
c22186f18cca4e1d9d30f35b2add8333.png
/ ^4 \6 l! H  j3 _. J! Q
% K5 ]/ R' w$ R$ J- B0 u# l  m
         就可以重新实现stm32l4xx_hal_gpio.c文件中的HAL_GPIO_EXTI_Callback函数来实现GPIO外部中断回调功能,例如设置如下,则实现按键KEY0按下异常,触发回调函数HAL_GPIO_EXTI_Callback调用,从而实现LED0灯状态反转(点亮或熄灭):
7 ^( l& ^4 Z  U: i8 P1 N% u$ n
  1. /* USER CODE BEGIN 0 */
    & C; u+ e. K- o
  2. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    8 ?3 [' M) J: e
  3. {
    ( {. o5 \' E* _+ t
  4.         if(GPIO_Pin==KEY0_Pin)
    % O% q. A  D9 |5 b( T" e/ l- h) O7 d
  5.         {
    7 m6 U6 i+ z5 R9 }% D
  6.                 static uint32_t key0_count = 0;
    6 y& P: z5 x; Z7 g7 t
  7.                 printf("this is %lu count for HAL_GPIO_EXTI_Callback!\r\n",key0_count++);7 Q2 |( j! n( O5 S9 M
  8.                 Toggle_led0();//LED0等状态反转一次
      _) p) K9 T! D% b3 r( ?
  9.         }
    - a+ R% m* q0 N+ }  d, ]% w: C
  10. }! h$ @% H# M  Z
  11. /* USER CODE END 0 */
复制代码
+ B/ O* y6 D3 K8 F; ^# H; Y! ?
         同样地对于外部中断请求函数HAL_GPIO_EXTI_IRQHandler也可以类似地进行调整实现GPIO外部中断触发器调用,从而实现我们需要的业务应用。/ P/ `* b6 X* A, n; F4 n( X4 ~

. a5 j. m7 }) \5 I        GPIO的HLA库中,HAL_GPIO_LockPin函数,主要是操作lock寄存器数值的,lock寄存器会针对GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR等GPIO寄存器配置对应的状态标记,而其他寄存器操作时,会先去lock寄存器读取其使用状态来确定是否能进行相关操作,从而确保防止冲突及达成一致性。
$ Y: @$ }- `1 j2 p% W3 D————————————————# F" a8 B' v: ], s4 a
版权声明:py_free-物联智能5 A) R' u# T: m1 |) i2 [: d
如有侵权请联系删除3 _. M: f6 w- C% o
收藏 评论0 发布时间:2023-4-4 23:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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