【GPIO8个函数解释】

函数解释

  1. void GPIO_DeInit(GPIO_TypeDef* GPIOx);
  • 作用:将指定GPIO端口的所有寄存器恢复为默认值。这会清除之前对该端口的所有配置,使其回到初始状态。
  • 使用方法 :传入要复位的GPIO端口指针,例如GPIOA、GPIOB等。
  1. void GPIO_AFIODeInit(void);
  • 作用:将复用功能I/O(AFIO)的寄存器恢复为默认值。复用功能I/O用于将一些外设功能映射到特定的GPIO引脚上,该函数可清除这些映射配置。
  • 使用方法:无需传入参数,直接调用即可。
  1. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
  • 作用 :根据GPIO_InitStruct结构体中的参数初始化指定的GPIO端口。该结构体包含了GPIO引脚的模式、速度等配置信息。
  • 使用方法 :传入要初始化的GPIO端口指针和一个GPIO_InitTypeDef结构体指针。
  1. void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
  • 作用 :将GPIO_InitTypeDef结构体的成员初始化为默认值。通常在使用GPIO_Init函数之前调用该函数,以确保结构体中的成员有合理的初始值。
  • 使用方法 :传入一个GPIO_InitTypeDef结构体指针。

示例代码

以下是一个简单的示例,展示了如何使用这些函数来初始化GPIO端口:

c 复制代码
#include "stm32f10x.h"

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 将GPIOA的所有寄存器恢复为默认值
    GPIO_DeInit(GPIOA);

    // 将复用功能I/O的寄存器恢复为默认值
    GPIO_AFIODeInit();

    // 将GPIO_InitStructure结构体的成员初始化为默认值
    GPIO_StructInit(&GPIO_InitStructure);

    // 配置GPIOA的引脚0为推挽输出模式,最大速度为50MHz
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    // 根据GPIO_InitStructure结构体的参数初始化GPIOA
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    while (1)
    {
        // 点亮LED
        GPIO_SetBits(GPIOA, GPIO_Pin_0);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);

        // 熄灭LED
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);
    }
}

代码解释

  1. 使能时钟 :在使用GPIO之前,需要先使能相应的时钟。这里使用RCC_APB2PeriphClockCmd函数使能GPIOA的时钟。
  2. 复位寄存器 :调用GPIO_DeInit和GPIO_AFIODeInit函数将GPIOA和复用功能I/O的寄存器恢复为默认值。
  3. 初始化结构体 :调用GPIO_StructInit函数将GPIO_InitStructure结构体的成员初始化为默认值。
  4. 配置GPIO :设置GPIO_InitStructure结构体的成员,指定要配置的引脚、模式和速度。
  5. 初始化GPIO端口 :调用GPIO_Init函数根据GPIO_InitStructure结构体的参数初始化GPIOA。
  6. 循环控制LED :在主循环中,使用GPIO_SetBits和GPIO_ResetBits函数点亮和熄灭连接到GPIOA引脚0的LED。

通过以上步骤,你可以使用这些函数来配置和控制STM32的GPIO端口。

函数名 功能 参数说明 适用场景
GPIO_SetBits 将指定GPIO端口的指定引脚置为高电平(逻辑1) - GPIOx:指定的GPIO端口,如GPIOA、GPIOB等 - GPIO_Pin:指定的引脚,如GPIO_Pin_0、GPIO_Pin_1等 仅需将引脚拉高的场景,操作简单直接
GPIO_ResetBits 将指定GPIO端口的指定引脚置为低电平(逻辑0) - GPIOx:指定的GPIO端口,如GPIOA、GPIOB等 - GPIO_Pin:指定的引脚,如GPIO_Pin_0、GPIO_Pin_1等 仅需将引脚拉低的场景,操作简单直接
GPIO_WriteBit 将指定GPIO端口的指定引脚设置为指定的电平值 - GPIOx:指定的GPIO端口,如GPIOA、GPIOB等 - GPIO_Pin:指定的引脚,如GPIO_Pin_0、GPIO_Pin_1等 - BitVal:电平值,Bit_SET表示高电平,Bit_RESET表示低电平 需要灵活设置引脚高低电平的场景
GPIO_Write 将一个16位的值写入指定的GPIO端口,一次性设置该端口所有引脚的电平状态 - GPIOx:指定的GPIO端口,如GPIOA、GPIOB等 - PortVal:一个16位的值,用于设置端口所有引脚的电平 需要对一个端口的多个引脚进行批量操作的场景

这四个函数均为STM32标准库中用于操作GPIO引脚输出电平的函数,下面为你对比分析它们的区别,并给出使用示例。

函数区别分析

1. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
  • 功能:将指定GPIO端口的指定引脚置为高电平(逻辑1)。
  • 特点:只能用于将引脚置高,操作简单直接,适用于只需要将引脚拉高的场景。
2. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
  • 功能:将指定GPIO端口的指定引脚置为低电平(逻辑0)。
  • 特点:只能用于将引脚置低,操作简单直接,适用于只需要将引脚拉低的场景。
3. void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
  • 功能 :将指定GPIO端口的指定引脚设置为指定的电平值,电平值可以是高电平(Bit_SET)或低电平(Bit_RESET)。
  • 特点 :可以灵活设置引脚的高低电平,通过传入不同的BitAction参数来控制。
