| name | atk-f407 |
| description | 正点原子 探索者 STM32F407ZGT6 开发板 V3 完整硬件参考。
用于 vibe coding 时快速了解引脚分配、外设映射、可用IO、冲突约束及 HAL 代码框架,
确保生成代码引脚规划准确无误。
调用场景:任何涉及该开发板的外设配置、引脚规划、HAL 驱动编写任务。
|
| metadata | {"board":"ATK-Explorer STM32F407 V3","mcu":"STM32F407ZGT6 (176-pin LQFP)","clock":"168 MHz (HSE 8 MHz → PLL 336/2)","flash":"1 MB internal + 16 MB W25Q128 (SPI)","ram":"192 KB internal + 1 MB external SRAM (FSMC)"} |
ATK-Explorer STM32F407 V3 硬件参考
1. 核心参数
| 项目 | 值 |
|---|
| MCU | STM32F407ZGT6,Cortex-M4,168 MHz,FPU |
| 主晶振 | 8 MHz (OSC_IN/OSC_OUT) |
| RTC晶振 | 32.768 kHz (PC14/PC15,不可用作 GPIO) |
| 备用电源 | VBAT → CR1220(PC13 共享,不可用作 GPIO) |
| BOOT0 | 硬件控制(CH340C DTR/RTS 自动下载),BOOT1=PB2 |
| 下载口 | USART1 via CH340C(PA9/PA10,P10 跳线) |
2. 引脚分配总表
图例:● = 专用已占用,不可复用 ○ = 条件可用(见备注) ✓ = 自由可用
"条件可用"指该引脚在不使用对应外设时或拔掉对应跳线帽后可当普通 IO 使用。
PORT A
| Pin | 功能 | 状态 | 备注 |
|---|
| PA0 | WK_UP / KEY_UP | ✓ | 高电平有效按键;不按下时可安全使用 |
| PA1 | RMII_REF_CLK (ETH) | ● | 直连 YT8512C TXC,50MHz 持续输出,不能用 |
| PA2 | USART2_TX / RS485_RX / ETH_MDIO | ○ | P4 跳线选 RS232 or RS485;拔 P4 可当 IO |
| PA3 | USART2_RX / RS485_TX / PWM_DAC | ○ | 同 PA2,拔 P4 可当 IO |
| PA4 | STM_DAC / DCMI_HREF | ✓ | DAC_OUT1;不用摄像头时完全自由 |
| PA5 | STM_ADC / TPAD | ✓ | ADC + 电容触摸键;P11 跳线,可自由使用 |
| PA6 | DCMI_PCLK | ✓ | 不用摄像头时完全自由 |
| PA7 | RMII_CRS_DV (ETH) | ● | 直连 YT8512C,不能用 |
| PA8 | DCMI_XCLK / REMOTE_IN / PWM_DAC | ○ | TIM1_CH1;LF0038 红外接收头(4.7K 上拉),可当 IO |
| PA9 | USART1_TX | ✓ | P10 跳线接 CH340C;可直接作 USART1 TX 使用 |
| PA10 | USART1_RX | ✓ | P10 跳线接 CH340C;可直接作 USART1 RX 使用 |
| PA11 | USB_D− / CAN_RX | ✓ | P5 跳线选 USB or CAN;拔 P5 跳线帽后可当 IO |
| PA12 | USB_D+ / CAN_TX | ✓ | 同 PA11 |
| PA13 | JTMS/SWDIO | ○ | SWD 调试用;不调试时可当 IO(内部 10K 上/下拉) |
| PA14 | JTCK/SWCLK | ○ | 同 PA13 |
| PA15 | JTDI / USB_PWR | ○ | USB HOST 供电控制;不用时可当 IO(10K 上拉) |
PORT B
| Pin | 功能 | 状态 | 备注 |
|---|
| PB0 | T_SCK(触摸屏 SPI SCK) | ✓ | 不接 LCD 触摸模块时完全自由 |
| PB1 | T_PEN(触摸屏中断) | ✓ | 同 PB0 |
| PB2 | BOOT1 / T_MISO | ○ | 上电 BOOT1(10K 下拉接地);运行后可用;不用 LCD 触摸可当 IO |
| PB3 | JTDO / SPI1_SCK(W25Q128 + NRF24L01) | ● | SPI1 总线,禁止 Flash CS 时可用;不用 SPI 设备才可当 IO |
| PB4 | JTRST / SPI1_MISO | ● | 同 PB3 |
| PB5 | SPI1_MOSI | ● | 同 PB3 |
| PB6 | DCMI_D5 | ✓ | 不用摄像头时完全自由 |
| PB7 | DCMI_VSYNC | ✓ | 不用摄像头时完全自由 |
| PB8 | I2C1_SCL(24C02 / ES8388 / ST480MC) | ● | 4.7K 上拉;不用这些器件可当 IO,但上拉已焊 |
| PB9 | I2C1_SDA | ● | 同 PB8 |
| PB10 | USART3_TX / RS232_COM3_RX / ATK_RXD | ✓ | P2 跳线接 RS232/ATK 模块;拔 P2 后完全自由 |
| PB11 | USART3_RX / RS232_COM3_TX / ATK_TXD | ✓ | 同 PB10 |
| PB12 | I2S2_LRCK (ES8388) | ○ | 不用音频时可当 IO |
| PB13 | I2S2_SCLK (ES8388) | ○ | 不用音频时可当 IO |
| PB14 | W25Q128 片选 F_CS | ● | SPI Flash CS,不用 Flash 时才可当 IO |
| PB15 | LCD_BL(LCD 背光 PWM) | ✓ | 使用 LCD 时驱动背光,也可用作 PWM IO |
PORT C
| Pin | 功能 | 状态 | 备注 |
|---|
| PC0 | ATK_MODULE_LED | ○ | 不用 ATK 模块可当 IO |
| PC1 | ETH_MDC (YT8512C) | ● | 不用以太网时(PHY 复位状态)才可当 IO |
| PC2 | I2S_SDOUT (ES8388) | ○ | 不用音频时可当 IO |
| PC3 | I2S_SDIN (ES8388) | ○ | 不用音频时可当 IO |
| PC4 | RMII_RXD0 (ETH) | ● | 直连 YT8512C,不能用 |
| PC5 | RMII_RXD1 (ETH) | ● | 直连 YT8512C,不能用 |
| PC6 | I2S_MCLK / DCMI_D0 | ● | 音频 MCLK;不用音频+摄像头时可当 IO |
| PC7 | DCMI_D1 | ✓ | 不用摄像头时完全自由 |
| PC8 | SDIO_D0 / DCMI_D2 | ○ | 47K 上拉;不用 SD 卡和摄像头时可当 IO |
| PC9 | SDIO_D1 / DCMI_D3 | ○ | 同 PC8 |
| PC10 | SDIO_D2 | ○ | 47K 上拉;不用 SD 卡可当 IO |
| PC11 | SDIO_D3 | ○ | 47K 上拉;不用 SD 卡可当 IO |
| PC12 | SDIO_SCK / DCMI_D4 | ✓ | 不用 SD 卡和摄像头时完全自由 |
| PC13 | T_CS(触摸屏 SPI CS) | ✓ | 不接 LCD 触摸模块时完全自由 |
| PC14 | RTC 32.768kHz 晶振 | ● | 不可用作 GPIO |
| PC15 | RTC 32.768kHz 晶振 | ● | 不可用作 GPIO |
PORT D
| Pin | 功能 | 状态 | 备注 |
|---|
| PD0 | FSMC_D2 (LCD/SRAM) | ● | FSMC 数据总线,不可用 |
| PD1 | FSMC_D3 (LCD/SRAM) | ● | FSMC 数据总线,不可用 |
| PD2 | SDIO_CMD | ○ | 47K 上拉;不用 SD 卡可当 IO |
| PD3 | ETH_RESET (YT8512C) | ○ | 不用以太网时可当 IO |
| PD4 | FSMC_NOE / RD (LCD/SRAM) | ● | FSMC 控制,不可用 |
| PD5 | FSMC_NWE / WR (LCD/SRAM) | ● | FSMC 控制,不可用 |
| PD6 | DCMI_SCL (摄像头 SCCB) | ✓ | 不用摄像头时完全自由 |
| PD7 | DCMI_SDA (摄像头 SCCB) | ✓ | 不用摄像头时完全自由 |
| PD8 | FSMC_D13 | ● | 不可用 |
| PD9 | FSMC_D14 | ● | 不可用 |
| PD10 | FSMC_D15 | ● | 不可用 |
| PD11 | FSMC_A16 (SRAM) | ● | 不可用 |
| PD12 | FSMC_A17 (SRAM) | ● | 不可用 |
| PD13 | FSMC_A18 (SRAM) | ● | 不可用 |
| PD14 | FSMC_D0 | ● | 不可用 |
| PD15 | FSMC_D1 | ● | 不可用 |
PORT E
| Pin | 功能 | 状态 | 备注 |
|---|
| PE0 | FSMC_NBL0 (SRAM) | ● | 不可用 |
| PE1 | FSMC_NBL1 (SRAM) | ● | 不可用 |
| PE2 | KEY2(低有效) | ✓ | 普通按键输入 |
| PE3 | KEY1(低有效) | ✓ | 普通按键输入 |
| PE4 | KEY0(低有效) | ✓ | 普通按键输入 |
| PE5 | DCMI_D6 | ✓ | 不用摄像头时完全自由 |
| PE6 | DCMI_D7 | ✓ | 不用摄像头时完全自由 |
| PE7~PE15 | FSMC_D4~D12 | ● | FSMC 数据总线,全部不可用 |
PORT F
| Pin | 功能 | 状态 | 备注 |
|---|
| PF0~PF5 | FSMC_A0~A5 (SRAM) | ● | 不可用 |
| PF6 | ATK_MODULE_KEY | ✓ | 不用 ATK 模块时完全自由 |
| PF7 | 光敏传感器 ADC3_IN5 | ○ | 不用光敏传感器可当 IO;有外部分压电路 |
| PF8 | BEEP(蜂鸣器) | ○ | S8050 驱动,高电平响;可复用作普通 IO 输出 |
| PF9 | LED0 DS0(红,低有效) | ○ | 可复用,LED 也会同步亮灭 |
| PF10 | LED1 DS1(绿,低有效) | ○ | 可复用,LED 也会同步亮灭 |
| PF11 | T_MOSI(触摸屏 SPI) | ✓ | 不接 LCD 触摸模块时完全自由 |
| PF12 | FSMC_A6 (LCD RS / SRAM) | ● | 不可用(LCD 的 D/C 信号) |
| PF13~PF15 | FSMC_A7~A9 (SRAM) | ● | 不可用 |
PORT G
| Pin | 功能 | 状态 | 备注 |
|---|
| PG0~PG5 | FSMC_A10~A15 (SRAM) | ● | 不可用 |
| PG6 | NRF24L01 CE | ✓ | 不用 NRF 无线模块时完全自由 |
| PG7 | NRF24L01 CSN | ✓ | 不用 NRF 无线模块时完全自由 |
| PG8 | NRF24L01 IRQ / RS485 RE/DE | ○ | 同时控制 NRF IRQ 和 RS485 方向;不用两者可当 IO |
| PG9 | DCMI_PWDN / 1-Wire DQ | ○ | 4.7K 上拉;不用摄像头和单总线传感器可当 IO |
| PG10 | FSMC_NE3 (SRAM 片选) | ● | 不可用 |
| PG11 | RMII_TX_EN (ETH) | ● | 直连 YT8512C,不能用 |
| PG12 | FSMC_NE4 (LCD 片选) | ✓ | 使用 LCD 时占用;不用 LCD 可当 IO |
| PG13 | RMII_TXD0 (ETH) | ● | 不能用 |
| PG14 | RMII_TXD1 (ETH) | ● | 不能用 |
| PG15 | DCMI_RESET | ✓ | 不用摄像头时完全自由 |
3. 常用外设快查
| 外设 | 引脚 | 芯片/接口 |
|---|
| LED0(红) | PF9 低有效 | — |
| LED1(绿) | PF10 低有效 | — |
| KEY0 | PE4 低有效 | — |
| KEY1 | PE3 低有效 | — |
| KEY2 | PE2 低有效 | — |
| KEY_UP(WK_UP) | PA0 高有效 | — |
| 蜂鸣器 | PF8 高有效 | S8050 NPN |
| LCD 背光 | PB15 高/PWM | — |
| LCD FSMC | NE4=PG12, RS=PF12(A6), RD=PD4, WR=PD5, D0-D15=PD/PE | FSMC Bank1 NE4 |
| LCD 基地址 | 0x6C000000(写RS=0) 0x6C000000+0x100(写RS=1,A6偏移) | |
| 触摸屏 SPI | SCK=PB0, MISO=PB2, MOSI=PF11, CS=PC13, PEN=PB1 | XPT2046/GT系列 |
| USART1 | TX=PA9, RX=PA10 | CH340C USB转串口(P10跳线) |
| USART2 | TX=PA2, RX=PA3 + RS485 RE/DE=PG8 | RS485(P4跳线)/RS232-COM2 |
| USART3 | TX=PB10, RX=PB11 | RS232-COM3(P2跳线)/ATK模块 |
| SPI1 | SCK=PB3, MISO=PB4, MOSI=PB5 | W25Q128 CS=PB14; NRF24L01 CE=PG6 CSN=PG7 IRQ=PG8 |
| I2C1 | SCL=PB8, SDA=PB9 | 24C02 EEPROM / ES8388音频 |
| 外部SRAM | FSMC Bank1 NE3=PG10, A0-A18=PF/PG/PD | XM8A51216 1MB 基址0x68000000 |
| SD卡 SDIO | D0-D3=PC8-PC11, SCK=PC12, CMD=PD2 | — |
| W25Q128 Flash | SPI1 + CS=PB14 | 16MB |
| 以太网 ETH | RMII: PA1,PA7,PC1,PC4,PC5,PG11,PG13,PG14 + RST=PD3 + MDIO=PA2(共享) | YT8512C |
| CAN1 | RX=PA11, TX=PA12(P5跳线,与USB互斥) | SIT1050T |
| USB_FS | DM=PA11, DP=PA12(P5跳线,与CAN互斥) | — |
| I2S / 音频 | MCLK=PC6, SCLK=PB13, LRCK=PB12, SDIN=PC3, SDOUT=PC2 | ES8388, I2C控制=PB8/PB9 |
| 摄像头 DCMI | D0-D7=PC6,PC7,PC8,PC9,PC11,PB6,PE5,PE6; PCLK=PA6,VSYNC=PB7,HREF=PA4,XCLK=PA8; SCCB=PD6/PD7; RST=PG15; PWDN=PG9 | OV2640 |
| 蜂鸣器 | PF8 | — |
| 光敏传感器 | PF7 → ADC3_IN5 | — |
| 单总线传感器 | PG9 (4.7K上拉) | DHT11 / DS18B20 |
| 红外接收 | PA8 → TIM1_CH1 | LF0038 |
| NRF24L01 | SPI1 + CE=PG6, CSN=PG7, IRQ=PG8 | — |
| TPAD电容触摸 | PA5 | RC充放电 |
| ADC测试端口 | PA5 | ADC1/2/3 IN5 |
| DAC测试端口 | PA4 | DAC_OUT1 |
| ATK模块接口 | KEY=PF6, LED=PC0, RXD=PB10, TXD=PB11 | 蓝牙/GPS等 |
4. 关键冲突约束
⚠️ PA11/PA12 = USB_DM/DP ↔ CAN1_RX/TX — 由 P5 跳线帽选择,二选一
⚠️ PA2 = USART2_TX ↔ ETH_MDIO — P4 决定接 RS485/RS232 还是以太网
⚠️ PA8 = DCMI_XCLK ↔ IR_IN — 红外和摄像头时钟共引脚
⚠️ PG8 = NRF_IRQ ↔ RS485_RE/DE — 同时控制,不可同时启用
⚠️ PG9 = DCMI_PWDN ↔ 1-Wire DQ — 摄像头与单总线传感器二选一
⚠️ PB10/PB11 = USART3 ↔ ATK_MODULE — P2 跳线帽选择
⚠️ PC6 = I2S_MCLK ↔ DCMI_D0 — 音频与摄像头 D0 冲突
⚠️ PC8~PC11 = SDIO_D0~D3 ↔ DCMI_D2~D4 — SD卡与摄像头冲突
⚠️ PB3~PB5 = SPI1共享 — W25Q128 和 NRF24L01 共用总线,用 CS 区分
⚠️ PC14/PC15 = RTC晶振 — 永远不可当 GPIO
⚠️ FSMC引脚 — PD0-D1/D8-D15, PE7-PE15, PF0-F5/F12-F15, PG0-G5/G10/G12 全部已占用
5. 推荐空闲 IO(用于新增外设)
以下为无外部硬件冲突、可直接用作新增外设的 GPIO,优先选用:
| 优先级 | 引脚 | 可用前提 | 推荐用途 |
|---|
| ★★★ | PB6, PB7 | 不用摄像头 | 普通 GPIO / UART / TIM |
| ★★★ | PC7, PC12 | 不用摄像头和SD卡 | 普通 IO |
| ★★★ | PD6, PD7 | 不用摄像头 | 普通 IO / 软 I2C |
| ★★★ | PG6, PG7 | 不用 NRF24L01 | 普通 IO |
| ★★★ | PG15 | 不用摄像头 | 普通 IO |
| ★★★ | PE5, PE6 | 不用摄像头 | 普通 IO |
| ★★ | PA11, PA12 | 拔 P5 跳线帽 | USB 或 CAN 或普通 IO |
| ★★ | PB10, PB11 | 拔 P2 跳线帽 | USART3 最常用(直连 MCU,无电平转换) |
| ★★ | PA2, PA3 | 拔 P4 跳线帽 | USART2 |
| ★ | PF6, PC0 | 不用 ATK 模块 | 普通 IO |
推荐 USART 扩展首选:USART3 (PB10/PB11),拔掉 P2 跳线帽,
直接 MCU-to-MCU 3.3V LVTTL,无需任何电平转换芯片。
6. FSMC 地址空间
#define LCD_BASE_CMD ((uint32_t)0x6C000000)
#define LCD_BASE_DATA ((uint32_t)0x6C000000 | (1<<(6+1)))
#define SRAM_BASE ((uint32_t)0x68000000)
7. 项目代码框架(HAL 库,Keil MDK)
标准目录结构
<ProjectRoot>/
├── User/ ← 用户应用代码(main.c, xxx.c/h 放这里)
├── BSP/
│ ├── LCD/ ← lcd.c lcd.h (FSMC LCD驱动, g_back_color全局)
│ ├── TOUCH/ ← touch.c touch.h (tp_dev结构体)
│ ├── LED/ ← led.c led.h
│ ├── KEY/ ← key.c key.h
│ ├── BEEP/ ← beep.c beep.h
│ ├── SPI/ ← spi.c spi.h (SPI1)
│ ├── NORFLASH/ ← norflash.c (W25Q128)
│ ├── SRAM/ ← sram.c (外部SRAM)
│ └── ...
├── SYSTEM/
│ ├── sys/ ← sys.h sys.c (时钟/RCC配置)
│ ├── delay/ ← delay.h delay.c (delay_ms, delay_us)
│ └── usart/ ← usart.h usart.c (USART1 printf重定向)
└── Middlewares/ ← FatFS / LwIP / FreeRTOS 等(按实验添加)
main.c 标准初始化模板
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/TOUCH/touch.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(336, 8, 2, 7);
delay_init(168);
usart_init(115200);
led_init();
lcd_init();
key_init();
tp_dev.init();
}
LCD 关键全局变量
extern uint16_t g_back_color;
extern _lcd_dev lcddev;
触摸屏结构体
extern _tp_dev tp_dev;
按键定义
#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3
#define WKUP_PRES 4
新外设 GPIO 初始化模板(HAL)
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_6;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &gpio);
USART3 扩展串口(最常用,PB10 TX / PB11 RX)
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_10 | GPIO_PIN_11;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_PULLUP;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
gpio.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOB, &gpio);
8. 使用本 Skill 的注意事项
- 引脚规划原则:新外设优先选用第 5 节推荐的空闲 IO;若需占用条件可用引脚,先明确对应跳线帽设置。
- USART 冲突:
usart.c 中 HAL_UART_RxCpltCallback 已为 USART1 实现,新增 USART 请使用直接寄存器 ISR 或独立 Handle。
- LCD 背景色:所有黑色背景页面必须在
lcd_clear() 前执行 g_back_color = 0x0000,否则文字周围出现白色矩形。
- SPI1 共享:W25Q128 和 NRF24L01 共用 PB3/PB4/PB5,通过各自 CS(PB14 / PG7)分时复用,不可同时拉低 CS。
- FSMC 引脚只读:所有 FSMC 相关引脚(约 40 个)在系统运行期间不可重配置为 GPIO。
- NVIC 分组:
HAL_Init() 已将 NVIC 设为 NVIC_PRIORITYGROUP_4(4位抢占、0位子优先级),全工程只有抢占优先级有效,HAL_NVIC_SetPriority 的第三个参数(子优先级)填任何值都无实际意义。
- 中断回调 delay_ms 禁用:
HAL_GPIO_EXTI_Callback 中用 delay_ms(20) 消抖是官方示例的简化写法,生产代码中禁止在中断上下文调用任何阻塞延时,改用标志位 + 主循环二次采样。
- DMA 流控/轮询:使用
HAL_UART_Transmit_DMA 后系统会自动开启 DMA 中断,若采用轮询方式(__HAL_DMA_GET_FLAG)则不需编写 IRQHandler,两者不可混用。
9. NVIC & EXTI 外部中断
9.1 本板按键 EXTI 映射
| 按键 | GPIO | EXTI线 | IRQn | IRQHandler | 触发方式 | 内部上下拉 |
|---|
| KEY_UP | PA0 | EXTI0 | EXTI0_IRQn | EXTI0_IRQHandler | 上升沿 | GPIO_PULLDOWN |
| KEY2 | PE2 | EXTI2 | EXTI2_IRQn | EXTI2_IRQHandler | 下降沿 | GPIO_PULLUP |
| KEY1 | PE3 | EXTI3 | EXTI3_IRQn | EXTI3_IRQHandler | 下降沿 | GPIO_PULLUP |
| KEY0 | PE4 | EXTI4 | EXTI4_IRQn | EXTI4_IRQHandler | 下降沿 | GPIO_PULLUP |
EXTI04 各有独立 IRQ;EXTI59 共用 EXTI9_5_IRQn;EXTI10~15 共用 EXTI15_10_IRQn。
同一 EXTI 线同时只能映射一个 GPIO 口(如 EXTI4 只能连 PA4/PB4/PC4/PD4/PE4 中的一个)。
9.2 exti.h 宏定义模板(照抄可用)
#define KEY0_INT_GPIO_PORT GPIOE
#define KEY0_INT_GPIO_PIN GPIO_PIN_4
#define KEY0_INT_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)
#define KEY0_INT_IRQn EXTI4_IRQn
#define KEY0_INT_IRQHandler EXTI4_IRQHandler
#define WKUP_INT_GPIO_PORT GPIOA
#define WKUP_INT_GPIO_PIN GPIO_PIN_0
#define WKUP_INT_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)
#define WKUP_INT_IRQn EXTI0_IRQn
#define WKUP_INT_IRQHandler EXTI0_IRQHandler
9.3 extix_init() 完整模板
void extix_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
key_init();
gpio_init_struct.Pin = KEY0_INT_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY0_INT_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = WKUP_INT_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_IT_RISING;
gpio_init_struct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(WKUP_INT_GPIO_PORT, &gpio_init_struct);
HAL_NVIC_SetPriority(KEY0_INT_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(KEY0_INT_IRQn);
HAL_NVIC_SetPriority(WKUP_INT_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(WKUP_INT_IRQn);
}
9.4 ISR + 回调标准写法
void KEY0_INT_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY0_INT_GPIO_PIN);
__HAL_GPIO_EXTI_CLEAR_IT(KEY0_INT_GPIO_PIN);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch (GPIO_Pin)
{
case KEY0_INT_GPIO_PIN:
if (KEY0 == 0) { LED0_TOGGLE(); }
break;
case WKUP_INT_GPIO_PIN:
if (WK_UP == 1) { BEEP_TOGGLE(); }
break;
default: break;
}
}
10. DMA 直接存储器访问
10.1 本板常用 DMA 流-通道映射
STM32F407 有 DMA1 和 DMA2,每个控制器 8 个 Stream,每 Stream 8 个 Channel。
仅 DMA2 支持存储器到存储器(Mem→Mem)传输。
| 外设 | 方向 | DMA控制器 | Stream | Channel | 标志宏 |
|---|
| USART1 TX | Mem→Periph | DMA2 | Stream7 | CH4 | DMA_FLAG_TCIF3_7 |
| USART1 RX | Periph→Mem | DMA2 | Stream2 | CH4 | DMA_FLAG_TCIF2_6 |
| USART2 TX | Mem→Periph | DMA1 | Stream6 | CH4 | DMA_FLAG_TCIF2_6(DMA1) |
| USART3 TX | Mem→Periph | DMA1 | Stream3 | CH4 | DMA_FLAG_TCIF3_7(DMA1) |
| SPI1 TX | Mem→Periph | DMA2 | Stream3 | CH3 | DMA_FLAG_TCIF3_7 |
| SPI1 RX | Periph→Mem | DMA2 | Stream0 | CH3 | DMA_FLAG_TCIF0_4 |
| ADC1 | Periph→Mem | DMA2 | Stream0 | CH0 | DMA_FLAG_TCIF0_4 |
DMA_FLAG_TCIFx_y 的含义:LISR 管 Stream03,HISR 管 Stream47,
同一寄存器内 Stream0 和 Stream4 位域相同,所以宏名写成 TCIF0_4 / TCIF3_7。
10.2 dma.c 完整模板(USART1 TX,照抄可用)
extern DMA_HandleTypeDef g_dma_handle;
void dma_init(DMA_Stream_TypeDef *dma_stream_handle, uint32_t ch);
#include "./BSP/DMA/dma.h"
DMA_HandleTypeDef g_dma_handle;
extern UART_HandleTypeDef g_uart1_handle;
void dma_init(DMA_Stream_TypeDef *dma_stream_handle, uint32_t ch)
{
if ((uint32_t)dma_stream_handle > (uint32_t)DMA2)
__HAL_RCC_DMA2_CLK_ENABLE();
else
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_LINKDMA(&g_uart1_handle, hdmatx, g_dma_handle);
g_dma_handle.Instance = dma_stream_handle;
g_dma_handle.Init.Channel = ch;
g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;
g_dma_handle.Init.MemInc = DMA_MINC_ENABLE;
g_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
g_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
g_dma_handle.Init.Mode = DMA_NORMAL;
g_dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;
g_dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
g_dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
g_dma_handle.Init.MemBurst = DMA_MBURST_SINGLE;
g_dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_DeInit(&g_dma_handle);
HAL_DMA_Init(&g_dma_handle);
}
10.3 main.c 调用示例(轮询方式)
dma_init(DMA2_Stream7, DMA_CHANNEL_4);
HAL_UART_Transmit_DMA(&g_uart1_handle, g_sendbuf, SEND_BUF_SIZE);
while (1)
{
if (__HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TCIF3_7))
{
__HAL_DMA_CLEAR_FLAG(&g_dma_handle, DMA_FLAG_TCIF3_7);
HAL_UART_DMAStop(&g_uart1_handle);
break;
}
float remaining = __HAL_DMA_GET_COUNTER(&g_dma_handle);
float pct = (1.0f - remaining / SEND_BUF_SIZE) * 100.0f;
lcd_show_num(30, 150, (uint32_t)pct, 3, 16, BLUE);
}
10.4 DMA 中断方式(替代轮询)
void DMA2_Stream7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&g_dma_handle);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &g_uart1_handle)
{
}
}