STM32中的GPIO框图解析与软件配置

本文最后更新于:几秒前

1 【学习笔记】STM32中的GPIO框图解析与软件配置

1.1 GPIO简介

GPIO全称为General-purpose I/O ports,一般译为“通用输入输出端口”,是STM32单片机中最基础的外设之一。

STM32芯片架构简图 参考<STM32库开发实战指南——基于野火MINI开发板>

GPIO有输出输入两种功能,可以实现与外部通讯、控制外部设备以及数据采集等功能。GPIO分为多组port,每一组port下一般有16个pin。

GPIOA12,为A组第12号引脚。(关于port和pin的叫法属于个人习惯)

输出功能可以实现控制引脚输出高低电平,实现开关控制,也可以接入继电器# 【学习笔记】STM32中的GPIO框图解析与软件配置

1.2 GPIO简介

GPIO全称为General-purpose I/O ports,一般译为“通用输入输出端口”,是STM32单片机中最基础的外设之一。

STM32芯片架构简图 参考<STM32库开发实战指南——基于野火MINI开发板>

GPIO有输出输入两种功能,可以实现与外部通讯、控制外部设备以及数据采集等功能。GPIO分为多组port,每一组port下一般有16个pin。

GPIOA12,为A组第12号引脚。(关于port和pin的叫法属于个人习惯)

输出功能可以实现控制引脚输出高低电平,实现开关控制,也可以接入继电器与三极管,实现控制大功率电路通断。

输入功能可以实现检测外部电平、读取引脚状态、采集模拟信号等功能。

下面对GPIO基本框图进行分析,了解GPIO主要的工作原理。

过一遍理解就可,有个印象

1.3 GPIO基本框图

GPIO基本框图
虽然标注的有点花花绿绿()但是大致上可以分为三个部分:

  • 紫色为引脚与外部设备连接的端口。
  • 以蓝色箭头为主线的一串冷色相关的,为输入模式相关的电路。
  • 以红色箭头为主线的一串暖色相关的,为输出模式相关的电路。

首先是紫色的保护二极管与上下拉电阻

引脚电压高于 VDDV_{DD} ,上方二极管导通。
引脚电压低于 VSSV_{SS} ,下方二极管导通。

这样就可以防止不正常的电压引入芯片导致芯片烧毁。但要注意,纵使有这样的保护也不能直接外接大功率驱动器件。


其次是红色的输出模式这一条线,从左往右看。

输出数据寄存器GPIOx_ODR开始,单片机可以对该寄存器修改值,从而给输出控制一个信号。
除此之外对置位/复位寄存器 GPIOx_BSRR的值进行修改也可以影响”输出数据寄存器“的值。

由这两个寄存器给出信号之后,通过一个开关接入输出控制。该开关可以控制是由”输出数据寄存器“还是由其他片上外设作为”输出源“。

例如要使用串口的时候,需要一个通讯发送引脚的时候,就可以将某个GPIO引脚配置为串口复用功能。

最关键的是由P-MOS与N-MOS两个管子组成的单元电路。这个单元电路使得GPIO的输出模式有两个模式,分别是推挽输出开漏输出

推挽输出
输出源给高电平,经过反向,上方的P-MOS导通,下方的N-MOS关闭,对外输出高电平;
输出源给低电平,经过反向,上方N-MOS管关闭,上方P-MOS导通,对外输出低电平;

开漏输出中,上方的P_MOS不工作
当N-MOS导通的时候对外输出为低电平(接地);
当N-MOS关闭的时候对外为高阻态,正常使用的时候需要接上拉电阻;此时等效于开漏电路,具有“线与”特性,一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中,或者需要输出电平不匹配的时候。

比如需要输出 5 伏的高电平,就可以在外部接一个上拉电阻,上拉电源为 5 伏, 并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出 5 伏的电平。


最后是蓝色的输入模式这一条线,从右往左看。

通过引脚采集电压之后,首先通过上/下拉电阻,配置成上/下拉输入,随后接一个TTL肖特基触发器,进行模数转换。

最后将触发器给出的数字信号存储在“输入数据寄存器GPIOx_IDR”中,通过读取该寄存器就可以了解GPIO引脚的电平状态。

输入模式中的复用功能输入与复用功能输出类似,也只是不经过“输入数据寄存器”,直接连接其他的片上外设,让别的外设读取引脚状态。

例如使用串口通讯,需要一个通讯接收引脚的时候,就可以将某个GPIO引脚配置为串口复用功能。此处与输出模式的复用功能输入所举的例子对应。

