GD32F103入门指南:用Keil MDK从零搭建工程并点亮LED

发布时间:2026/10/4 10:19:44
GD32F103入门指南:用Keil MDK从零搭建工程并点亮LED 在嵌入式开发这块GD32F103 算是很多朋友从 51/STM32 过渡过来的热门选择。作为国产 Cortex-M3 内核芯片的代表它和 STM32F103 在引脚上基本兼容但又不是完全一样库函数也有差异。我去年做一个小项目时从 STM32 切换到 GD32踩了一圈环境配置的坑索性把“从零搭一个能点灯的最小工程”这条路子彻底捋了一遍。这篇就作为系列的第一篇重点解决三件事把开发环境装明白、把工程模板搭起来、把程序真正烧进片子跑起来。这个系列面向两类人一类是从 STM32 转过来的老手想快速对齐 GD32 的差异另一类是刚入门 ARM 内核 MCU 的新人需要一个能复现的完整流程。不管哪类这篇都能让你在一小时内拥有一个“代码→编译→下载→运行”的闭环。我先说结论环境配置这种事看着琐碎但工具链选对了后面能省一大半心。1. 工欲善其事先把整套开发环境理清楚1.1 为什么选 Keil MDK 而不是其他 IDEGD32F103 的开发环境选择其实不少主流的无非是三类Keil MDK、IAR EWARM、以及基于 GCC 的 VSCode 交叉编译器方案。我个人的建议是入门阶段直接用 Keil MDK别折腾。原因很实在。第一GD32 官方提供的标准固件库、例程、应用笔记大量都以 Keil 工程形式组织和验证你用 Keil 打开官方例程就是零成本上手。第二Keil 的调试器支持做得成熟和 J-Link、ST-Link、DAP-Link 的配合都很顺畅新手在调试阶段能少很多烦恼。第三网上关于 GD32 的中文资料十篇里有八篇是基于 Keil 的你遇到问题搜索解决方案时命中的概率大得多。那我是不是完全否定 VSCode 方案也不是。如果你之前用 STM32CubeMX CMake GCC 这套现代工具链已经很顺手那 GD32 也完全可以这么玩后面有时间我会专门写一篇 VSCode GCC 搭建 GD32 工程的方法。但作为系列的第一篇我坚持“最小阻力原则”用最成熟的工具先把流程跑通建立信心和数据基准。1.2 工具链详细清单与安装要点具体需要装哪些东西我按“必须”和“建议”两个层级整理了一份清单。工具用途版本建议安装要点Keil MDK (MDK-ARM)编译、下载、调试至少 5.27 以上建议 5.36安装路径不要带中文和空格以管理员身份运行安装GD32F1x0 固件库标准外设库驱动开发基础最新版即可解压到无中文路径GD32 器件支持包 (Pack)Keil 识别 GD32 芯片型号对应芯片系列双击 Pack 文件自动安装ST-Link / J-Link 驱动烧录器和调试器官方最新版确认系统设备管理器能看到调试器串口工具 (XCOM / SSCOM)串口打印与通信验证任意无特殊要求安装顺序上有个讲究先装 Keil再装 Pack 包最后插调试器装驱动。原因很简单Keil 是宿主环境Pack 是让 Keil 认识 GD32 芯片的“身份证”调试器驱动是让电脑和折腾器通信的桥梁一层层装上去逻辑比较顺。如果你顺序反了比如先插了调试器再装 Keil有时候会出现驱动识别异常还得手动更新驱动没必要给自己找这个麻烦。提示GD32F103 对应的是 GD32F1x0 系列 Pack。下载时认准官网或者直接通过 Keil 自带的 Pack Installer 搜索 GD32F1x0后者会省事很多不用自己去网页上找包。1.3 验证环境是否装好的“最小动作”装完这些东西怎么快速判断环境没问题不要急着建工程先做两步检查。第一步在 Keil 的 Pack Installer 里搜索“GD32F1x0”能看到器件包已经出现在“Installed”列表里这就说明 Keil 已经认识 GD32 芯片了。第二步插上调试器比如 ST-Link打开设备管理器在“端口”或者“通用串行总线设备”里能看到对应设备且没有黄色感叹号。这两步都过了环境就算基本就绪了。我见过太多人一上来就建工程编译报一堆错然后发现自己根本没装 Pack 包——这种基础错误浪费半小时起步。2. 搭建工程模板别从零写起用好官方例程打个底2.1 官方例程的正确“打开方式”新手最容易犯的错误是试图从零手写一个启动文件、链接脚本、系统时钟初始化然后把自己劝退了。说实话在 2024 年这个时间点工程模板最合理的来源就是官方固件库里的现成例程你要做的事是“基于官方例程改造”而不是“从零发明”。GD32F103 官方固件库的具体路径结构一般是每个外设一个例程文件夹比如GPIO、USART、Timer、ADC等。每个例程文件夹里通常已经包含建好的 Keil 工程.uvprojx。这里我推荐以GPIO下的跑马灯例程作为模板起点——它足够简单不涉及复杂外设初始化而且跑马灯本身就是嵌入式界的“Hello World”非常适合验证工具链和烧录链路。拿到例程之后你不需要马上改代码先干一件事找一个只有数字英文的路径比如D:\GD32_Project\01_LED把整个例程文件夹复制过去。这一步是为了避免后续编译时出现“中文路径/空格路径导致头文件包含失败”的诡异问题。我用 Keil 快十年了这种路径问题折磨过我不下五次。2.2 固件库关键文件结构与工程配置打开 Keil 工程后你会看到左边的 Project 窗口里有一堆分组通常包括这几类Startup启动文件核心是startup_gd32f10x_hd.s汇编写的负责初始化堆栈、中断向量表、调用SystemInit和main。CMSIS内核抽象层包含system_gd32f10x.c和core_cm3.h前者负责系统时钟初始化后者是 ARM 官方提供的 Cortex-M3 内核寄存器定义。Peripherals标准外设库源码gd32f10x_*.c这一堆是操作 GPIO、USART、Timer 等外设的 API 实现。User应用层代码main.c、gd32f10x_it.c中断服务函数、systick.c系统节拍很多例程都有。初次接触这个结构你只需要关心User分组里main.c的内容其他暂时可以当“黑盒”看待。这就像你开一辆车不需要懂发动机每个零件的原理先会点火和挂挡就行后面再慢慢补内部知识。编译前有两点要注意。第一点在 Options for Target 里确认一下 Target 页面选择的芯片型号确实是GD32F103C8T6或者其他你手上的型号选错了型号链接器会报芯片容量相关的错误。第二点C/C 页面里确认宏定义GD32F10X_HD或GD32F10X_MD与你的芯片匹配——大容量HD对应 256KB 以上 Flash中容量MD对应 64KB/128KB。这个宏会影响芯片内部外设的寄存器映射写错了程序跑起来会非常诡异比如 GPIO 乱跳或者根本不起振。2.3 改造例程从跑马灯到自己的“最小工程”官方例程能编译通过还不够我们得把它改造成有自己风格、适合自己的模板。改动的重点就两个一个是main.c里的逻辑另一个是去掉不需要的外设依赖。以最经典的“两个 LED 交替闪烁”为例我通常会把main.c精简成下面这个结构#include gd32f10x.h #include systick.h #define LED1_GPIO_PORT GPIOB #define LED1_GPIO_PIN GPIO_PIN_0 #define LED1_GPIO_CLK RCU_GPIOB #define LED2_GPIO_PORT GPIOB #define LED2_GPIO_PIN GPIO_PIN_1 #define LED2_GPIO_CLK RCU_GPIOB void led_config(void) { /* 使能 GPIO 时钟GD32 的外设时钟开关都在 RCU 模块里 */ rcu_periph_clock_enable(LED1_GPIO_CLK); rcu_periph_clock_enable(LED2_GPIO_CLK); /* 配置 GPIO 为推挽输出速度 50MHz */ gpio_init(LED1_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED1_GPIO_PIN); gpio_init(LED2_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED2_GPIO_PIN); /* 初始状态熄灭高电平熄灭取决于硬件接法 */ gpio_bit_set(LED1_GPIO_PORT, LED1_GPIO_PIN); gpio_bit_set(LED2_GPIO_PORT, LED2_GPIO_PIN); } int main(void) { /* 配置系统时钟为 108MHz这是 GD32F103 区别于 STM32F103 的一个重要点 */ system_clock_config(); /* 初始化 SysTick提供 delay_ms 延时 */ systick_config(); led_config(); while (1) { gpio_bit_reset(LED1_GPIO_PORT, LED1_GPIO_PIN); /* LED1 亮 */ gpio_bit_set(LED2_GPIO_PORT, LED2_GPIO_PIN); /* LED2 灭 */ delay_1ms(500); gpio_bit_set(LED1_GPIO_PORT, LED1_GPIO_PIN); /* LED1 灭 */ gpio_bit_reset(LED2_GPIO_PORT, LED2_GPIO_PIN); /* LED2 亮 */ delay_1ms(500); } }这段代码里有一个非常关键的 GD32 特色system_clock_config()会把系统时钟配置到 108MHz而 STM32F103 通常是 72MHz。这俩芯片虽然管脚兼容但时钟树的设计有差异GD32F103 的 GPIOM 系列和 GD32F103 后期的某些型号最高可以跑到 108MHz。这不是小事因为你如果直接拿 STM32 的时钟初始化代码来用定时器时序、串口波特率全部会算错表现就是通信乱码、延时不准。这一点建议大家务必记住。还有一个 GPIOM 的细节需要额外说明GD32 库函数里用的是gpio_init()一次性配置模式/速度/引脚而 STM32 标准库老写法是GPIO_InitStructure.GPIO_Mode ...; GPIO_Init(...)。GD32 的库把结构体方式简化成了函数参数方式很多 STM32 老手初次接触会有点不习惯多写两次就顺手了。2.4 工程模板的自检清单工程模板建好以后不要急着烧录先做一轮自检能过滤掉大半低级错误编译是否零错误零警告如果只有警告注意看一下警告内容有些是变量未使用之类的小问题但有些可能暗示配置错误。能否生成.hex或.axf文件Keil 默认输出 axf如果你要生成 hex需要在 Options for Target → Output 里勾选 “Create HEX File”这是烧录时经常用到的。.map文件里 Flash 和 RAM 的占用是否合理小工程一般 Flash 占用几 KB 到十几 KB如果出现几百 KB 的占用检查是不是选了错误的芯片型号。3. 烧写程序三条路都能走通但路线选择有讲究3.1 SWD/JTAG 调试器烧录方式这是我最推荐的一种方式也是日常开发效率最高的方式。无论你用 ST-Link、J-Link 还是 DAP-Link接线都很简单SWDIO、SWCLK、GND如果要给目标板供电就再加一根 3.3V然后插入调试器在 Keil 的 Options for Target → Debug 页面里选择对应的调试器CMSIS-DAP、ST-Link 或 J-Link。Keil 里烧录按钮就在工具栏上点一下LOAD按钮即可如果只想烧录不进入调试状态在 Flash Download 里配置好编程算法就行。这里有个小坑如果你的芯片是全新的、Flash 里是空的第一次烧录前要确认 Flash Download 页面里勾选了 “Erase Full Chip” 或 “Erase Sectors”否则可能报错。这个问题不算高频但遇到了会很耗时间提前做了免得临时摸索。另外提一句接线距离的问题SWD 模式虽然抗干扰能力强但连接线超过 20cm 还绕来绕去的时候尤其隔壁有电机、继电器这类大功率设备偶尔会出现烧录失败。解决办法是降低 SWD 通信速率或者在 Options for Target → Debug → Settings 里把 Max Clock 调低到 1MHz 以下。3.2 串口 ISP 方式没有调试器时的救场方案有时候手上只有一块裸板和一根 USB 转 TTL 串口线没有调试器怎么办GD32F103 出厂时 BOOT0 引脚拉高、BOOT1 引脚拉低再上电复位芯片就会进入系统存储器中的出厂 Bootloader可以通过串口接收程序并写入 Flash。这就是 ISPIn-System Programming模式。使用串口 ISP 时接线方式是USB 转 TTL 的 TXD 接芯片的 PA10USART0_RXRXD 接 PA9USART0_TXGND 接 GND。GD32 的 ISP 软件可以用官方的“GD32 MCU ISP Programmer”工具或者用 FlyMcu 这类通用 STM32 ISP 工具选择对应的串口选择要烧录的 hex 文件设置好波特率点击开始然后在目标板上进行上电复位烧录就会开始。这个方式适合“口袋里只有一个 USB 转 TTL”的应急场景但它的缺点也很明显每次烧录都要手动拨动 BOOT0 跳线帽、上电复位来回折腾很烦人而且速度慢几十 KB 的程序要传一阵子。所以它最佳的使用场景是产品出厂后需要通过串口升级固件或者在特殊情况下没有办法使用调试器的时候。日常开发我还是强烈建议配一个几十块钱的 DAP-Link。3.3 DFU 模式USB 直接烧录这个方式很多人不知道GD32F103 还有一个比较特殊的烧录通道USB DFUDevice Firmware Upgrade。如果你的板子上的芯片是一颗自带 USB 控制器且固件库里有 DFU Bootloader 的型号比如 GD32F103C8T6 的 USB 功能正常你可以让芯片运行一段 DFU 程序之后通过 USB 线直接在 PC 端升级用户程序。DFU 方式的好处是只要芯片里有一段可用的 DFU Bootloader你以后烧录就不用接调试器、不用拨 BOOT 引脚一根 USB 线搞定。缺点是芯片出厂时不一定预置 DFU Bootloader需要你自己先用 SWD 或者 ISP 方式把 DFU Bootloader 烧进去另外 DFU 传输速度一般适合小固件更新。对于入门阶段我不建议你花太多时间在 DFU 上。知道有这条路存在就行等后面做 USB 相关项目时再深入使用会顺理成章很多。3.4 烧录成功后的第一步验证跑马灯是你的“心跳”烧录完成之后如果你用的是 ST-Link/J-LinkKeil 会提示 “Flash Download: Programming Done”然后程序自动运行如果设置了 Reset and Run。这时观察你板子上的 LED如果按预期交替闪烁恭喜你整条链路算是打通了。但“LED 闪烁”只是第一步我当时做完以后还做了一件事打开串口助手配置波特率 115200看能不能收到USART0 Send Test之类的打印数据。为什么建议你做这一步因为 GPIO 控制只是验证了最基础的输出能力串口打印验证的是 MCU 的核心时钟频率设定和 USART 外设链路。如果串口数据正常说明系统时钟配置是对的后续你跑 LCD、跑传感器、跑通信都有了一个可靠的底层基准。4. 常见问题与排查技巧实录4.1 环境配置阶段的高频报错报错/现象根本原因处理方法“Error: Flash Download failed - Cortex-M3”调试器没接好或芯片型号选错检查 SWD 接线、确认 Target 芯片型号“No ULINK Device found”Keil 的 Debug 驱动选错切换到正确的 CMSIS-DAP/ST-Link 选项编译报错找不到gd32f10x.h头文件包含路径缺失Options → C/C → Include Paths 添加固件库路径烧录成功但程序不运行Reset and Run 未勾选或 BOOT0 引脚配置不对勾选 Reset and Run检查 BOOT0/BOOT1 电平串口输出乱码时钟频率配置错误或波特率不匹配确认系统时钟为 108MHz核对串口波特率设置这里面我最想展开的是第二个——“烧录成功但程序不运行”。这个现象特别坑因为它的特征不是编译失败、不是烧录失败而是 Keil 提示“一切正常”但板子上毫无反应。我记得有一次帮同事排查最后发现是板上 BOOT0 引脚被一个外部电路拉高了芯片每次复位都进入 Bootloader用户程序根本没机会执行。这种问题用万用表量一下 BOOT0 电平就能发现但新手往往想不到这一层。4.2 我在实际使用中踩过的几个坑按时间顺序把我在 GD32 入门阶段真正花过时间的问题列出来供大家避坑。第一个坑是器件包版本与 Keil 版本不兼容。早期 GD32 的 Pack 在 Keil 5.23 以下版本会报“Device not found”我当时用的是 Keil 5.20折腾了一下午最后升级到 5.36 就好了。这件事给我的教训是嵌入式开发中工具链版本一定要用较新的稳定版不要因为“能用就一直不升级”。第二个坑是系统时钟 108MHz 引发的延时问题。我当时从 STM32 迁移代码习惯性地把SystemInit()后系统时钟当 72MHz 用结果delay_ms全部偏到 1.4 倍左右LED 闪烁频率明显不对。最后检查系统时钟配置才找到原因。这件事让我意识到GD32 即使号称兼容 STM32时钟树配置也必须以官方代码为准不能想当然。第三个坑比较冷门是GPIO 引脚复用模式配置不全导致 I2C 通信失败。GD32 的 GPIO 初始化参数里有GPIO_MODE_AF_PP复用推挽输出这种模式STM32 里也有但 GD32 的库函数要求你在gpio_init()之前正确选择gpio_af_set()复用功能映射。我因为没配置这个I2C 引脚输出一直是高阻外设怎么都通信不上排查了大半天才发现是引脚复用配置漏了。如果你后面用到 USART、SPI、I2C 这类复用功能外设请务必检查复用映射函数。4.3 调试器连接不上的排查思路如果你插上调试器后 Keil 识别不到目标芯片先别急着怀疑芯片坏了按照下面的顺序排查用万用表量 VDD 和 GND确认目标板供电正常3.3V 左右。量 SWDIO 和 SWCLK 引脚对 GND 的电压——正常时 SWCLK 应该有上拉趋势SWDIO 同理。检查复位引脚 NRST 是否被拉低——有些板上复位电路异常会导致芯片一直处于复位状态调试器自然连接不上。如果接线没问题但仍连不上把调试器速率降到 100kHz 试试有些芯片在低电压或长线缆情况下高速通信不稳定。实在不行把 BOOT0 拉高复位一次再拉低复位一次让芯片脱离可能跑飞的程序状态再连接。这个排查顺序解决过我至少五次“连不上”的问题特别是第 4 步平时用 4MHz 没事换了根 30cm 杜邦线后就总断降速到 1MHz 立刻稳如老狗。4.4 给你一条“抄作业”的起飞路径最后给第一次接触 GD32 的朋友一个可执行的“起飞路径”按顺序走基本不踩坑用官方 GPIO 跑马灯例程建立工程确保编译通过。修改 LED 引脚为自己的板子对应引脚点亮一颗 LED。用串口例程做回环测试板上 TX/RX 短接或者连电脑打印一串字符。这时你已经有了一个“代码编译 烧录 调试 串口输出”的闭环。之后想做什么外设就从官方例程复制对应外设逐步叠加功能。很多人学单片机喜欢“一次学整个体系”买个开发板想把所有外设都过一遍。这个想法有动力是好的但不符合大脑的学习规律。我更推荐“最小闭环 逐步扩展”的路子第一次就跑通一个 LED获得掌控感第二次加一个传感器第三次开始自己改逻辑。每次跑通一个点心理上都是正向反馈这种节奏特别适合入门期。我这几年折腾嵌入式的一个核心体会是工具链和工程模板看似是“脏活累活”但这一层打磨好了后面的开发效率会成倍放大。很多人卡在入门阶段不是因为看不懂原理图、写不了代码而是被环境配置、工程搭建这些细碎的坑磨掉了耐心。希望这篇能帮你把“地基”打得快一点、稳一点。下一讲我准备写一写 GD32 的时钟树与系统时钟配置细节——这是整个芯片运行的“心跳”也是和 STM32 差异最大的地方之一。如果你在搭工程或者烧录时遇到了这篇里没提到的问题欢迎在下面留言我看情况把高频问题整理到后续文章里。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询