STM外设介绍1(GPIO)

1. GPIO 简介

GPIO (General Purpose Input/Output) 是嵌入式系统最常用的外设之一,用于连接和控制外部设备,如 LED、按键、传感器、继电器等。

1.1 GPIO 模式

GPIO 可配置为不同的工作模式,以满足不同的硬件需求:

模式描述
输入模式GPIO 用于接收外部信号。
- 浮空输入 (Floating Input)无内部上拉或下拉电阻,适合外部信号驱动。
- 上拉输入 (Pull-up Input)内部连接上拉电阻,输入默认为高电平。
- 下拉输入 (Pull-down Input)内部连接下拉电阻,输入默认为低电平。
- 模拟输入 (Analog Input)用于连接模拟信号(如 ADC)。
输出模式GPIO 用于输出信号。
- 推挽输出 (Push-Pull)输出高电平或低电平,适合驱动 LED、继电器等。
- 开漏输出 (Open-Drain)输出低电平或高阻状态,适合与 I²C 等总线连接。
复用功能模式GPIO 引脚复用为外设功能(如 USART、SPI、I²C 等)。
输入/输出高速模式支持快速切换(最高可达 50 MHz),适用于高速通信。

1.2 GPIO 特点

  1. 可配置方向:每个引脚可以独立配置为输入或输出。
  2. 中断功能:输入模式支持边沿触发中断(上升沿、下降沿或双边沿)。
  3. 复用功能:每个引脚可复用为多种外设功能。
  4. 端口组:STM32 GPIO 按端口分组,通常为 A、B、C 等,每组包含最多 16 个引脚(PA0-PA15、PB0-PB15)。

1.3 GPIO 控制寄存器

在 STM32F103 上,GPIO 的配置通过以下寄存器实现:

寄存器名称描述
GPIOx_CRL配置低 8 个引脚(Pin 0 - Pin 7)的模式和功能。
GPIOx_CRH配置高 8 个引脚(Pin 8 - Pin 15)的模式和功能。
GPIOx_IDR输入数据寄存器,用于读取引脚的电平状态。
GPIOx_ODR输出数据寄存器,用于控制引脚的输出电平。
GPIOx_BSRR置位/复位寄存器,用于高效地设置或清除引脚。
GPIOx_BRR清除寄存器,用于快速清除指定引脚的状态。
GPIOx_LCKR引脚锁定寄存器,用于防止误修改引脚配置。

2. GPIO 在 STM32F103 上的应用

下面是基于 STM32F103 的具体应用场景和代码示例。


2.1 GPIO 控制 LED 灯

目标:使用 GPIO 输出控制一个 LED 灯。

硬件连接
  • 将 LED 的正极连接到 PA0 引脚。
  • LED 的负极通过电阻(约 330 欧姆)连接到 GND。
代码实现

以下代码使用标准外设库 (StdPeriph Library) 进行实现。

#include "stm32f10x.h"

// 初始化 GPIO
void GPIO_Init_LED(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    // 1. 启用 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 2. 配置 PA0 为推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;            // 引脚 PA0
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    // 输出速度 50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     // 推挽输出模式
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

// 主函数
int main(void) {
    GPIO_Init_LED();

    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++); // 简单延时
    }
}

HAL库版本

#include "main.h"