模拟输入与输出的通道是当引脚需要做ADC/DAC的时候,需要用原始信号时所提供的通道。
ADC时需要采集原始的模拟信号,因此不经过触发器。
DAC时需要输出原始的模拟信号,因此不经过双MOS管的结构。

A for analog, D for digital. ADC-模数转换,DAC数模转换。


至此基本将GPIO的原理框图进行了一遍梳理,下面为在HAL库中如何配置GPIO的一些记录。

1.4 HAL库中GPIO的配置

本节例程参考野火的<STM32 HAL库开发实战指南——F103系列>使用固件库点亮LED一章

首先明确一下软件上的层级关系:

LED灯的控制相关的代码不属于STM32HAL库的内容,一般将这样的控制代码封装在另外的文件中。本次例程中将文件名命名为bsp_led.cbsp_led.h,这里的bsp是Board Support Packet的简写,即板级支持包。

对bsp的个人理解:不同外设的控制代码。

本次使用的开发板是野火的F103-MINI 开发板,下面是本次例程所涉及的硬件原理图:

如图所示容易看出,若将这两个GPIO引脚设置为低电平即可点亮LED。

本次例程中关于引脚定义的宏:

bsp_led.h

1
2
3
4
5
6
7
8
9
10
11
12
13
//引脚定义
/*******************************************************/

#define LED1_PIN GPIO_PIN_2
#define LED1_GPIO_PORT GPIOC
#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()


#define LED2_PIN GPIO_PIN_3
#define LED2_GPIO_PORT GPIOC
#define LED2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()

/************************************************************/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/** 控制LED灯亮灭的宏,
* LED低电平亮,设置ON=0,OFF=1
* 若LED高电平亮,把宏设置成ON=1 ,OFF=0 即可
*/
#define ON GPIO_PIN_RESET
#define OFF GPIO_PIN_SET

/* 带参宏,可以像内联函数一样使用 */
#define LED1(a) HAL_GPIO_WritePin(LED1_GPIO_PORT,LED1_PIN,a)


#define LED2(a) HAL_GPIO_WritePin(LED2_GPIO_PORT,LED2_PIN,a)


/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i) {p->BSRR=i;} //设置为高电平
#define digitalLo(p,i) {p->BSRR=(uint32_t)i << 16;} //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态


/* 定义控制IO的宏 */
#define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_PIN)
#define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_PIN)
#define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_PIN)

#define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_PIN)
#define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_PIN)
#define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_PIN)



//黑(全部关闭)
#define LED_RGBOFF \
LED1_OFF;\
LED2_OFF

此处控制LED亮灭的操作是直接向BSRR写入控制指令来实现的,对BSRR低 16 位 写 1 输出高电平,对BSRR高 16 位写 1 输出低电平。同时,对ODR某位进行异或操作可反转位的状态。

BSRRODR在前文详解GPIO框图的输出模式时候提到过
BSRR:置位/复位寄存器 GPIOx_BSRR,Bit Set/Reset Register
ODR:输出数据寄存器GPIOx_ODR,Output Data Register

输出数据寄存器GPIOx_ODR开始,单片机可以对该寄存器修改值,从而给输出控制一个信号。
除此之外对置位/复位寄存器 GPIOx_BSRR的值进行修改也可以影响”输出数据寄存器“的值。


