当前位置: 首页 > news >正文

STM32中EXTI(外部中断)详解

前言:为什么需要EXTI?

在嵌入式系统中,我们经常需要处理来自外部的"突发情况":比如按键被按下、传感器检测到阈值、外部设备发出触发信号等。这些事件具有随机性,无法通过轮询(不断查询引脚状态)高效处理——轮询会占用大量CPU资源,且可能错过短暂的触发信号。

EXTI(External Interrupt/Event Controller,外部中断/事件控制器) 正是为解决这类问题而生。它能让CPU在外部事件发生时立即暂停当前任务,转而去处理中断服务(ISR),处理完成后再回到原任务,实现对外部事件的实时响应

本文将从EXTI的硬件结构、工作原理、配置步骤到实战案例,全面讲解STM32的EXTI外设,帮助大家彻底掌握外部中断的使用。

一、EXTI核心原理:从引脚到中断服务程序

1.1 什么是EXTI?

EXTI是STM32中专门负责处理外部中断和事件的外设,其核心功能是:

  • 监测指定引脚的电平变化(上升沿、下降沿或双边沿)
  • 当检测到有效电平变化时,触发中断(CPU响应)或事件(外设联动)
  • 支持19条中断线(EXTI0~EXTI18),可映射到不同GPIO引脚或内部外设

EXTI的优势在于实时性低CPU占用:无需持续查询引脚状态,只需在事件发生时被动响应,极大提高了系统效率。

1.2 EXTI的基本工作流程

EXTI的工作流程可概括为"检测-触发-响应"三步:

  1. 检测:EXTI控制器持续监测指定引脚的电平变化,根据配置的触发方式(上升沿/下降沿)判断是否为有效事件
  2. 触发:当检测到有效事件时,EXTI生成中断请求(送往NVIC)或事件信号(送往其他外设)
  3. 响应
    • 中断模式:CPU响应中断,执行中断服务程序(ISR)
    • 事件模式:事件信号直接触发其他外设(如DMA、TIM),无需CPU干预

1.3 中断与事件的核心区别

很多初学者会混淆"中断"和"事件",两者的本质区别在于是否需要CPU参与

  • 中断:触发后会向CPU发送中断请求,CPU暂停当前任务,转而去执行中断服务程序(需软件处理)
  • 事件:触发后生成一个硬件信号,直接用于驱动其他外设(如启动ADC转换、触发DMA传输),全程无CPU参与,效率更高

举个例子:按键按下时用中断处理(需要CPU亮灯),而传感器数据就绪时用事件触发DMA传输(无需CPU干预)。

二、EXTI硬件结构:深入理解中断控制器的组成

STM32的EXTI控制器结构清晰,主要由以下模块组成(以STM32F103为例):

2.1 中断线(EXTI0~EXTI18)

EXTI共有19条中断线,每条线对应特定的触发源:

  • **EXTI0EXTI15**:可映射到GPIO引脚(PA0PA15、PB0~PB15等)
  • EXTI16:连接到PVD(电源电压监测)
  • EXTI17:连接到RTC闹钟事件
  • EXTI18:连接到USB唤醒事件

关键特性:每条中断线只能对应一个触发源(如EXTI0可连接PA0或PB0,但同一时间只能选一个)。

2.2 边沿检测电路

每条中断线都配备边沿检测电路,用于判断电平变化是否有效,支持三种触发方式:

  • 上升沿触发:引脚电平从低→高跳变时触发(如按键按下,从GND到VCC)
  • 下降沿触发:引脚电平从高→低跳变时触发(如按键松开,从VCC到GND)
  • 双边沿触发:上升沿和下降沿均触发(如需要检测按键按下和松开两个动作)

边沿检测的核心是寄存器配置:通过EXTI_RTSR(上升沿触发选择寄存器)和EXTI_FTSR(下降沿触发选择寄存器)设置。
在这里插入图片描述

2.3 中断屏蔽寄存器(EXTI_IMR)与事件屏蔽寄存器(EXTI_EMR)

这两个寄存器用于控制中断线是否允许触发中断或事件:

  • EXTI_IMR:bit0bit18对应EXTI0EXTI18,置1表示允许触发中断
  • EXTI_EMR:bit0bit18对应EXTI0EXTI18,置1表示允许触发事件

例如:若EXTI_IMR的bit0=1,则EXTI0的有效触发会产生中断请求;若EXTI_EMR的bit0=1,则会产生事件信号。

2.4 中断请求寄存器(EXTI_PR)

