stm32_GPIO

GPIO


1. 概念与基本原理

GPIO,全称General Purpose Input/Output,即通用输入/输出端口。它是微控制器(MCU)、单片机、树莓派、ESP32等嵌入式系统中非常基础且重要的功能模块。

基本原理: GPIO引脚可以被软件配置为输入或输出。

  • 输入模式 (Input Mode): 当配置为输入时,GPIO引脚可以读取外部设备的电平状态(高电平或低电平),从而感知外部信号或传感器数据。
  • 输出模式 (Output Mode): 当配置为输出时,GPIO引脚可以输出高电平或低电平,从而控制外部设备,如点亮LED、驱动继电器、控制电机等。

核心思想: 通过软件对硬件引脚进行直接操作,实现微控制器与外部世界的交互。


2. GPIO引脚结构(可图示)

想象一个GPIO引脚的内部结构,它通常包含以下几个关键部分:

c 复制代码
       外部引脚
          |
          V
+---------------------+
|                     |
|  保护二极管(ESD保护)|
|                     |
+---------------------+
          |
          V
+---------------------+
|                     |
|   输入缓冲器/施密特触发器  |  <-- 确保输入信号的稳定性
|                     |
+---------------------+
          |
          V
+---------------------+
|                     |
|      输入数据寄存器     |  <-- 存储当前引脚的电平状态
|                     |
+---------------------+
          |
          V
+---------------------+
|                     |
|      输出数据寄存器     |  <-- 存储要输出的电平状态
|                     |
+---------------------+
          |
          V
+---------------------+
|                     |
|    输出驱动器(推挽/开漏)|  <-- 提供电流驱动外部设备
|                     |
+---------------------+
          |
          V
+---------------------+
|                     |
|   方向控制寄存器(输入/输出)|  <-- 配置引脚是输入还是输出
|                     |
+---------------------+
          |
          V
+---------------------+
|                     |
|   上拉/下拉电阻配置   |  <-- 控制引脚默认电平(防止浮空)
|                     |
+---------------------+

关键部件解释:

  • 保护二极管(ESD保护): 防止静电放电(ESD)损坏芯片。

  • 输入缓冲器/施密特触发器: 提高输入信号的抗噪声能力,确保输入信号的可靠性。

  • 输入数据寄存器: 存储当前引脚的逻辑电平(0或1)。

  • 输出数据寄存器: 存储要输出到引脚的逻辑电平。

  • 输出驱动器:

    根据输出数据寄存器的值驱动引脚电平。常见的驱动类型有:

    • 推挽输出 (Push-Pull): 可以输出高电平(连接到VCC)或低电平(连接到GND),驱动能力强,常用于驱动LED、电机等。
    • 开漏输出 (Open-Drain/Open-Collector): 只能输出低电平(连接到GND)或高阻态(浮空)。通常需要外接一个上拉电阻才能输出高电平。常用于I2C总线、电平转换等。
  • 方向控制寄存器: 配置GPIO引脚是作为输入还是输出。

  • 上拉/下拉电阻配置:

    • 上拉电阻 (Pull-up): 将引脚默认拉高到高电平。常用于按键输入,当按键按下时,引脚被拉低。
    • 下拉电阻 (Pull-down): 将引脚默认拉低到低电平。当按键按下时,引脚被拉高。
    • 无(浮空): 不使用内部上拉或下拉电阻。此时引脚电平容易受外部干扰影响,通常需要外部上拉/下拉电阻。

3. GPIO工作模式(可图示)

GPIO的工作模式主要包括以下几个方面:

c 复制代码
+-------------------------------------------------------+
|                       GPIO工作模式                     |
+-------------------------------------------------------+
|                                                       |
|  1. 方向配置 (Direction Configuration)                |
|     +-----------------------------------------+       |
|     |                                         |       |
|     |  输入模式 (Input Mode)                  |       |
|     |    - 读取外部电平状态                   |       |
|     |    - 配合上拉/下拉电阻使用              |       |
|     |                                         |       |
|     |  输出模式 (Output Mode)                 |       |
|     |    - 输出高/低电平                     |       |
|     |    - 控制外部设备                      |       |
|     +-----------------------------------------+       |
|                                                       |
|  2. 输出类型配置 (Output Type Configuration)          |
|     +-----------------------------------------+       |
|     |                                         |       |
|     |  推挽输出 (Push-Pull)                   |       |
|     |    - 可以输出高/低电平                  |       |
|     |    - 驱动能力强                         |       |
|     |                                         |       |
|     |  开漏输出 (Open-Drain)                  |       |
|     |    - 只能输出低电平或高阻态             |       |
|     |    - 需要外部上拉电阻                  |       |
|     +-----------------------------------------+       |
|                                                       |
|  3. 上拉/下拉电阻配置 (Pull-up/Pull-down Configuration)|
|     +-----------------------------------------+       |
|     |                                         |       |
|     |  内部上拉 (Internal Pull-up)            |       |
|     |  内部下拉 (Internal Pull-down)          |       |
|     |  无上拉/下拉 (No Pull-up/Pull-down)     |       |
|     +-----------------------------------------+       |
|                                                       |
|  4. 中断配置 (Interrupt Configuration)                |
|     +-----------------------------------------+       |
|     |                                         |       |
|     |  边沿触发 (Edge Triggered)              |       |
|     |    - 上升沿触发                        |       |
|     |    - 下降沿触发                        |       |
|     |    - 双边沿触发                        |       |
|     |                                         |       |
|     |  电平触发 (Level Triggered)             |       |
|     |    - 高电平触发                        |       |
|     |    - 低电平触发                        |       |
|     +-----------------------------------------+       |
+-------------------------------------------------------+

详细说明:

  1. 方向配置: 这是最基本的配置,决定了引脚是输入还是输出。
  2. 输出类型配置: 仅当引脚配置为输出时才需要考虑。
  3. 上拉/下拉电阻配置: 无论输入还是输出模式,都可以配置,但主要对输入模式有意义,用于确定引脚在未被外部驱动时的默认电平。
  4. 中断配置 (Interrupt): 允许GPIO引脚在电平变化(上升沿、下降沿、高电平、低电平)时触发微控制器中断,从而无需持续轮询引脚状态,提高系统效率和响应速度。

4. GPIO操作流程(可图示)

GPIO的操作通常遵循以下流程:

c 复制代码
+-------------------+
|     开始          |
+-------------------+
        |
        V
+-------------------+
|  1. 初始化GPIO外设 |
|    - 使能GPIO时钟  |
+-------------------+
        |
        V
+-------------------+
|  2. 配置GPIO引脚   |
|    - 选择引脚号    |
|    - 配置方向(输入/输出)|
|    - 配置输出类型(推挽/开漏)|
|    - 配置上拉/下拉电阻 |
|    - (可选)配置复用功能 |
+-------------------+
        |
        V
+-------------------+
|  3. 进行GPIO操作   |
|    - 如果是输出:   |
|      - 设置高/低电平 |
|    - 如果是输入:   |
|      - 读取引脚电平  |
+-------------------+
        |
        V
+-------------------+
|   4. (可选)中断处理  |
|     - 配置中断触发条件 |
|     - 编写中断服务函数 |
+-------------------+
        |
        V
+-------------------+
|      结束         |
+-------------------+

流程详解:

  1. 初始化GPIO外设:
    • 使能GPIO时钟: 大多数微控制器为了节省功耗,外设的时钟是默认关闭的。使用GPIO前需要先使能对应GPIO端口的时钟。
  2. 配置GPIO引脚:
    • 选择引脚号: 明确要操作的GPIO引脚(例如PA0, PB5等)。
    • 配置方向: 设置为输入或输出。
    • 配置输出类型: 如果是输出,选择推挽或开漏。
    • 配置上拉/下拉电阻: 根据应用需求配置内部上拉、下拉或无。
    • (可选)配置复用功能: GPIO引脚往往不止一种功能,它们可以被复用为其他外设(如UART, SPI, I2C等)的接口。当用作GPIO时,需要确保其没有被配置为其他复用功能。
  3. 进行GPIO操作:
    • 输出: 通过写入GPIO数据寄存器来设置引脚的电平(高或低)。
    • 输入: 通过读取GPIO数据寄存器来获取引脚的当前电平。
  4. (可选)中断处理:
    • 配置中断触发条件: 设置在什么条件下触发中断(上升沿、下降沿等)。
    • 编写中断服务函数 (ISR): 当中断发生时,CPU会跳转到预先定义好的中断服务函数中执行相应的处理逻辑。

5. 完整流程代码案例 (以STM32为例)

这里以STM32微控制器为例,使用HAL库(硬件抽象层)来演示一个完整的GPIO代码案例。我们将实现一个简单的功能:控制一个LED灯亮灭,并通过一个按键控制LED的亮灭状态。

硬件连接:

  • LED: 连接到STM32F407开发板上的GPIOD的第13个引脚 (PD13)。LED的一端接PD13,另一端通过限流电阻接地。
  • 按键: 连接到STM32F407开发板上的GPIOA的第0个引脚 (PA0)。按键一端接PA0,另一端接地。PA0将配置为带内部上拉电阻的输入模式,这样按键未按下时,PA0为高电平;按键按下时,PA0为低电平。