下面是本次例程的配置GPIO编程要点:

  • 使能GPIO端口时钟

    要使用这个外设,首先得使能时钟,没什么说的。


    bsp_led.c

    1
    2
    3
    /*开启LED相关的GPIO外设时钟*/
    LED1_GPIO_CLK_ENABLE();
    LED2_GPIO_CLK_ENABLE();

    这里使能时钟用的函数是宏定义的名字,实际是用__HAL_RCC_GPIOx_CLK_ENABLE()这个函数。

    注意GPIOx改成实际的port口。
    这里的GPIO时钟宏__HAL_RCC_GPIOx_CLK_ENABLE()是 STM32HAL库定义的GPIO端口时钟相关的宏,它的作用与GPIO_PIN_x这类宏类似,是用于指示寄存器位的,方便库函数使用。

  • 初始化GPIO目标引脚为推挽输出模式,配置GPIO初始化结构体

    没有什么特殊需求,所以输出模式直接使用推挽输出模式


    bsp_led.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.Pin = LED1_PIN;

    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    /*设置引脚为上拉模式*/
    GPIO_InitStruct.Pull = GPIO_PULLUP;

    /*设置引脚速率为高速 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    这里配置了四个东西,分别是:
    GPIO_InitStruct.Pin:pin号
    GPIO_InitStruct.Mode:输出模式
    GPIO_InitStruct.Pull:上下拉模式
    GPIO_InitStruct.Speed:引脚速率

    其中HAL库中配置输出模式:
    推挽输出GPIO_MODE_OUTPUT_PP
    开漏输出GPIO_MODE_OUTPUT_OD
    复用推挽输出GPIO_MODE_AF_PP
    复用开漏输出GPIO_MODE_AF_OD
    ……等等

    其中的简写全称记录如下:
    PP for push-pull,推挽
    OD for open-drain,开漏
    AF for alternate function,复用功能

    关于HAL库中GPIO初始化结构体成员变量的配置,考虑到本次例程的篇幅,现简单记录如上,后面有时间做一个总结。

    下面是整个初始化函数的程序:

    bsp_led.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    void LED_GPIO_Config(void)
    {
    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStruct;

    /*开启LED相关的GPIO外设时钟*/
    LED1_GPIO_CLK_ENABLE();
    LED2_GPIO_CLK_ENABLE();

    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    /*设置引脚为上拉模式*/
    GPIO_InitStruct.Pull = GPIO_PULLUP;

    /*设置引脚速率为高速 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
    /*选择要控制的GPIO引脚*/
    GPIO_InitStruct.Pin = LED1_PIN;
    HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);

    /*选择要控制的GPIO引脚*/
    GPIO_InitStruct.Pin = LED2_PIN;
    HAL_GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStruct);

    /*关闭RGB灯*/
    LED_RGBOFF;
    }
  • 编写简单测试程序,控制GPIO引脚输出高低电平

    main函数


    main.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    int main(void)
    {
    /* 系统时钟初始化成72 MHz */
    SystemClock_Config();

    /* LED 端口初始化 */
    LED_GPIO_Config();

    /* 控制LED灯 */
    while (1)
    {
    LED1( ON ); // 亮
    HAL_Delay(1000);
    LED1( OFF ); // 灭

    LED2( ON ); // 亮
    HAL_Delay(1000);
    LED2( OFF ); // 灭
    }
    }

    控制LED使用的宏定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /* 直接操作寄存器的方法控制IO */
    #define digitalHi(p,i) {p->BSRR=i;} //设置为高电平
    #define digitalLo(p,i) {p->BSRR=(uint32_t)i << 16;} //输出低电平
    #define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态


    /* 定义控制IO的宏 */
    #define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_PIN)
    #define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_PIN)
    #define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_PIN)

    #define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_PIN)
    #define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_PIN)
    #define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_PIN)

    //黑(全部关闭)
    #define LED_RGBOFF \
    LED1_OFF;\
    LED2_OFF

    大概就是这样。

1.5 总结

关于GPIO的分析和HAL库的配置大概就是这样。与三极管,实现控制大功率电路通断。

输入功能可以实现检测外部电平、读取引脚状态、采集模拟信号等功能。

下面对GPIO基本框图进行分析,了解GPIO主要的工作原理。

过一遍理解就可,有个印象

1.6 GPIO基本框图

GPIO基本框图
虽然标注的有点花花绿绿()但是大致上可以分为三个部分:

  • 紫色为引脚与外部设备连接的端口。
  • 以蓝色箭头为主线的一串冷色相关的,为输入模式相关的电路。
  • 以红色箭头为主线的一串暖色相关的,为输出模式相关的电路。

首先是紫色的保护二极管与上下拉电阻

引脚电压高于 VDDV_{DD} ,上方二极管导通。
引脚电压低于 VSSV_{SS} ,下方二极管导通。

这样就可以防止不正常的电压引入芯片导致芯片烧毁。但要注意,纵使有这样的保护也不能直接外接大功率驱动器件。


其次是红色的输出模式这一条线,从左往右看。

输出数据寄存器GPIOx_ODR开始,单片机可以对该寄存器修改值,从而给输出控制一个信号。
除此之外对置位/复位寄存器 GPIOx_BSRR的值进行修改也可以影响”输出数据寄存器“的值。

由这两个寄存器给出信号之后,通过一个开关接入输出控制。该开关可以控制是由”输出数据寄存器“还是由其他片上外设作为”输出源“。

例如要使用串口的时候,需要一个通讯发送引脚的时候,就可以将某个GPIO引脚配置为串口复用功能。

最关键的是由P-MOS与N-MOS两个管子组成的单元电路。这个单元电路使得GPIO的输出模式有两个模式,分别是推挽输出开漏输出