4. void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
  • 功能:将一个16位的值写入指定的GPIO端口,一次性设置该端口所有引脚的电平状态。
  • 特点:可以同时控制一个端口的所有16个引脚,适用于需要对多个引脚进行批量操作的场景。

示例代码

以下是使用这四个函数的示例代码:

c 复制代码
#include "stm32f10x.h"

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 配置GPIOA的引脚0和引脚1为推挽输出模式,最大速度为50MHz
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    while (1)
    {
        // 使用GPIO_SetBits将引脚0置高
        GPIO_SetBits(GPIOA, GPIO_Pin_0);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);

        // 使用GPIO_ResetBits将引脚0置低
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);

        // 使用GPIO_WriteBit将引脚1置高
        GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);

        // 使用GPIO_WriteBit将引脚1置低
        GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);

        // 使用GPIO_Write同时设置引脚0和引脚1的电平
        // 0x03 表示二进制 0000 0000 0000 0011,即引脚0和引脚1都置高
        GPIO_Write(GPIOA, 0x03);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);

        // 使用GPIO_Write同时设置引脚0和引脚1的电平
        // 0x00 表示二进制 0000 0000 0000 0000,即引脚0和引脚1都置低
        GPIO_Write(GPIOA, 0x00);

        // 延时一段时间
        for (int i = 0; i < 1000000; i++);
    }
}

代码解释

  1. 使能时钟和配置GPIO:使能GPIOA的时钟,并将GPIOA的引脚0和引脚1配置为推挽输出模式。
  2. 使用GPIO_SetBits和GPIO_ResetBits:分别将引脚0置高和置低,实现引脚0的电平翻转。
  3. 使用GPIO_WriteBit :通过传入Bit_SET和Bit_RESET参数,将引脚1置高和置低,实现引脚1的电平翻转。
  4. 使用GPIO_Write:通过传入不同的16位值,一次性设置引脚0和引脚1的电平状态。

以下是三种GPIO控制方法的对比及效果分析:


1. 方法对比

方法1 :GPIO_SetBits 和 GPIO_ResetBits
c 复制代码
GPIO_SetBits(GPIOA, GPIO_Pin_0);   // 置高电平
GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 置低电平
  • 原理:直接操作寄存器,通过宏定义实现。
  • 特点 :
    • 代码简洁,无函数调用开销,执行效率高。
    • 专用于单一操作(置高或置低),功能明确。
方法2 :GPIO_WriteBit 配合 Bit_RESET 和 Bit_SET
c 复制代码
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // 置低电平
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);   // 置高电平
  • 原理 :通过函数调用设置电平,参数使用枚举值(BitAction)。
  • 特点 :
    • 代码直观,参数明确(Bit_SET/Bit_RESET)。
    • 灵活性高,可动态指定电平状态(如通过变量控制)。
方法3 :GPIO_WriteBit 配合强制类型转换
c 复制代码
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0); // 置低电平
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1); // 置高电平
  • 原理 :强制将整数 0 和 1 转换为 BitAction 类型。
  • 特点 :
    • 功能上等同于方法2(BitAction 内部对应 0 和 1)。
    • 缺点:代码可读性差,潜在兼容性风险(依赖枚举底层实现)。

2. 效果是否相同?

  • 功能层面 :三种方法最终均会修改GPIO输出寄存器的对应位,实现引脚电平控制,效果完全相同。
  • 性能层面 :
    • 方法1(宏操作)直接操作寄存器,无函数调用,效率最高。
    • 方法2和方法3(函数调用)有轻微函数调用开销,但实际应用中差异可忽略。

3. 代码规范建议

  1. 推荐方法2 :

    使用 Bit_SET 和 Bit_RESET,兼顾可读性、规范性和灵活性。

    c 复制代码
    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // 正确写法
  2. 避免方法3 :

    强制类型转换会降低代码可维护性,且不符合ST库的设计意图。

  3. 方法1的适用场景 :

    若需极致性能(如高频信号控制),可优先选择 GPIO_SetBits/GPIO_ResetBits。


4. 补充说明

  • 条件编译 #if 0 的作用 :
    代码中被 #if 0 包裹的部分会被编译器忽略,仅用于临时禁用代码块。
    若要启用方法1或方法2,需将对应的 #if 0 改为 #if 1。

总结

三种方法在功能上完全等效,但代码风格和可维护性差异显著。推荐优先使用方法2(Bit_SET/Bit_RESET),既能保证效率,又符合工程规范。

相关推荐
不悔哥3 天前
开源OV-Watch:怎么做一个智能手表
单片机·开源·嵌入式
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
优信电子3 天前
AIT1001 非接触式红外测温模块 STM32 驱动开发实战:从引脚到代码全解析
stm32·嵌入式·温度传感器·红外测温·非接触式测温·ait1001
深圳老胡3 天前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
wuyk5553 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
女神下凡3 天前
嵌入式设计的各种存储芯片的硬件/软件设计规范,非常全面。
arm开发·单片机·嵌入式硬件
梅梅9663 天前
一款mipi转lvds的lcd调试(LT8912B)
单片机·计算机外设·电脑·显示器·pd芯片
开发笔记-阿牛3 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
从零开始的嵌入式之旅3 天前
day47
arm开发·经验分享·笔记·嵌入式硬件
恒锐丰科技林技术员3 天前
EG1164 高压大电流升压同步整流芯片解析
经验分享·嵌入式硬件·硬件工程