开发环境: Keil MDK, STM32CubeMX (用于生成初始化代码)

5.1 STM32CubeMX配置步骤
  1. 新建项目并选择芯片。
  2. 配置GPIO:
    • PD13 (LED):
      • 设置为 GPIO_Output
      • 用户标签:LED_PIN
      • GPIO output level: Low (默认低电平)
      • GPIO mode: Output Push Pull
      • No pull-up and pull-down
      • Maximum output speed: Low
    • PA0 (Button):
      • 设置为 GPIO_Input
      • 用户标签:BUTTON_PIN
      • GPIO mode: Input mode
      • GPIO pull-up/pull-down: Pull-up
      • (可选:如果需要中断)选择 External Interrupt Mode with Rising/Falling Edge trigger detection,这里我们用轮询方式,所以不需要中断。
  3. 时钟配置: 保持默认即可,确保GPIO端口的时钟被使能。
  4. 生成代码。
5.2 Keil MDK代码实现

在STM32CubeMX生成的基础代码上,我们主要修改 main.c 文件。

c 复制代码
/* USER CODE BEGIN Includes */
#include "main.h" // 包含CubeMX生成的头文件
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init(); // CubeMX生成的GPIO初始化函数
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    // 读取按键状态
    // HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) 函数用于读取GPIO引脚的电平
    // 如果按键按下 (PA0被拉低),HAL_GPIO_ReadPin 返回 GPIO_PIN_RESET (低电平)
    if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
    {
      // 按键被按下
      HAL_Delay(10); // 简单的消抖延时,防止按键抖动误判
      if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
      {
        // 再次确认按键按下,执行操作
        // 翻转LED状态
        // HAL_GPIO_TogglePin(GPIOx, GPIO_Pin) 函数用于翻转GPIO引脚的电平
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

        // 等待按键释放,防止一次按键触发多次翻转
        while(HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET);
      }
    }

    // 可以添加其他任务或延时
    // HAL_Delay(100); // 如果没有按键操作,可以适当延时以降低CPU占用
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  /* ... (CubeMX生成的时钟配置代码) ... */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  * where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
5.3 代码解释
  • #include "main.h": 包含CubeMX生成的main.h,其中定义了所有GPIO引脚和端口的宏(例如 LED_GPIO_Port, LED_Pin, BUTTON_GPIO_Port, BUTTON_Pin)。

  • MX_GPIO_Init();:

    这是STM32CubeMX生成的GPIO初始化函数。它会在程序启动时,根据我们在CubeMX中的配置,自动完成:

    • 使能相应GPIO端口的时钟。
    • 配置GPIO引脚的方向(输入/输出)。
    • 配置GPIO引脚的输出类型(推挽/开漏)。
    • 配置GPIO引脚的上拉/下拉电阻。
    • 设置初始电平。
  • HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin):

    • HAL_GPIO_ReadPin 是HAL库提供的读取GPIO引脚电平的函数。
    • BUTTON_GPIO_Port (GPIOA) 是按键连接的GPIO端口。
    • BUTTON_Pin (GPIO_PIN_0) 是按键连接的GPIO引脚。
    • 当按键按下时,PA0被拉低,函数返回 GPIO_PIN_RESET (逻辑0)。
  • HAL_Delay(10);: 一个简单的软件消抖,防止按键按下时由于机械抖动产生多个高低电平跳变,导致LED多次翻转。

  • HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);:

    • HAL_GPIO_TogglePin 是HAL库提供的翻转GPIO引脚电平的函数。
    • LED_GPIO_Port (GPIOD) 是LED连接的GPIO端口。
    • LED_Pin (GPIO_PIN_13) 是LED连接的GPIO引脚。
    • 每次调用都会将LED的状态从亮变为灭,或从灭变为亮。
  • while(HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET);: 这是一个等待按键释放的循环。它确保只有当按键完全释放后,程序才会继续向下执行,从而避免在按键持续按下的情况下LED持续闪烁。

相关推荐
森焱森36 分钟前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白40 分钟前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D1 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术4 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt5 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘5 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang5 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n7 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件
Despacito0o11 小时前
ESP32-s3摄像头驱动开发实战:从零搭建实时图像显示系统
人工智能·驱动开发·嵌入式硬件·音视频·嵌入式实时数据库
门思科技11 小时前
设计可靠 LoRaWAN 设备时需要考虑的关键能力
运维·服务器·网络·嵌入式硬件·物联网