推挽输出
输出源给高电平,经过反向,上方的P-MOS导通,下方的N-MOS关闭,对外输出高电平;
输出源给低电平,经过反向,上方N-MOS管关闭,上方P-MOS导通,对外输出低电平;

开漏输出中,上方的P_MOS不工作
当N-MOS导通的时候对外输出为低电平(接地);
当N-MOS关闭的时候对外为高阻态,正常使用的时候需要接上拉电阻;此时等效于开漏电路,具有“线与”特性,一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中,或者需要输出电平不匹配的时候。

比如需要输出 5 伏的高电平,就可以在外部接一个上拉电阻,上拉电源为 5 伏, 并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出 5 伏的电平。


最后是蓝色的输入模式这一条线,从右往左看。

通过引脚采集电压之后,首先通过上/下拉电阻,配置成上/下拉输入,随后接一个TTL肖特基触发器,进行模数转换。

最后将触发器给出的数字信号存储在“输入数据寄存器GPIOx_IDR”中,通过读取该寄存器就可以了解GPIO引脚的电平状态。

输入模式中的复用功能输入与复用功能输出类似,也只是不经过“输入数据寄存器”,直接连接其他的片上外设,让别的外设读取引脚状态。

例如使用串口通讯,需要一个通讯接收引脚的时候,就可以将某个GPIO引脚配置为串口复用功能。此处与输出模式的复用功能输入所举的例子对应。

模拟输入与输出的通道是当引脚需要做ADC/DAC的时候,需要用原始信号时所提供的通道。
ADC时需要采集原始的模拟信号,因此不经过触发器。
DAC时需要输出原始的模拟信号,因此不经过双MOS管的结构。

A for analog, D for digital. ADC-模数转换,DAC数模转换。


至此基本将GPIO的原理框图进行了一遍梳理,下面为在HAL库中如何配置GPIO的一些记录。

1.7 HAL库中GPIO的配置

本节例程参考野火的<STM32 HAL库开发实战指南——F103系列>使用固件库点亮LED一章

首先明确一下软件上的层级关系:

LED灯的控制相关的代码不属于STM32HAL库的内容,一般将这样的控制代码封装在另外的文件中。本次例程中将文件名命名为bsp_led.cbsp_led.h,这里的bsp是Board Support Packet的简写,即板级支持包。

对bsp的个人理解:不同外设的控制代码。

本次使用的开发板是野火的F103-MINI 开发板,下面是本次例程所涉及的硬件原理图:

如图所示容易看出,若将这两个GPIO引脚设置为低电平即可点亮LED。

本次例程中关于引脚定义的宏:

bsp_led.h

1
2
3
4
5
6
7
8
9
10
11
12
13
//引脚定义
/*******************************************************/

#define LED1_PIN GPIO_PIN_2
#define LED1_GPIO_PORT GPIOC
#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()


#define LED2_PIN GPIO_PIN_3
#define LED2_GPIO_PORT GPIOC
#define LED2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()

/************************************************************/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/** 控制LED灯亮灭的宏,
* LED低电平亮,设置ON=0,OFF=1
* 若LED高电平亮,把宏设置成ON=1 ,OFF=0 即可
*/
#define ON GPIO_PIN_RESET
#define OFF GPIO_PIN_SET

/* 带参宏,可以像内联函数一样使用 */
#define LED1(a) HAL_GPIO_WritePin(LED1_GPIO_PORT,LED1_PIN,a)


#define LED2(a) HAL_GPIO_WritePin(LED2_GPIO_PORT,LED2_PIN,a)


/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i) {p->BSRR=i;} //设置为高电平
#define digitalLo(p,i) {p->BSRR=(uint32_t)i << 16;} //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态


/* 定义控制IO的宏 */
#define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_PIN)
#define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_PIN)
#define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_PIN)

#define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_PIN)
#define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_PIN)
#define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_PIN)



//黑(全部关闭)
#define LED_RGBOFF \
LED1_OFF;\
LED2_OFF

此处控制LED亮灭的操作是直接向BSRR写入控制指令来实现的,对BSRR低 16 位 写 1 输出高电平,对BSRR高 16 位写 1 输出低电平。同时,对ODR某位进行异或操作可反转位的状态。

BSRRODR在前文详解GPIO框图的输出模式时候提到过
BSRR:置位/复位寄存器 GPIOx_BSRR,Bit Set/Reset Register
ODR:输出数据寄存器GPIOx_ODR,Output Data Register

