一、GPIO

1. 基本结构

2. 位结构

输入驱动器部分

保护二极管对输入电压进行限幅。Vdd是数字电源,为3.3V,Vss是数字地。

当输入电压大于3.3V时,上方保护二极管导通,电流流入Vdd,避免过大的电流对内部电路产生影响。

同理,当输入小于-3.3V的负压时,下方二极管导通。当输入电压在0~3.3V之间时,两二极管均不导通。

上拉电阻和下拉电阻处的开关由寄存器的相应位控制,分为上拉输入模式,下拉输入模式和浮空输入模式。

浮空输入:浮空输入是输入端口未连接任何信号源时,其输入端口处于一种“悬空”状态,即没有明确的电平值。2.上拉输入:“上拉输入”是指在数字电路中,将一个输入端口连接至高电平信号(通常为Vdd)的电路拓扑。在这种情况下,当输入端口不接任何信号源时(悬空)其输入端口处于高电平状态。3.下拉输入:同理

TTL肖特基触发器:当输入波形大于上限电压时,输出高电平,即使后续波形在上限电压上下反复横跳,在上限和下限之间波动,仍输出高电平,只有当输入波形小于下限电压时,输入低电平。有效避免了信号波动造成的电平不定现象。所以经过整形后的输入波形就是一个标准的数字信号。

输出部分

输出数据寄存器不可位寻址,但可以使用位设置或位清除寄存器对其上的位进行单独操作。

如果要对输出数据寄存器某位置1,只需要在位设置寄存器对应位置1即可,写0的对应位保持不变,同理,位清除寄存器某位置1,在输出数据寄存器中的对应位清零。

开漏模式下,P-MOS恒定断开,当N-MOS闭合时,低电平驱动,当N-MOS断开,输出端口处于高阻模式。

开漏模式下,要输出高电平,N-MOS断开,pin处于高阻态,再外接一个上拉电阻,上拉电阻接Vdd为5V。GPIO输出端口被拉到5V。

关闭模式:两个mos管均断开,端口电平由外部信号控制,流向输入模块。

3. 模式总结

EXTI基

二、EXTI

1. EXTI基本结构

1.输入源:GPIO 引脚
每个 GPIO 端口(GPIOA/GPIOB/GPIOC等所有GPIO口)都有 16 个通用 IO 引脚(编号0~15),均可作为外部中断的输入信号源。
关键限制:EXTI 线 0~15(一共16条线),每条EXTIx线只能连接到一个 GPIO 端口的第x个引脚(如EXTI0只能选PA0/PB0/PC0.....中的一个,无法同时连接多个),因此需要 AFIO 模块做 “选择开关”。
2. 选择开关:AFIO(复用功能 IO)模块
全称Alternate Function I/O,核心作用是为每条 EXTI 线选择对应的 GPIO 引脚,解决多引脚共用 EXTI 线的冲突。例如:EXTI1只能选通PA1/PB1/PC1.....中的一个。

注意:必须先开启 AFIO 时钟(RCC_APB2Periph_AFIO),否则无法配置该模块。

EXTI 线号 对应功能
EXTI0~EXTI15 GPIO 引脚外部中断
PVD PVD(可编程电压检测器)中断
RTC RTC 闹钟事件中断
USB USB 唤醒事件中断
ETH 以太网唤醒事件中断(大容量型号)

2. EXTI 线号与NVIC 中断通道的对应关系

EXTI 线号 对应 NVIC 中断通道
EXTI0 EXTI0_IRQn (外部中断0的中断通道命名)
EXTI1 EXTI1_IRQn
EXTI2 EXTI2_IRQn
EXTI3 EXTI3_IRQn
EXTI4 EXTI4_IRQn
EXTI5~EXTI9 EXTI9_5_IRQn(共用同一个中断通道)
EXTI10~EXTI15 EXTI15_10_IRQn(共用)

3.示例代码

#include "stm32f10x.h"

// LED状态标志位
uint8_t led_state = 0;

/**
 * @brief  配置GPIO:PA0为按键输入,PC13为LED输出
 */
void GPIO_EXTI_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 1. 开启GPIOA和GPIOC的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
    
    // 2. 配置PA0为上拉输入(按键默认高电平,按下时拉低)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       // 上拉输入模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   // 输入模式速度可忽略,配置也无妨
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 3. 配置PC13为推挽输出(LED)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    // 推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   // 输出速度50MHz
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    // 初始化LED为熄灭状态(PC13输出高电平)
    GPIO_SetBits(GPIOC, GPIO_Pin_13);
    led_state = 0;
}

/**
 * @brief  配置AFIO和EXTI:PA0映射到EXTI0,下降沿触发
 */
void EXTI_Config(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    
    // 1. 开启AFIO时钟(EXTI配置必须开启!否则无法映射引脚)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    // 2. 将PA0映射到EXTI0线(AFIO配置)
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    
    // 3. 配置EXTI0线参数
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;                 // 选择EXTI0线
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;        // 模式:中断(不是事件)
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;   // 触发方式:下降沿(按键按下时)
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                  // 使能该EXTI线
    EXTI_Init(&EXTI_InitStructure);
}

/**
 * @brief  配置NVIC:设置EXTI0中断优先级并使能
 */
void NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    // 配置中断优先级分组:2位抢占优先级,2位响应优先级
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    // 配置EXTI0中断通道
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;                 // 选择EXTI0对应的中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;    // 抢占优先级:1(0为最高)
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;             // 响应优先级:1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                  // 使能该中断通道
    NVIC_Init(&NVIC_InitStructure);
}

/**
 * @brief  EXTI0中断服务函数:中断触发时自动调用
 * @note   函数名必须与启动文件中定义的一致,不能写错!
 */
void EXTI0_IRQHandler(void)
{
    // 确认是EXTI0触发的中断(防止其他中断误触发)
    if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    {
        // 翻转LED状态
        led_state = !led_state;
        if(led_state == 0)
        {
            GPIO_SetBits(GPIOC, GPIO_Pin_13);   // 熄灭LED(PC13高电平)
        }
        else
        {
            GPIO_ResetBits(GPIOC, GPIO_Pin_13); // 点亮LED(PC13低电平)
        }
        
        // 关键:清除EXTI0的中断挂起位,否则会一直触发中断!
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

/**
 * @brief  主函数:初始化模块,循环等待中断
 */
int main(void)
{
    // 初始化GPIO、EXTI、NVIC
    GPIO_EXTI_Config();
    EXTI_Config();
    NVIC_Config();
    
    // 主循环:空转,所有操作在中断服务函数中完成
    while(1)
    {
        // 可在此添加其他任务,不影响中断响应
    }
}

注:EXTI 线共用问题EXTI5~EXTI9共用EXTI9_5_IRQn中断通道,EXTI10~EXTI15共用EXTI15_10_IRQn通道,如果使用这几个外部中断线,需在中断服务函数中用EXTI_GetITStatus()轮询判断具体触发的线。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