当EXTI检测到有效触发时,会在EXTI_PR中对应位置1(如EXTI0触发,bit0=1),表示"待处理请求"。在中断服务程序中,需手动清零该位(写1清零),否则会持续触发中断。

三、EXTI与GPIO的映射关系:如何将引脚连接到中断线?

EXTI0~EXTI15与GPIO引脚的映射是EXTI使用的核心知识点,也是初学者最容易混淆的部分。

3.1 映射规则:同一中断线对应多个GPIO引脚

STM32的GPIO分为多个端口(AG),每个端口有16个引脚(015)。EXTI0~EXTI15与GPIO的映射规则是:

  • EXTI_x(x=0~15)可映射到任意端口的x号引脚,即:
    • EXTI0 → PA0、PB0、PC0、…、PG0
    • EXTI1 → PA1、PB1、PC1、…、PG1
    • …以此类推…
    • EXTI15 → PA15、PB15、PC15、…、PG15

例如,若需要用PB3作为外部中断源,应选择EXTI3,并将其映射到PB3。

3.2 映射配置:通过AFIO寄存器选择端口

中断线与GPIO的映射通过AFIO(复用功能I/O) 寄存器配置,具体是AFIO_EXTICRx寄存器(x=1~4):

  • AFIO_EXTICR1:配置EXTI0~EXTI3
  • AFIO_EXTICR2:配置EXTI4~EXTI7
  • AFIO_EXTICR3:配置EXTI8~EXTI11
  • AFIO_EXTICR4:配置EXTI12~EXTI15

每个寄存器的低4位对应一条中断线,用于选择端口(0=PA,1=PB,2=PC,…,6=PG)。

例如,配置EXTI3映射到PB3:

// 标准库代码:EXTI3映射到GPIOB
AFIO->EXTICR[0] &= ~(0x0F << 12); // 清除EXTI3的配置(EXTICR1的bit12~15)
AFIO->EXTICR[0] |= (0x01 << 12);  // 0x01表示GPIOB

3.3 常用映射表(以STM32F103为例)

为方便查询,整理EXTI0~EXTI15与GPIO的映射关系如下:
在这里插入图片描述

(注:EXTI9,只限于互联型)

注意:同一时间,一条中断线只能映射到一个GPIO引脚(如EXTI0不能同时映射到PA0和PB0)。

四、EXTI配置步骤:从初始化到中断响应

使用EXTI实现外部中断的完整步骤如下(以中断模式为例):

4.1 步骤1:使能相关时钟

EXTI涉及GPIO、AFIO和EXTI本身的时钟,需先使能:

  • GPIO时钟:对应引脚所在的GPIO端口(如GPIOA、GPIOB)
  • AFIO时钟:用于配置中断线与GPIO的映射(必须使能)
  • (EXTI无需单独使能时钟,属于内核外设)
// HAL库代码:使能GPIOA、AFIO时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();

4.2 步骤2:配置GPIO为输入模式

外部中断的引脚需配置为输入模式(浮空输入、上拉输入或下拉输入):

  • 浮空输入:适用于外部有上拉/下拉电阻的场景(如按键外接电阻)
  • 上拉输入:适用于无外部电阻的场景(默认高电平,按下接GND)
  • 下拉输入:适用于无外部电阻的场景(默认低电平,按下接VCC)
// HAL库代码:配置PA0为上拉输入
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;      // 输入模式
GPIO_InitStruct.Pull = GPIO_PULLUP;          // 上拉输入(默认高电平)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速(输入模式无影响)
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

4.3 步骤3:配置EXTI映射(AFIO)

通过AFIO寄存器将GPIO引脚映射到对应的EXTI线(如PA0→EXTI0):

// HAL库代码:将PA0映射到EXTI0
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // 先设置NVIC优先级(见步骤5)
HAL_NVIC_EnableIRQ(EXTI0_IRQn);         // 使能EXTI0中断// 配置映射(HAL库通过GPIO_InitTypeDef的Mode间接配置AFIO)
// 注意:在HAL中,需将GPIO模式设置为GPIO_MODE_IT_RISING(上升沿中断)等,自动关联EXTI

HAL库的简化:在HAL中无需直接操作AFIO_EXTICR,只需将GPIO的Mode设置为中断模式(如GPIO_MODE_IT_RISING),库函数会自动配置映射。

4.4 步骤4:配置EXTI触发方式与屏蔽

通过EXTI寄存器设置触发方式(上升沿/下降沿)和使能中断:

// HAL库代码:配置EXTI0为上升沿触发(在GPIO初始化时同步配置)
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿中断模式
// 其他可选模式:GPIO_MODE_IT_FALLING(下降沿)、GPIO_MODE_IT_RISING_FALLING(双边沿)

4.5 步骤5:配置NVIC(嵌套向量中断控制器)

EXTI的中断请求需要通过NVIC(内核外设)才能被CPU响应,需配置:

  • 中断优先级:通过抢占优先级和子优先级设置(数值越小优先级越高)
  • 使能中断通道:允许EXTI对应的中断线向CPU发送请求
// HAL库代码:配置EXTI0的NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0); // 抢占优先级2,子优先级0
HAL_NVIC_EnableIRQ(EXTI0_IRQn);         // 使能EXTI0中断

4.6 步骤6:编写中断服务程序(ISR)

当EXTI触发中断后,CPU会跳转到对应的中断服务程序。STM32的EXTI中断服务程序名称是固定的(如EXTI0_IRQHandler对应EXTI0)。

在ISR中需完成:

  1. 检查中断标志(确认是否由目标EXTI线触发)
  2. 清除中断标志(避免重复触发)
  3. 执行中断处理逻辑(如控制LED、读取传感器)
// 中断服务程序(启动文件中定义,不可修改函数名)
void EXTI0_IRQHandler(void)
{// HAL库中断处理函数:会自动检查标志并清除HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}// HAL库回调函数:用户在此编写中断处理逻辑
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if (GPIO_Pin == GPIO_PIN_0) // 确认是PA0触发的中断{// 处理逻辑:如翻转LEDHAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);}
}

注意HAL_GPIO_EXTI_Callback是所有EXTI中断的通用回调函数,需通过GPIO_Pin判断具体触发源。

五、EXTI实战案例:按键中断控制LED

下面通过一个完整案例(按键触发EXTI中断,控制LED翻转),演示EXTI的使用流程。

5.1 硬件设计

  • 按键:PA0(下拉输入,按下时接3.3V,产生上升沿)在这里插入图片描述

  • LED:PB0、PB1、PB5(推挽输出,低电平点亮)

  • 按键按下时,PA0电平从高→低(下降沿),触发EXTI0中断,在中断中翻转LED状态。在这里插入图片描述

5.2 软件实现(HAL库)

(1)初始化函数
#include "stm32f1xx_hal.h"// 全局变量
GPIO_InitTypeDef GPIO_InitStruct;void SystemClock_Config(void);
static void MX_GPIO_Init(void);int main(void)
{// 初始化HAL库HAL_Init();// 配置系统时钟SystemClock_Config();// 初始化GPIO(按键和LED)MX_GPIO_Init();// 主循环while (1){// 主任务:此处为空,演示中断的被动响应}
}// GPIO初始化函数
static void MX_GPIO_Init(void)
{// 使能GPIOA、GPIOC、AFIO时钟__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();// 配置LED(PC13)为推挽输出GPIO_InitStruct.Pin = GPIO_PIN_13;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);// 配置按键(PA0)为上升沿中断模式,下拉输入
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发中断
GPIO_InitStruct.Pull = GPIO_PULLDOWN;       // 为下拉输入      HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 配置NVIC(EXTI0中断)HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // 优先级0(最高)HAL_NVIC_EnableIRQ(EXTI0_IRQn);         // 使能中断
}
(2)中断服务程序与回调函数
// EXTI0中断服务程序
void EXTI0_IRQHandler(void)
{// 调用HAL库中断处理函数(自动清标志)HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}// 中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if (GPIO_Pin == GPIO_PIN_0){// 按键按下(下降沿),翻转LEDHAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);// 软件消抖(简单处理:延时后再检查引脚状态)HAL_Delay(10); // 10ms消抖if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){// 确认按键按下,可添加其他逻辑(如打印信息)printf("按键按下,LED已翻转\r\n");}}
}
(3)系统时钟配置(省略,根据实际硬件生成)
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};// 配置时钟...(使用STM32CubeMX生成即可)
}

5.3 代码解析与注意事项

  1. 触发方式选择:按键按下时电平从高→低,因此用GPIO_MODE_IT_FALLING(下降沿触发);若需要检测按下和松开,可改用GPIO_MODE_IT_RISING_FALLING(双边沿)。

  2. 软件消抖:机械按键会有10~20ms的抖动,导致一次按下触发多次中断,需在回调函数中添加延时消抖(如HAL_Delay(10))。

  3. 中断优先级:若系统中有多个中断,需合理设置优先级(如高频响应的中断设为高优先级)。

  4. 标志清除:HAL库的HAL_GPIO_EXTI_IRQHandler会自动清除EXTI_PR中的标志位,无需手动操作;若用标准库,需手动写1清零(EXTI->PR |= EXTI_PR_PR0)。

