玩过 STM32 的朋友应该都体会过 CubeMX 的香选个芯片、拖几个引脚、配一下时钟树代码就自动生成了。但你手里如果换成了 GD32F103还能不能继续享受这种待遇答案是能而且比你想象的简单。GD32 官方早就为 CubeMX 发布了支持包装完之后在 CubeMX 里可以直接选 GD32F103生成的是 GD32 固件库风格的工程不是拿 STM32 的 HAL 硬套。这篇文章就用手把手的方式带你把 GD32F103 的点灯和串口一次调通工程结构和关键代码我尽量贴全适合刚从 STM32 转过来的人也适合第一次接触 GD32 的嵌入式新手。1. 动手之前必须搞懂的三个关键点1.1 GD32F103 和 STM32F103 到底是什么血缘关系先说结论GD32F103 是兆易创新基于 Cortex-M3 内核设计的国产 MCU引脚定义和 STM32F103 高度兼容很多核心板可以直接互换焊接。功能上两者也基本是“你有的我也有”比如 USART、SPI、I2C、定时器这些外设名字都差不多。但这不意味着你能直接把 STM32 的工程拿过来编译烧录就行因为内核虽然是同一个 ARM 内核但外设寄存器的地址映射、控制位定义、甚至固件库的函数接口都有差异。最典型的差异就是时钟模块。STM32 里面叫 RCC到了 GD32 变成 RCUSTM32 用 HAL 库GD32 有自己的一套标准外设库。如果你硬用 STM32 CubeMX 生成 HAL 库代码往 GD32 里烧十有八九是跑不起来的。所以正确做法是用 GD32 官方的 CMSIS 包、标准外设库和启动文件。好在 CubeMX 现在能直接生成这些内容省去了自己搭工程模板的时间。1.2 为什么推荐用 CubeMX 而不是手搓寄存器很多老工程师的习惯是“关闭 IDE 自动生成全部手写寄存器”这样对底层确实理解更深但对节奏快的项目来说太慢了。CubeMX 的价值在于三件事图形化配置引脚、可视化校验时钟树、自动生成初始化代码。尤其是引脚冲突检查它会在你配置的时候实时提示哪个引脚被占用了这在手写代码时很容易漏掉。对 GD32 来说用 CubeMX 还有一个额外好处芯片支持包是官方出的生成的主频、外设初始化、中断向量表都是经过验证的比自己在网上东拼西凑一份模板可靠得多。尤其对新手CubeMX 生成代码加几个业务逻辑就能跑能把精力花在理解外设原理上而不是浪费时间在“为什么编译不过”这种环境问题上。1.3 先记住一个坑GD32 的串口编号和 STM32 不一样很多人从 STM32 转过来会在这里懵掉。STM32F103 的串口叫 USART1、USART2、USART3而 GD32F103 的串口叫 USART0、USART1、USART2。也就是说GD32 的 USART0 对应 STM32 的 USART1GD32 的 USART1 对应 STM32 的 USART2后面依次类推。这个差异直接影响你在 CubeMX 里的选择。这篇博文里我用的是 GD32 的 USART0对应的引脚是 PA9TX和 PA10RX。如果你以前习惯用 STM32 的 USART1千万记得在 GD32 里要找的是 USART0别在配置界面里翻半天。2. 软硬件准备与 CubeMX 支持包安装2.1 硬件清单一块 GD32F103 核心板我这边用的是 GD32F103C8T6板载 8MHz 晶振。调试下载器ST-Link、J-Link、DAP-Link 都行只要支持 Cortex-M3 的 SWD 协议。实测下来 DAP-Link 兼容性最好ST-Link 新版固件也能正常识别 GD32。USB 转 TTL 模块主控用 CH340 的比较常见便宜好用。几根杜邦线用于连接串口和调试器。串口调试助手Windows 下用 XCOM、SSCOM 都可以我习惯用 XCOM界面干净。硬件上没太多讲究唯一要注意的是先确认板子上的 LED 和串口到底接在哪个引脚上。不同厂家的核心板布局不一样我手里这块板 LED 在 PA1串口是 PA9/PA10。如果你拿到的板子 LED 在 PC13把后面代码里的引脚号改一下就行原理完全一样。2.2 软件安装清单STM32CubeMX我用的是 6.x 版本版本太老可能看不到 GD32 的在线支持包。Keil MDK 5建议用较新的版本旧版本打开 GD32 工程时可能提示设备支持包缺失。CH340 驱动如果操作系统是 Windows 10 或 11通常插上就能识别但遇到识别异常时还是手动装一下稳妥。GD32F10x 系列的支持包这个分两处一处是给 CubeMX 用的芯片支持包另一处是给 Keil 用的 Device Pack。前者让 CubeMX 能生成 GD32 工程后者让 Keil 能编译下载 GD32 程序两个都要装。2.3 让 CubeMX 认识 GD32F103支持包安装实操打开 CubeMX 后菜单栏 Help - Manage embedded software packages进入软件包管理器。左侧供应商列表里如果有 GigaDevice直接点开选择对应系列在线安装装完后 New Project 的搜索框里就能搜到 GD32F103。如果左侧列表里找不到 GigaDevice说明你这个版本的 CubeMX 默认列表里没有需要去 GD 官网下载离线包然后回到这个界面点右下角的 From Local 按钮选择下载好的离线压缩包导入。导入成功后包管理器里能看到 GD32F10x 系列的条目。这里有个小细节CubeMX 里的 GD32 支持包版本和库版本是绑定的安装时尽量选最新的因为旧版本可能不支持某些新型号。安装过程中如果提示需要下载依赖网络不好会卡住此时建议直接下载离线包导入速度更快也更稳定。Keil 那边的 Device Pack 也要同步安装。打开 Keil 的 Pack Installer在 File 菜单里找到 Import from Local Directory把 GD32 的 Keil 支持包导入。导入之后新建工程或者打开 CubeMX 生成的工程时Device 选择框里就能看到 GigaDevice 分类下的 GD32F103 系列了。没有这一步CubeMX 生成的工程在 Keil 里会报“Device not found”错误。3. 用 CubeMX 创建 GD32F103 工程3.1 新建工程与芯片选型打开 CubeMX点击 New Project在芯片搜索框里输入 GD32F103C8T6。搜索结果出现后选中该型号双击进入配置界面。这里要留意一下封装预览确认引脚数量和你的板子一致。进入主界面后左侧是外设列表右侧是引脚布局图中间是时钟树。整个操作方式和 STM32 完全一样因为 CubeMX 的 UI 是统一的支持包只是提供了芯片的定义数据。如果你以前用过 CubeMX 配 STM32这里可以无缝上手。3.2 时钟树配置点开 Clock Configuration 标签页先确认 HSE 是外部晶振还是内部振荡器。GD32F103C8T6 核心板一般都会焊接外部 8MHz 晶振所以 HSE 选择 Crystal/Ceramic Resonator。然后在时钟树面板里把 SYSCLK 拉到 108MHz。GD32F103 的最高主频是 108MHz比 STM32F103 的 72MHz 高出一截。PLL 倍频系数会根据你输入的 HSE 频率自动计算。这里有个容易踩的坑如果你的板子晶振频率不是 8MHz比如是 25MHz就必须先在 HSE 输入框里改对否则时钟树计算出来的主频会完全错误后面串口必乱码。时钟树配好后CubeMX 会自动校验 PLL 参数是否在允许范围内。遇到校验报错时先回查 HSE 频率填没填对再检查倍频系数是否超范围。这一步没问题后主频配置就结束了。3.3 GPIO 和 USART0 配置先在引脚布局图里找到 PA1鼠标左键点击在弹出的菜单里选择 GPIO_Output这个引脚就配成了推挽输出用来驱动板载 LED。再找到 PA9 和 PA10。PA9 选择 USART0_TXPA10 选择 USART0_RX。这两个引脚是 USART0 的默认复用功能绝大多数 GD32F103 核心板都会把它们引出来当串口用。如果你用的是其它引脚映射需要在 GPIO 设置里改 AF 选项不过没必要默认映射是最省事的。选完引脚后在左侧外设树里点击 USART0配置参数ModeAsynchronous异步模式波特率115200数据位8停止位1校验位None然后在 NVIC Settings 选项卡里勾选 USART0 global interrupt。这一步必须做否则后面中断收发用不了。CubeMX 会自动生成外设初始化和中断相关代码。3.4 工程生成选项点击菜单栏 Project - Generate Code进入工程设置界面。Project Name 填个项目名比如GD32_LED_USART。Project Location 选一个路径注意路径里尽量不要带中文和空格避免 Keil 编译时出莫名其妙的问题。Toolchain/IDE 选择 MDK-ARM V5。Code Generator 选项卡里勾选“Generate peripheral initialization as a pair of .c/.h files per peripheral”这样每个外设的初始化代码会单独拆成文件阅读和修改都方便。生成完成后CubeMX 会弹出一个提示框点击 Open Project 直接打开 Keil 工程。打开后的工程目录大概长这样GD32_LED_USART/ ├── Core/ │ ├── Inc/ │ │ ├── main.h │ │ └── gd32f10x_it.h │ ├── Src/ │ │ ├── main.c │ │ ├── system_gd32f10x.c │ │ └── gd32f10x_it.c ├── Libraries/ │ ├── CMSIS/ │ └── GD32F10x_Firmware_Library/ ├── MDK-ARM/ │ ├── GD32_LED_USART.uvprojx │ └── ... └── .mxprojectCore 目录存放用户代码和中断函数Libraries 目录是 GD32 的标准外设库和 CMSIS 文件MDK-ARM 是 Keil 工程文件所在位置。整体结构和 STM32CubeMX 生成的工程如出一辙只不过底层库换成了 GD32 的。4. 点灯实操从初始化代码到 LED 翻转4.1 查看生成的 GPIO 初始化代码打开gpio_config.c如果你勾选了每个外设独立文件它会叫这个名字核心内容大概是这样的void gpio_config(void) { rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); gpio_bit_reset(GPIOA, GPIO_PIN_1); }这里就能看到 GD32 和 STM32 的第一个明显区别时钟使能函数从__HAL_RCC_GPIOA_CLK_ENABLE()变成了rcu_periph_clock_enable(RCU_GPIOA)常量名从RCC换成了RCU。函数名称虽然变了但逻辑完全一致都是先开外设时钟再配置引脚模式。关于 GPIO 的速度GD32 支持GPIO_OSPEED_50MHZ一般 LED、串口这种低速外设够用了。如果跑 SPI 或刷屏建议换成GPIO_OSPEED_MAX避免信号边沿过缓导致通信异常。这不是必须的但算是个小经验。4.2 主循环加入 LED 翻转逻辑CubeMX 生成的主函数里while(1)是空的。直接把翻转逻辑写进去while (1) { gpio_bit_write(GPIOA, GPIO_PIN_1, (bit_status)(1 - gpio_output_bit_get(GPIOA, GPIO_PIN_1))); delay_1ms(500); }gpio_output_bit_get用来读取当前引脚输出状态1 -取反然后写回去实现每隔 500ms 翻转一次。这里的delay_1ms是工程里自己在 SysTick 中断里实现的延时函数CubeMX 模板不会自动生成需要你补一段简单的延时代码或者用循环做个粗略延时。实测中 SysTick 延时要准一点循环延时受编译优化影响很大。如果你不想写 SysTick 延时也可以用 DWT 或者定时器延时但没必要复杂化SysTick 已经够用。注意bit_status这个类型是 GD32 固件库定义的枚举类型取值只有RESET和SET对应 0 和 1。这里用1 -的方式在两者之间切换简短但可读性不如显式判断新手看不懂的话可以改成if (gpio_output_bit_get(GPIOA, GPIO_PIN_1) RESET) { gpio_bit_set(GPIOA, GPIO_PIN_1); } else { gpio_bit_reset(GPIOA, GPIO_PIN_1); }效果完全一样。4.3 编译、下载、验证点灯编译前先在 Keil 的 Options for Target 里确认 Device 选择的是 GD32F103C8 系列然后到 Debug 选项卡选择你手里的调试器类型这里以 ST-Link 为例。点击 Download 按钮程序烧写成功后LED 应该开始以 0.5 秒的间隔闪烁。如果灯不亮先别急着怀疑代码按这个顺序排查确认板子上的 LED 引脚确实是 PA1查看原理图最直接。确认 LED 是高电平点亮还是低电平点亮。有些板子的 LED 电路设计是低电平亮你就需要把初始化里的复位改成置位再观察现象。确认下载时没有报 Flash 校验失败。GD32F103C8 的 Flash 标称是 64KB如果 Keil 里选的 Flash 大小不对会出现下载成功但程序运行异常的情况。遇到的话在 Utilities 选项卡里更新 Flash 算法或者手动选择匹配的 GD32F10x Flash 算法。这三个问题占了点灯失败案例的九成剩下的基本都是芯片没进入下载模式或者调试器连接不稳定。把调试器速度降低到 1MHz 再试往往能解决 SWD 不稳定的问题。5. 串口实操初始化、printf 重定向和中断回显5.1 看懂 USART0 初始化代码打开usart_config.cCubeMX 生成的初始化代码结构和 STM32 HAL 有很大差别但逻辑是熟悉的void usart_config(void) { rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_USART0); gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); usart_deinit(USART0); usart_baudrate_set(USART0, 115200U); usart_word_length_set(USART0, USART_WL_8BIT); usart_stop_bit_set(USART0, USART_STB_1BIT); usart_parity_config(USART0, USART_PM_NONE); usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE); usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE); usart_receive_config(USART0, USART_RECEIVE_ENABLE); usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); usart_enable(USART0); }注意 PA9 配置的是GPIO_MODE_AF_PP复用推挽输出PA10 配置的是GPIO_MODE_IN_FLOATING浮空输入。这是串口引脚的标准配置和 STM32 的 SPL 库写法几乎一样。USART0 的时钟使能用的是rcu_periph_clock_enable(RCU_USART0)这行不要漏掉漏掉之后串口是完全不工作的这是新手常犯的第一个错。波特率设置是usart_baudrate_set它能正确工作的前提是系统主频和外部时钟配置正确。如果你把 HSE 频率填错了或者 PLL 倍频算出来的主频不是 108MHz那么即使初始化代码看起来完全正确实际波特率也会偏串口就会乱码。参数配置里USART_WL_8BIT、USART_STB_1BIT、USART_PM_NONE分别对应 8 个数据位、1 个停止位、无校验这是串口调试最常用的配置上位机那边也要保持一致。5.2 实现 printf 重定向串口调通之后printf是调试效率最高的输出方式。嵌入式裸机上用 printf本质是把标准输出重定向到底层串口发送函数里。在 Keil 工程里先勾选 Use MicroLIB。MicroLIB 是精简版 C 库占用资源更小而且能省去很多标准库的初始化流程对嵌入式场景非常友好。然后在任意.c文件里加这两个函数int fputc(int ch, FILE *f) { usart_data_transmit(USART0, (uint8_t)ch); while (RESET usart_flag_get(USART0, USART_FLAG_TBE)); return ch; }usart_data_transmit往发送数据寄存器写一个字节usart_flag_get(USART0, USART_FLAG_TBE)检查发送数据寄存器是否为空。这里的 TBE 标志是 Transmit Buffer Empty寄存器空了才能写下一个字节否则会丢数据。这样在任意地方调用printf(hello\n)字符串就能从串口发出去。实测下来配合 XCOM 等串口助手在调试各种传感器参数、打印状态日志的时候非常直观。不过这里有个建议频繁使用 printf 输出浮点数时MicroLIB 的浮点打印比较消耗时间主频不高的情况下会拖慢主循环。最好把浮点数转成字符串或者缩小倍数后按整数打印或者干脆直接用自定义的格式化输出。这不是必须要做的但项目开发后期你会发现调试输出性能也很重要。5.3 中断方式实现串口回显推荐使用中断方式接收因为它不占用主循环时间。CubeMX 已经帮你在 NVIC 里开启了 USART0 中断所以只需要在gd32f10x_it.c文件里写中断服务函数。void USART0_IRQHandler(void) { if (SET usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) { uint8_t ch usart_data_receive(USART0); usart_data_transmit(USART0, ch); while (RESET usart_flag_get(USART0, USART_FLAG_TBE)); } }USART_INT_FLAG_RBNE是 GD32 对接收缓冲区非空标志的叫法对应 STM32 的 RXNE。进入中断后先用usart_data_receive把数据从接收寄存器读出来存到ch再原样发送回去。这个回显逻辑虽然简单但它验证了完整的串口收发链路上位机发数据芯片中断接收再原路返回。把这个逻辑吃透后面做 Modbus 协议、串口命令解析就有了基础。5.4 串口实测连接与验证用 USB 转 TTL 模块连接 GD32 核心板模块的 TX 接板子的 PA10RX模块的 RX 接板子的 PA9TX模块的 GND 接板子的 GND共地是必须的不接 GND 会导致串口数据完全不可靠这是一个极其常见的坑。接好后把模块插入电脑打开设备管理器确认 CH340 映射的 COM 口号。如果插上后系统没有识别到设备检查驱动是否安装或者换一根数据线试试。部分劣质 USB 线只有充电线芯没有数据线芯插上电脑毫无反应就是这个原因。打开 XCOM选择对应的 COM 口波特率设为 115200数据位 8停止位 1无校验。点击“打开串口”在发送区输入任意字符点击发送如果能收到相同的字符回显就说明串口收发链路完全打通。如果你在发送区输入内容后接收区乱码按这个顺序排查波特率参数是不是 115200上位机和芯片两端都要一致。芯片的时钟主频是否正确尤其是外部晶振频率和 CubeMX 时钟树里配置的是否一致。8MHz 晶振配错成 25MHz主频计算差了 3 倍串口必然全是乱码。检查 TX 和 RX 有没有接反。TX 要接对端的 RXRX 要对端的 TX接反时几乎不会出现乱码而是完全没反应。6. 完整工程结构说明与进阶方向6.1 工程目录整体说明CubeMX 生成的工程结构比较清晰实际使用时建议维持默认目录不变只在Core/Src和Core/Inc下添加自己的业务代码文件。这样做的原因是每次重新用 CubeMX 生成代码时它只管覆盖自己生成的文件用户新建的文件一般不会被动但如果你改了工程目录结构重新生成时可能出现路径错乱。我个人的习惯是把用户代码都放在Core/Src/user/下面比如user_led.c、user_uart.c这样即使 CubeMX 重新生成这些文件也不受影响。整份工程可以直接拷贝给任何人依赖关系都在工程文件里明明白白。6.2 串口之外的拓展方向串口调通后能做的事就非常多了。最常见的两个方向一是通过串口做 IAP 升级用 Bootloader 配合上位机软件刷写应用区程序二是做 Modbus RTU 从站让 GD32F103 接入工业控制网络。IAP 升级的原理是芯片上电先运行放在 Bootloader 区的程序通过串口接收上位机发来的固件写入应用区 Flash再跳转执行。对 GD32F103 来说关键是 Flash 擦写接口和中断向量表重映射这都是在串口基础上扩展出来的。Modbus 则侧重在串口数据的协议解析上需要把中断接收到的字节按照 Modbus 帧格式组装、校验 CRC16、解析功能码、构造响应帧。这两个方向都很适合拿调通的串口练手这也是我建议把串口吃透的原因——它是整个嵌入式调试体系中性价比最高的工具。回到工程本身我在这套 CubeMX GD32 的流程上反复跑过很多次遇到过各式各样的问题但大部分都能归结为时钟配置、引脚复用、调试器连接这三类。把这三块基础打牢后面无论是换芯片型号还是加外设都只是打开 CubeMX 改改配置、重新生成代码的事。希望这篇能帮你顺利迈过 GD32F103 入门的门槛少走一些我当时走过的弯路。
企业数字化 ERP 产品动态
相关推荐
【Dify】思维导图生成助手 结构化知识整理与信息梳理是自学编程过程中常见的高频需求。文本内容转为思维导图,不仅提升理解效率,也便于知识体系搭建和后续复习。
本文介绍一套基于Dify平台的思维导图生成助手,从对话采集、数据结构生成,到一键输出Markmap格式导图,完整覆盖从内容输入到可视化预览的… · 2026/9/24 14:01:47
【Dify】文本驱动的短视频生成与应用 AI文本生成视频技术正快速改变内容创作的方式。通过简洁的文字描述,即可自动生成多样风格的高质量短视频,为内容生产带来全新体验。
文生视频工作流集成了多种开源大模型,实现了从文字输入到视频输出的全自动处理流程。无需视频制作基础,仅需输入内容描述和参数配置,即可… · 2026/9/24 14:01:47
【Dify】实时热点新闻聚合每日简报应用 新闻信息量持续爆炸,热点聚合和高效推送已成为必需能力。自动化工具结合定制化流程,可让每日资讯采集、整理和分发变得极为高效。
本文介绍基于Dify的实时热点新闻聚合引擎,从多平台数据采集到内容聚合、邮件分发的完整自动化方案。聚焦技术实现,拆解关键节点,面向自学编… · 2026/9/24 14:01:47
Dopamine TensorboardCollector 源码级解析:训练指标如何写入 TensorBoard 机器学习深度学习 【免费下载链接】dopamine Dopamine is a research framework for fast prototyping of reinforcement learning algorithms. 项目地址: https://gitcode.com/gh_mirrors/do/dopamine 点击查看 免费下载 Dopamine 是 Google 推出的强化学习&… · 2026/9/24 14:32:10
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44