外部中断实验演示理论
106.3.1外部中断实验演示理论
/* ==================== Core\Inc\main.h ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define EXIT_KEY1_Pin GPIO_PIN_3
#define EXIT_KEY1_GPIO_Port GPIOE
#define EXIT_KEY1_EXTI_IRQn EXTI3_IRQn
#define EXTI_KEY2_Pin GPIO_PIN_4
#define EXTI_KEY2_GPIO_Port GPIOE
#define EXTI_KEY2_EXTI_IRQn EXTI4_IRQn
#define LED1_Pin GPIO_PIN_5
#define LED1_GPIO_Port GPIOB
#define BEEP_Pin GPIO_PIN_8
#define BEEP_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/* ==================== Core\Inc\gpio.h ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file gpio.h
* @brief This file contains all the function prototypes for
* the gpio.c file
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __GPIO_H__
#define __GPIO_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_GPIO_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */
/* ==================== Core\Inc\stm32f1xx_it.h ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f1xx_it.h
* @brief This file contains the headers of the interrupt handlers.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F1xx_IT_H
#define __STM32F1xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void EXTI3_IRQHandler(void);
void EXTI4_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F1xx_IT_H */
/* ==================== Core\Src\main.c ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* 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();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(EXIT_KEY1_GPIO_Port, EXIT_KEY1_Pin)==0)
{
HAL_GPIO_TogglePin(BEEP_GPIO_Port, BEEP_Pin);
}
if(HAL_GPIO_ReadPin(EXTI_KEY2_GPIO_Port, EXTI_KEY2_Pin)==0)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
}
}
/* 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 */
__disable_irq();
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,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/* ==================== Core\Src\gpio.c ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file gpio.c
* @brief This file provides code for the configuration
* of all used GPIO pins.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "gpio.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/*----------------------------------------------------------------------------*/
/* Configure GPIO */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PEPin PEPin */
GPIO_InitStruct.Pin = EXIT_KEY1_Pin|EXTI_KEY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = BEEP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(BEEP_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
HAL_NVIC_SetPriority(EXTI4_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* ==================== Core\Src\stm32f1xx_it.c ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f1xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/******************************************************************************/
/* Cortex-M3 Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
/**
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void)
{
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
/* USER CODE END MemoryManagement_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
/* USER CODE END W1_MemoryManagement_IRQn 0 */
}
}
/**
* @brief This function handles Prefetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
/* USER CODE BEGIN BusFault_IRQn 0 */
/* USER CODE END BusFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
/* USER CODE END W1_BusFault_IRQn 0 */
}
}
/**
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void)
{
/* USER CODE BEGIN UsageFault_IRQn 0 */
/* USER CODE END UsageFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
/* USER CODE END W1_UsageFault_IRQn 0 */
}
}
/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
/* USER CODE BEGIN SVCall_IRQn 0 */
/* USER CODE END SVCall_IRQn 0 */
/* USER CODE BEGIN SVCall_IRQn 1 */
/* USER CODE END SVCall_IRQn 1 */
}
/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void)
{
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
}
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f1xx.s). */
/******************************************************************************/
/**
* @brief This function handles EXTI line3 interrupt.
*/
void EXTI3_IRQHandler(void)
{
/* USER CODE BEGIN EXTI3_IRQn 0 */
/* USER CODE END EXTI3_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(EXIT_KEY1_Pin);
/* USER CODE BEGIN EXTI3_IRQn 1 */
/* USER CODE END EXTI3_IRQn 1 */
}
/**
* @brief This function handles EXTI line4 interrupt.
*/
void EXTI4_IRQHandler(void)
{
/* USER CODE BEGIN EXTI4_IRQn 0 */
/* USER CODE END EXTI4_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(EXTI_KEY2_Pin);
/* USER CODE BEGIN EXTI4_IRQn 1 */
/* USER CODE END EXTI4_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
一、外部中断实验演示
本实验实现两项功能:
| 输入 | MCU 引脚 | 触发边沿 | 输出 | MCU 引脚 |
|---|---|---|---|---|
| KEY1 | PE3 | 下降沿 | 蜂鸣器翻转 | PB8 |
| KEY0 | PE4 | 下降沿 | LED1 翻转 | PB5 |
按键松开时由内部上拉保持高电平,按下后接地变低,所以按下瞬间形成下降沿。外部中断让 CPU 不必在主循环中不停询问按键;引脚出现目标边沿后,硬件自动提出中断请求。
flowchart LR
KEY[按键按下] --> EDGE[PE3/PE4 产生下降沿]
EDGE --> EXTI[EXTI3/EXTI4 挂起]
EXTI --> NVIC[NVIC 仲裁优先级]
NVIC --> ISR[EXTI3/EXTI4_IRQHandler]
ISR --> HAL[HAL_GPIO_EXTI_IRQHandler]
HAL --> CB[HAL_GPIO_EXTI_Callback]
CB --> OUT[翻转蜂鸣器或 LED]
1.1 中断基本概念
中断是处理器对异步事件的硬件响应。主程序正常执行时,某个中断源提出请求;满足使能和优先级条件后,CPU 暂停当前指令流,保存必要现场,跳到对应中断服务程序,处理完成后再返回原位置继续执行。
主程序:A → B → C ─────────────→ D → E
↑ ↓
中断请求 └─ ISR:保存现场 → 处理 → 返回
轮询与中断的区别:
| 方式 | CPU 行为 | 优点 | 风险/代价 |
|---|---|---|---|
| 轮询 | 周期性主动读取状态 | 流程直观,调试简单 | 响应取决于轮询周期,占用执行时间 |
| 中断 | 事件到来才跳入 ISR | 响应及时,主循环可做其他工作 | 存在并发、优先级和 ISR 时长问题 |
中断不等于多线程,但会打断主程序,也可能被更高优先级中断打断,所以共享变量仍有并发问题。主程序与 ISR 共用的状态通常需要 volatile、临界区或原子操作。
1.2 外部中断
外部中断的信号来自 MCU 引脚或少数内部事件线。STM32F1 的 GPIO 外部中断不是“每个 GPIO 都有独立中断线”,而是同号引脚共享同一条 EXTI 线:
PA0/PB0/PC0/... ──选择一个──> EXTI0
PA1/PB1/PC1/... ──选择一个──> EXTI1
...
PA15/PB15/... ──选择一个──> EXTI15
端口选择由 AFIO_EXTICR1~4 完成。因此 PE3 使用 EXTI3,PE4 使用 EXTI4;同一时刻不能再把 PB3 也独立映射为另一条 EXTI3。
1.2.1 实验演示按键控制蜂鸣器和灯
开发板按键和输出器件的电路决定了有效电平。
PE3/PE4 按键:
STM32 内部 开发板
3.3 V ──[弱上拉]──┬── PE3/PE4 ── 按键 ── GND
│
输入缓冲
松开:GPIO=1
按下:GPIO=0,形成 1→0 下降沿
PB5 LED1:
3.3 V ── LED ──[1 kΩ]── PB5
PB5=0:MCU 吸收电流,LED 亮
PB5=1:LED 两端压差接近 0,LED 灭
PB8 蜂鸣器:
3.3 V
│
有源蜂鸣器
│
C
PB8 ──[1 kΩ]── B S8050 NPN
E │
├──[10 kΩ]── GND
└─────────── GND
PB8=1:基极有电流,三极管导通,蜂鸣器响
PB8=0:三极管截止,蜂鸣器停
MCU 不直接承担蜂鸣器工作电流。PB8 只提供受限的基极电流,S8050 像受控开关一样接通蜂鸣器到地的电流路径。10 kΩ 下拉使 PB8 上电高阻时三极管保持截止,避免误响。原理图标注 3 kHz 表明它是带内部振荡的有源蜂鸣器,给直流使能电平即可发声;无源蜂鸣器则需要 PWM。
实验初始值为 LED1=高(灭)、BEEP=低(停)。每次按键确认后执行 Toggle,所以输出在开与关之间切换。
1.2.2 中断配置
外部按键中断需要同时打通五层:
- GPIOE 时钟和 AFIO 时钟;
- PE3/PE4 配为带上拉的输入;
- AFIO 将 EXTI3/4 映射到端口 E;
- EXTI 选择下降沿并解除中断屏蔽;
- NVIC 设置优先级并使能对应 IRQ。
任何一层缺失都会导致 IRQHandler 不执行。
1.2.2.1 芯片电路图分析
经典 8051 的外部中断入口通常是 P3.2/INT0 和 P3.3/INT1。课程 51 开发板的两只按键按下时接地,松开状态利用 P3 准双向口自身的内部上拉保持为高;它们是芯片预先固定的专用复用引脚。
STM32F103 的结构更灵活:几乎任意 Px0~Px15 都可连接对应编号的 EXTIx,但必须经过 AFIO 选择端口。
8051:
按键 ──> 固定的 P3.2/INT0 或 P3.3/INT1 ──> 中断控制器
STM32F1:
PE3 ──> AFIO_EXTICR1 选择端口 E ──> EXTI3 ──> NVIC
PE4 ──> AFIO_EXTICR2 选择端口 E ──> EXTI4 ──> NVIC
看原理图时应依次回答:
- 按键按下接 VCC 还是 GND?
- 松开状态由外部电阻还是内部上下拉确定?
- 输出器件高电平有效还是低电平有效?
- MCU 是直接驱动负载,还是通过三极管/MOSFET?
- 原理图网络名与代码宏是否一致?
本实验蜂鸣器是 PB8,不是 PB0;LED1 是 PB5;按键为 PE3 和 PE4。
1.2.2.2 配置界面
CubeMX/CubeIDE 中的配置要点:
| 引脚 | 功能 | GPIO Pull-up/Pull-down | User Label |
|---|---|---|---|
| PE3 | GPIO_EXTI3 | Pull-up | EXIT_KEY1 |
| PE4 | GPIO_EXTI4 | Pull-up | EXTI_KEY2 |
| PB5 | GPIO_Output | Pull-up,Low speed | LED1 |
| PB8 | GPIO_Output | Pull-down,Low speed | BEEP |
PE3/PE4 选择 External Interrupt Mode with Falling edge trigger detection。随后在 NVIC 中启用 EXTI line3 和 EXTI line4。
标签只影响生成的宏名,不改变硬件功能。工程中 KEY1 宏写成 EXIT_KEY1,KEY2 写成 EXTI_KEY2,虽然拼写不完全一致,但必须在 main.h、gpio.c 与中断文件中保持一致。
1.2.2.3 外部通用中断线
STM32F103 常用 EXTI 线:
| EXTI 线 | 来源 |
|---|---|
| 0~15 | GPIO 的 0~15 号引脚,由 AFIO 选择端口 |
| 16 | PVD 输出 |
| 17 | RTC Alarm |
| 18 | USB Wakeup |
| 19 | 仅互联型器件的 Ethernet Wakeup;普通 STM32F103 不使用 |
IRQ 向量的组合方式:
| 线 | NVIC IRQ |
|---|---|
| EXTI0~EXTI4 | 各自独立 IRQ |
| EXTI5~EXTI9 | 共用 EXTI9_5_IRQn |
| EXTI10~EXTI15 | 共用 EXTI15_10_IRQn |
共享 IRQ 中必须检查 PR 挂起位,判断究竟是哪一条线触发。
1.2.2.4 中断和事件控制器
EXTI 同一套边沿检测可走两条输出通路:
flowchart LR
IN[输入线] --> EDGE[上升/下降沿检测]
EDGE --> PEND[挂起请求]
PEND --> IMR{IMR 是否开放}
IMR -->|是| NVIC[NVIC 中断请求]
EDGE --> EMR{EMR 是否开放}
EMR -->|是| EVT[事件脉冲/WFE 唤醒]
SWIER[软件请求] --> PEND
- 中断通路经过 IMR 和 NVIC,CPU 跳转到 ISR;
- 事件通路经过 EMR,可产生事件脉冲或唤醒 WFE,不必执行 ISR;
- RTSR 选择上升沿,FTSR 选择下降沿,两者可同时开启;
- PR 记录挂起状态,写 1 清除;
- SWIER 可由软件模拟提出请求。
1.2.2.5 中断配置示例
本实验 PE3/PE4 的关键寄存器结果:
RCC_APB2ENR.IOPEEN = 1
RCC_APB2ENR.AFIOEN = 1
AFIO_EXTICR1.EXTI3 = 0100 (端口 E)
AFIO_EXTICR2.EXTI4 = 0100 (端口 E)
EXTI_FTSR.TR3 = 1
EXTI_FTSR.TR4 = 1
EXTI_RTSR.TR3 = 0
EXTI_RTSR.TR4 = 0
EXTI_IMR.MR3 = 1
EXTI_IMR.MR4 = 1
NVIC 再分别使能 EXTI3_IRQn 和 EXTI4_IRQn。边沿发生后,硬件置位 PR3/PR4;HAL 中断处理函数写 1 清除对应挂起位,再调用用户回调。若不清 PR,中断会再次进入。
按键机械抖动会产生多个下降/上升沿。可靠设计应让 ISR 只记录“哪一键发生事件”和时间戳,再由主循环确认稳定状态;不应把长延时、串口打印或复杂业务全部放进中断回调。