六、EXTI高级特性:中断共享、事件模式与低功耗唤醒

6.1 中断线共享:多个引脚共用一条EXTI线

当多个引脚需要使用同一中断线时(如PA0和PB0共用EXTI0),需在中断服务程序中区分具体触发引脚,步骤如下:

  1. 配置多个GPIO引脚映射到同一EXTI线(如PA0和PB0都映射到EXTI0)
  2. 在中断服务程序中,通过HAL_GPIO_ReadPin检查各引脚状态,判断实际触发源
// 示例:PA0和PB0共用EXTI0,中断中区分触发源
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if (GPIO_Pin == GPIO_PIN_0){// 检查PA0状态if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){printf("PA0触发中断\r\n");}// 检查PB0状态else if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){printf("PB0触发中断\r\n");}}
}

注意:同一中断线的多个引脚需配置相同的触发方式(如都用下降沿)。

6.2 事件模式:无CPU参与的硬件联动

事件模式用于触发外设联动,无需CPU干预,典型应用如"外部信号触发ADC采样":

  1. 配置EXTI为事件模式(GPIO_MODE_EVT_RISING
  2. 将EXTI事件输出连接到ADC的触发源
  3. 当EXTI检测到有效电平变化时,直接启动ADC转换
// 示例:EXTI0事件模式触发ADC1采样
void EXTI_Event_Init(void)
{// 1. 配置PA0为上升沿事件模式GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING; // 上升沿事件GPIO_InitStruct.Pull = GPIO_PULLDOWN;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 2. 配置AFIO,将PA0映射到EXTI0__HAL_AFIO_REMAP_EXTI0_PA0(); // 宏定义配置映射// 3. 使能EXTI0事件(EXTI_EMR寄存器)EXTI->EMR |= EXTI_EMR_MR0; // 允许EXTI0产生事件// 4. 配置ADC1由EXTI0事件触发ADC_HandleTypeDef hadc1;hadc1.Instance = ADC1;// ... ADC其他配置 ...ADC_ChannelConfTypeDef sConfig = {0};sConfig.TriggerSource = ADC_EXTERNALTRIGCONV_T1_CC1; // 假设映射到EXTI0HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

事件模式的优势是零CPU开销,适合高速实时采集场景(如传感器数据突发采样)。

6.3 低功耗模式下的EXTI唤醒

EXTI是低功耗模式(如停机模式、待机模式)的重要唤醒源,当系统进入低功耗状态时,EXTI可通过外部信号将其唤醒:

// 示例:进入停机模式,等待EXTI0唤醒
void EnterStopMode(void)
{// 1. 配置EXTI0为下降沿中断(唤醒源)// ... 已在初始化中完成 ...// 2. 关闭不必要的外设时钟__HAL_RCC_GPIOA_CLK_DISABLE();__HAL_RCC_GPIOB_CLK_DISABLE();// 3. 进入停机模式HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);// 4. 唤醒后重新配置系统时钟SystemClock_Config();
}

唤醒原理:EXTI的中断信号可穿透低功耗模式,触发CPU从停机状态恢复,执行中断服务程序后回到主循环。

七、EXTI常见问题与解决方案

7.1 中断不触发:排查步骤

若EXTI中断未按预期触发,可按以下步骤排查:

  1. GPIO配置检查

    • 确认引脚模式是否为中断模式(GPIO_MODE_IT_xxx
    • 检查上拉/下拉配置是否正确(如按键是否接反导致电平未变化)
    • 用示波器测量引脚,确认触发时是否有预期的电平变化
  2. EXTI映射检查

    • 确认AFIO配置正确(中断线与GPIO引脚对应)
    • 检查是否有其他外设占用了该中断线(如TIM的外部触发)
  3. NVIC配置检查

    • 确认HAL_NVIC_EnableIRQ已调用(中断通道已使能)
    • 检查中断优先级是否被更高优先级中断屏蔽
  4. 标志位检查

    • 触发后查看EXTI_PR寄存器,确认对应位是否置1(若未置1,说明未检测到有效触发)
    • 若用标准库,确认已清除标志位(否则只会触发一次)

7.2 中断频繁触发:抖动与噪声处理

机械按键或外部噪声可能导致中断频繁触发,解决方案:

  1. 硬件消抖:在引脚处并联100nF电容,滤除高频噪声
  2. 软件消抖:在中断回调函数中添加延时后再检测引脚状态:
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {if (GPIO_Pin == GPIO_PIN_0){HAL_Delay(10); // 10ms消抖if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){// 确认有效触发}}
    }
    
  3. 中断屏蔽:处理中断时暂时屏蔽该中断线,避免嵌套触发:
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {if (GPIO_Pin == GPIO_PIN_0){HAL_NVIC_DisableIRQ(EXTI0_IRQn); // 屏蔽中断// 处理逻辑HAL_Delay(10); // 消抖HAL_NVIC_EnableIRQ(EXTI0_IRQn);  // 重新使能}
    }
    

7.3 多中断优先级冲突:合理设置抢占优先级

当多个中断同时触发时,需通过抢占优先级控制响应顺序:

  • 抢占优先级高的中断可打断正在执行的低优先级中断
  • 若抢占优先级相同,根据中断向量表顺序响应(EXTI0比EXTI1先响应)

示例:设置按键中断(EXTI0)优先级高于定时器中断:

// 按键中断(高优先级)
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // 抢占优先级0
// 定时器中断(低优先级)
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);  // 抢占优先级1

八、EXTI应用场景总结

EXTI作为STM32的核心外设,应用场景广泛,典型包括:

  1. 按键输入:通过中断检测按键按下/松开,替代轮询节省CPU资源
  2. 传感器触发:如红外传感器检测到物体、加速度传感器检测到震动时触发中断
  3. 外部设备同步:与外部芯片(如FPGA、DSP)通过中断信号实现同步通信
  4. 低功耗唤醒:在电池供电设备中,用EXTI唤醒低功耗模式,延长续航
  5. 故障检测:如电源欠压、温度过高等异常信号触发中断,执行保护逻辑

EXTI的核心价值在于实时响应外部事件,同时最小化CPU占用,是嵌入式系统中处理异步事件的首选方案。

九、总结与扩展学习

本文详细讲解了STM32 EXTI的工作原理、硬件结构、配置步骤和实战案例,核心要点:

  • EXTI通过19条中断线实现外部事件检测,支持中断和事件两种响应模式
  • 中断线与GPIO的映射需通过AFIO配置,每条线可对应多个引脚但同一时间只能选一个
  • 配置流程包括时钟使能、GPIO初始化、EXTI映射、触发方式设置、NVIC配置和中断服务程序编写
  • 实际应用中需注意消抖、优先级设置和标志位清除

扩展学习建议

  1. 深入研究EXTI与其他外设的联动(如EXTI触发DMA传输、定时器捕获)
  2. 学习中断嵌套和优先级管理的高级技巧
  3. 探索EXTI在实时操作系统(如FreeRTOS)中的应用(如中断服务程序与任务通信)

掌握EXTI是STM32开发的基础技能,灵活运用EXTI能显著提升系统的响应速度和效率,为复杂嵌入式系统开发奠定基础。

http://www.dtcms.com/a/277552.html

相关文章:

  • Vue中的render()函数
  • word中多行合一功能实现
  • python基础知识pip配置pip.conf文件
  • Tableau破解安装
  • ROS2---NodeOptions
  • 数据预处理
  • 基于requests_html的爬虫实战
  • UE5多人MOBA+GAS 20、添加眩晕
  • 基于Flink的实时开发平台-Dinky
  • 基于Leaflet调用天地图在线API的多层级地名检索实战
  • LeetCode第 458 场周赛题解
  • 复习笔记 35
  • PHP语法高级篇(二):文件处理
  • c++ thread_local
  • Java求职面试:从Spring到微服务的全面挑战
  • 牛客周赛 Round 100
  • Android事件分发机制完整总结
  • CMSIS(Cortex Microcontroller Software Interface Standard)ARM公司为 Cortex-M 系列处理器
  • 互联网大厂Java面试:从Spring Boot到微服务的场景应用
  • 2024CVPR:Question Aware Vision Transformer for Multimodal Reasoning介绍
  • 考研复习-数据结构-第六章-图
  • RedisJSON 技术揭秘(五)`JSON.ARRPOP` 原子弹出 修改数组的终极手段
  • git实操
  • HTML 标题标签
  • 香港理工大学实验室定时预约
  • 【windows办公小助手】快速搜索文件及文件所处目录everything
  • 内存对齐与缓存优化:从硬件原理到代码实战
  • 前端进阶之路-从传统前端到VUE-JS(第五期-路由应用)
  • 通信网络编程5.0——JAVA
  • 新手向:使用Python从PDF中高效提取结构化文本