输出数据寄存器GPIOx_ODR开始,单片机可以对该寄存器修改值,从而给输出控制一个信号。
除此之外对置位/复位寄存器 GPIOx_BSRR的值进行修改也可以影响”输出数据寄存器“的值。


下面是本次例程的配置GPIO编程要点:

  • 使能GPIO端口时钟

    要使用这个外设,首先得使能时钟,没什么说的。


    bsp_led.c

    1
    2
    3
    /*开启LED相关的GPIO外设时钟*/
    LED1_GPIO_CLK_ENABLE();
    LED2_GPIO_CLK_ENABLE();

    这里使能时钟用的函数是宏定义的名字,实际是用__HAL_RCC_GPIOx_CLK_ENABLE()这个函数。

    注意GPIOx改成实际的port口。
    这里的GPIO时钟宏__HAL_RCC_GPIOx_CLK_ENABLE()是 STM32HAL库定义的GPIO端口时钟相关的宏,它的作用与GPIO_PIN_x这类宏类似,是用于指示寄存器位的,方便库函数使用。

  • 初始化GPIO目标引脚为推挽输出模式,配置GPIO初始化结构体

    没有什么特殊需求,所以输出模式直接使用推挽输出模式


    bsp_led.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.Pin = LED1_PIN;

    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    /*设置引脚为上拉模式*/
    GPIO_InitStruct.Pull = GPIO_PULLUP;

    /*设置引脚速率为高速 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    这里配置了四个东西,分别是:
    GPIO_InitStruct.Pin:pin号
    GPIO_InitStruct.Mode:输出模式
    GPIO_InitStruct.Pull:上下拉模式
    GPIO_InitStruct.Speed:引脚速率

    其中HAL库中配置输出模式:
    推挽输出GPIO_MODE_OUTPUT_PP
    开漏输出GPIO_MODE_OUTPUT_OD
    复用推挽输出GPIO_MODE_AF_PP
    复用开漏输出GPIO_MODE_AF_OD
    ……等等

    其中的简写全称记录如下:
    PP for push-pull,推挽
    OD for open-drain,开漏
    AF for alternate function,复用功能

    关于HAL库中GPIO初始化结构体成员变量的配置,考虑到本次例程的篇幅,现简单记录如上,后面有时间做一个总结。

    下面是整个初始化函数的程序:

    bsp_led.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    void LED_GPIO_Config(void)
    {
    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStruct;

    /*开启LED相关的GPIO外设时钟*/
    LED1_GPIO_CLK_ENABLE();
    LED2_GPIO_CLK_ENABLE();

    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

    /*设置引脚为上拉模式*/
    GPIO_InitStruct.Pull = GPIO_PULLUP;

    /*设置引脚速率为高速 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
    /*选择要控制的GPIO引脚*/
    GPIO_InitStruct.Pin = LED1_PIN;
    HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);

    /*选择要控制的GPIO引脚*/
    GPIO_InitStruct.Pin = LED2_PIN;
    HAL_GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStruct);

    /*关闭RGB灯*/
    LED_RGBOFF;
    }
  • 编写简单测试程序,控制GPIO引脚输出高低电平

    main函数


    main.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    int main(void)
    {
    /* 系统时钟初始化成72 MHz */
    SystemClock_Config();

    /* LED 端口初始化 */
    LED_GPIO_Config();

    /* 控制LED灯 */
    while (1)
    {
    LED1( ON ); // 亮
    HAL_Delay(1000);
    LED1( OFF ); // 灭

    LED2( ON ); // 亮
    HAL_Delay(1000);
    LED2( OFF ); // 灭
    }
    }

    控制LED使用的宏定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /* 直接操作寄存器的方法控制IO */
    #define digitalHi(p,i) {p->BSRR=i;} //设置为高电平
    #define digitalLo(p,i) {p->BSRR=(uint32_t)i << 16;} //输出低电平
    #define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态


    /* 定义控制IO的宏 */
    #define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_PIN)
    #define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_PIN)
    #define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_PIN)

    #define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_PIN)
    #define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_PIN)
    #define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_PIN)

    //黑(全部关闭)
    #define LED_RGBOFF \
    LED1_OFF;\
    LED2_OFF

    大概就是这样。

1.8 总结

关于GPIO的分析和HAL库的配置大概就是这样。


STM32中的GPIO框图解析与软件配置
https://sagi-rastar.github.io/2023/11/07/STM32中的GPIO框图解析与软件配置/
作者
SagiRastar
发布于
2023年11月7日
许可协议