stm32_GPIO

GPIO


1. 概念与基本原理

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

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

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

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


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

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

       外部引脚
          |
          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的工作模式主要包括以下几个方面:

+-------------------------------------------------------+
|                       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的操作通常遵循以下流程:

+-------------------+
|     开始          |
+-------------------+
        |
        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 文件。

/* 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持续闪烁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值