// 初始化 GPIO
void GPIO_Init_LED(void) {
    // 1. 启用 GPIOA 时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 2. 配置 PA0 为推挽输出
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;               // 配置引脚为 PA0
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;     // 推挽输出模式
    GPIO_InitStruct.Pull = GPIO_NOPULL;             // 无上拉或下拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;    // 低速输出
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

int main(void) {
    // HAL 库初始化
    HAL_Init();

    // 初始化 LED GPIO
    GPIO_Init_LED();

    while (1) {
        // 点亮 LED
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
        HAL_Delay(500); // 延时 500 毫秒

        // 熄灭 LED
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
        HAL_Delay(500); // 延时 500 毫秒
    }
}

2.2 GPIO 读取按键输入

目标:读取一个外部按键的状态,按下时点亮 LED。

硬件连接
  • 按键一端连接到 PB0,另一端连接到 GND。
  • LED 的正极连接到 PA0
代码实现
#include "stm32f10x.h"

// 初始化 GPIO
void GPIO_Init_Key_LED(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    // 1. 启用 GPIO 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    // 2. 配置 PA0 为 LED 输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;            // 引脚 PA0
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    // 输出速度 50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     // 推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. 配置 PB0 为按键输入,上拉模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;            // 引脚 PB0
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;        // 上拉输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

// 主函数
int main(void) {
    GPIO_Init_Key_LED();

    while (1) {
        // 检测按键状态
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) { // 按键按下
            GPIO_SetBits(GPIOA, GPIO_Pin_0);                // 点亮 LED
        } else {
            GPIO_ResetBits(GPIOA, GPIO_Pin_0);              // 熄灭 LED
        }
    }
}

HAL库版本

#include "main.h"

// 初始化 GPIO
void GPIO_Init_Key_LED(void) {
    // 1. 启用 GPIO 时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 启用 GPIOA 时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 启用 GPIOB 时钟

    // 2. 配置 PA0 为 LED 推挽输出
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;     // 推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;             // 无上拉或下拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;    // 低速输出
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 3. 配置 PB0 为按键输入(上拉模式)
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;         // 输入模式
    GPIO_InitStruct.Pull = GPIO_PULLUP;             // 上拉输入
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

int main(void) {
    // HAL 库初始化
    HAL_Init();

    // 初始化 GPIO
    GPIO_Init_Key_LED();

    while (1) {
        // 检测按键状态
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) { // 按键按下
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);       // 点亮 LED
        } else {
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);     // 熄灭 LED
        }
    }
}

2.3 GPIO 中断:按键控制 LED

目标:通过 GPIO 中断方式,按键每按下一次,LED 状态翻转一次。

硬件连接
  • 按键连接到 PB0,另一端连接 GND。
  • LED 的正极连接到 PA0
代码实现
#include "stm32f10x.h"

// LED 状态变量
volatile uint8_t LED_State = 0;

// 初始化 GPIO 和中断
void GPIO_Init_With_EXTI(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 1. 启用 GPIO 和 AFIO 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

    // 2. 配置 PA0 为 LED 输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. 配置 PB0 为按键输入(浮空模式)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 4. 配置 EXTI 线路
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // 5. 配置 NVIC
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// 中断处理函数
void EXTI0_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        LED_State = !LED_State; // 翻转 LED 状态

        if (LED_State) {
            GPIO_SetBits(GPIOA, GPIO_Pin_0);
        } else {
            GPIO_ResetBits(GPIOA, GPIO_Pin_0);
        }

        // 清除中断标志位
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

int main(void) {
    GPIO_Init_With_EXTI();

    while (1) {
        // 主循环空闲,等待中断
    }
}

HAL库版本 

#include "main.h"

// LED 状态变量
volatile uint8_t LED_State = 0;

// 初始化 GPIO
void GPIO_Init_With_EXTI(void) {
    // 1. 启用 GPIO 和 SYSCFG 时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // 2. 配置 PA0 为 LED 输出
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;     // 推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 3. 配置 PB0 为按键输入(带外部中断)
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;    // 下降沿触发中断
    GPIO_InitStruct.Pull = GPIO_PULLUP;             // 上拉输入
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 4. 配置中断优先级并启用中断
    HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

// 外部中断处理函数
void EXTI0_IRQHandler(void) {
    // 检查是否是 EXTI_Line0 中断
    if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
        // 清除中断标志
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

        // 翻转 LED 状态
        LED_State = !LED_State;
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, LED_State ? GPIO_PIN_SET : GPIO_PIN_RESET);
    }
}

int main(void) {
    // HAL 库初始化
    HAL_Init();

    // 初始化 GPIO
    GPIO_Init_With_EXTI();

    while (1) {
        // 主循环空闲,等待中断触发
    }
}



总结

  • GPIO 是 STM32 最常用的外设之一,提供了灵活的输入、输出和中断功能。
  • 通过 STM32 的外设库或 HAL 库,可以快速实现常见的 GPIO 应用,如 LED 控制、按键检测和中断响应。
  • 在 STM32F103 上,GPIO 的设置简单高效,非常适合嵌入式开发入门者学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值