news 2026/2/26 23:36:31

Keil5工程创建实战案例:适用于STM32项目

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Keil5工程创建实战案例:适用于STM32项目

手把手教你从零搭建STM32开发环境:Keil5工程创建全解析

你有没有遇到过这样的场景?刚拿到一块STM32最小系统板,打开Keil5却不知道从哪下手——新建工程后一片空白,编译报错一堆“undefined symbol”,下载程序后单片机毫无反应……别急,这几乎是每个嵌入式新手都会踩的坑。

今天我们就以STM32F103C8T6(俗称“蓝丸”)为例,带你用Keil MDK-ARM 5(简称Keil5)从零开始,一步步搭建一个可运行、可调试、结构清晰的标准工程模板。整个过程不依赖STM32CubeMX,完全手动配置,让你真正理解每一个步骤背后的原理。


为什么你的Keil工程总是出问题?

在正式动手前,先搞清楚一个关键问题:为什么很多人照着教程做,最后还是失败?

根本原因在于——他们只是“复制操作”,而没有理解每个环节的作用。比如:
- 启动文件选错了会怎样?
- 宏定义没加会导致什么后果?
- 头文件路径漏了一条会发生什么?

这些问题的答案,藏在工具链的工作机制里。我们先快速扫一眼背后的技术支撑。

STM32是怎么启动的?

当你按下复位键,CPU做的第一件事不是执行main()函数,而是:

  1. 从Flash地址0x0800_0000开始读取初始堆栈指针(MSP)
  2. 跳转到复位向量(Reset Handler),进入汇编写的启动代码
  3. 执行SystemInit()初始化时钟
  4. 初始化.data.bss段(复制已初始化变量、清零未初始化变量)
  5. 最终调用C语言的main()

这个过程中,启动文件、CMSIS标准、HAL库初始化缺一不可。任何一个环节出错,程序就可能“卡住不动”。


第一步:创建工程 & 选择芯片

打开Keil μVision5,点击菜单栏:

Project → New uVision Project

弹出对话框,选择你的项目路径,建议组织为如下结构:

MyProject/ ├── Project/ ← 存放.uvprojx工程文件 ├── Src/ ← C源码 ├── Inc/ ← 头文件 ├── Core/ ← 内核相关(启动文件、system等) └── Drivers/ ← HAL库等驱动代码

输入工程名(如STM32_Minimal.uvprojx),保存后会跳转到“Select Device”界面。

搜索STM32F103C8,选择具体型号:
👉STMicroelectronics → STM32F103C8Tx

⚠️ 注意后缀含义:
-T表示LQFP48封装
-x中的8表示64KB Flash(不是128KB!)

选错型号可能导致链接脚本不匹配或外设定义错误。

确认后,Keil会自动加载该芯片的基本信息,包括内存布局、寄存器定义等。


第二步:引入CMSIS与启动文件(最关键一步)

接下来是决定工程能否跑起来的核心环节。

点击工具栏上的魔术棒图标(Options for Target),切换到“Manage Run-Time Environment” (RTE)标签页。

你会看到一个模块化配置窗口,这是Keil5的一大特色功能。

展开以下两项并勾选:

  • CMSIS → CORE
    包括内核寄存器访问头文件和基本运行支持
  • Device → Startup
    自动添加对应芯片的启动文件(这里是startup_stm32f103xb.s

📌 关键提示:
xb对应的是64KB Flash容量组(64~128KB),正好适用于C8T6。如果用了xc(128KB以上)可能会导致中断向量表偏移!

点击OK后,Keil会在左侧“Project”面板中自动生成两个Group:
-CMSIS
-Device

并且将startup_stm32f103xb.s添加进工程。

此时,编译一下试试?

你会发现仍然报错:“cannot open source input file ‘stm32f1xx.h’: No such file or directory”

别慌,这才刚开始。


第三步:添加必要源文件与目录结构

现在我们要把缺失的文件补全。这些文件可以从ST官网下载的HAL库包中获取,也可以直接从STM32CubeF1软件包提取。

我们需要添加以下几类文件:

1. 系统级文件(放入/Core目录)

文件来源作用
system_stm32f1xx.cSTM32Cube_FW_F1_V1.8.5\Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates实现SystemInit()函数,配置HSI/HSE、PLL等时钟源
stm32f1xx_it.c同上路径下的 Exceptions 模板放置所有中断服务函数(NMI_Handler, HardFault_Handler 等)

同时,在/Inc目录下添加对应的头文件:
-stm32f1xx_it.h
-main.h

2. HAL库文件(放入/Drivers/STM32F1xx_HAL_Driver

至少需要加入以下.c文件到工程:

stm32f1xx_hal.c stm32f1xx_hal_cortex.c stm32f1xx_hal_rcc.c stm32f1xx_hal_rcc_ex.c stm32f1xx_hal_gpio.c

🔍 小技巧:你可以只加入这些文件,而不必把整个HAL库都拖进来,节省空间且便于管理。

将这些文件分别归入名为 “HAL Library” 或 “Drivers”的Group中。


第四步:配置编译选项(让编译器认识你的代码)

再次打开“Options for Target”(魔术棒),进行关键设置。

【Target】选项卡

  • XTAL (MHz):设置为外部晶振频率,例如8.0
  • Operating:选择On-chip ROM & RAM(使用片上存储器)

Keil会根据所选芯片自动分配Flash(0x08000000起始)和SRAM。

【C/C++】选项卡

这是最容易出错的地方!

添加宏定义(Define)

在“Define”栏中输入:

USE_HAL_DRIVER,STM32F103xB

❗解释:
-USE_HAL_DRIVER:启用HAL库条件编译
-STM32F103xB:表示中等容量产品线(64KB Flash),必须与芯片匹配!

如果不加这两个宏,编译器就不会包含HAL相关的实现代码,导致大量“undefined”错误。

添加头文件路径(Include Paths)

点击右侧“…”按钮,添加以下路径:

.\Inc .\Core .\Drivers\CMSIS\Include .\Drivers\CMSIS\Device\ST\STM32F1xx\Include .\Drivers\STM32F1xx_HAL_Driver\Inc

确保每一级头文件都能被找到,尤其是stm32f1xx.hcore_cm3.h

【Output】选项卡

勾选:
- ✅ Create HEX File
生成可用于ISP烧录的HEX文件
- ✅ Create Debug Information
保留调试符号,方便后续调试

【Debug】选项卡

选择调试器类型,例如:
-Use: ST-Link Debugger

点击右侧“Settings”,进入调试设置:
- 在“Flash Download”页,勾选:
- ✅ Program
- ✅ Verify
(确保程序正确写入并校验)

还可以在这里选择是否“Reset and Run”,即下载完成后自动运行程序。


第五步:编写最简主程序验证工程

现在工程框架已经搭好,来写一段最简单的代码测试是否能正常工作。

main.c 示例代码

#include "main.h" // 假设LED连接在PA5(常见蓝丸板载LED) #define LED_PIN GPIO_PIN_5 #define LED_GPIO_PORT GPIOA void SystemClock_Config(void); int main(void) { // 初始化HAL库(必须第一步调用) HAL_Init(); // 配置系统时钟为主频72MHz(HSE=8MHz, PLL×9) SystemClock_Config(); // GPIO初始化 __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef gpio = {0}; gpio.Pin = LED_PIN; gpio.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出 gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_GPIO_PORT, &gpio); while (1) { HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_PIN); HAL_Delay(500); // 半秒闪烁一次 } }

main.h

#ifndef __MAIN_H #define __MAIN_H #include "stm32f1xx_hal.h" void SystemClock_Config(void); #endif

system_clock_config.c(可由CubeMX生成,也可手写)

这部分代码用于配置PLL倍频使主频达到72MHz,典型如下:

void SystemClock_Config(void) { RCC_OscInitTypeDef osc_init = {0}; RCC_ClkInitTypeDef clk_init = {0}; /** Initializes the RCC Oscillators */ osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE; osc_init.HSEState = RCC_HSE_ON; osc_init.HSIState = RCC_HSI_OFF; osc_init.PLL.PLLState = RCC_PLL_ON; osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE; osc_init.PLL.PLLMUL = RCC_PLL_MUL9; // 8MHz × 9 = 72MHz if (HAL_RCC_OscConfig(&osc_init) != HAL_OK) { while (1); } /** Initializes the CPU, AHB and APB buses clocks */ clk_init.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1; clk_init.APB1CLKDivider = RCC_HCLK_DIV2; clk_init.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&clk_init, FLASH_LATENCY_2) != HAL_OK) { while (1); } }

编译 & 下载:见证成果时刻!

点击顶部的“Build”按钮(小锤子图标),等待编译结果。

如果一切顺利,你会看到:

".\Output\STM32_Minimal.axf" - 0 Error(s), 0 Warning(s).

接着点击“Download”(向下箭头图标),Keil会通过ST-Link将程序烧录进MCU的Flash中。

如果你的板子上有LED,并且接线正确,应该能看到它开始以500ms周期闪烁!

🎉 恭喜你,第一个完整的Keil5工程成功运行!


常见问题排查清单

现象可能原因解决方案
编译时报undefined symbol未添加HAL源文件或宏未定义检查是否加入了stm32f1xx_hal.c并正确定义USE_HAL_DRIVER
程序无法下载SWD接线错误 / 调试器未识别检查VCC、GND、SWCLK、SWDIO是否连通;尝试更新ST-Link固件
LED不亮引脚配置错误或时钟未启用使用__HAL_RCC_GPIOx_CLK_ENABLE()启用对应GPIO时钟
HAL_Delay()不准未调用SystemClock_Config()确保在HAL_Init()后立即配置系统主频
程序跑飞启动文件与Flash大小不符更换为startup_stm32f103xb.s(非xc/zd版本)

工程结构最佳实践(团队协作推荐)

为了提升可维护性和移植性,建议采用以下目录规范:

Project/ ├── Project/ # Keil工程文件 │ └── STM32_Minimal.uvprojx ├── Src/ │ ├── main.c │ ├── system_clock_config.c │ └── stm32f1xx_it.c ├── Inc/ │ └── main.h ├── Core/ │ ├── startup_stm32f103xb.s │ └── system_stm32f1xx.c ├── Drivers/ │ └── STM32F1xx_HAL_Driver/ │ ├── Inc/ │ └── Src/ └── Output/ ├── Objects/ └── Lists/

💡 提示:将.uvoptx.uvgui文件加入.gitignore,避免提交个人调试配置。


总结:掌握本质,才能灵活应对

通过本次实战,你应该已经明白:

  • Keil5工程的本质是一组配置 + 一组源文件的集合;
  • CMSIS启动文件决定了程序如何开始;
  • 宏定义和头文件路径是编译成功的钥匙;
  • HAL库初始化顺序必须严格遵守;
  • 合理的工程结构是长期维护的基础。

这套流程不仅适用于F1系列,稍作修改即可用于F4、G0、L4等其他STM32平台。

下次当你再问“keil5怎么创建新工程”时,希望你能自信地说:我知道每一步背后发生了什么。

如果你正在准备嵌入式面试,或者想建立自己的通用模板,不妨把这篇文章对应的工程打包存档,未来直接复用,效率翻倍。

如果你在搭建过程中遇到了其他问题,欢迎在评论区留言讨论,我们一起解决实际工程难题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/26 13:37:50

Conda环境导出为yml文件供TensorFlow团队共享

Conda环境导出为yml文件供TensorFlow团队共享 在深度学习项目中,最让人头疼的往往不是模型调参,而是“为什么我的代码在你机器上跑不通”。这种看似低级的问题,实则暴露了现代AI开发中的核心痛点——环境不一致。尤其是在使用像 TensorFlow 这…

作者头像 李华
网站建设 2026/2/26 23:00:58

AtCoder Beginner Contest竞赛题解 | 洛谷 AT_abc438_a First Contest of the Year

​欢迎大家订阅我的专栏:算法题解:C与Python实现! 本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战! 专栏特色 1.经典算法练习:根据信息学竞赛大纲,精心挑选…

作者头像 李华
网站建设 2026/2/24 17:53:15

基于GPU算力售卖的TensorFlow-v2.9镜像优化策略

基于GPU算力售卖的TensorFlow-v2.9镜像优化策略 在AI研发日益“平民化”的今天,越来越多开发者通过云平台按需租用GPU资源进行模型训练。但一个现实问题随之而来:即便手握A100实例,也可能因为环境配置不当导致GPU利用率不足30%,甚…

作者头像 李华
网站建设 2026/2/26 9:28:45

Phoenix监控平台:5步快速搭建企业级监控系统

Phoenix监控平台:5步快速搭建企业级监控系统 【免费下载链接】phoenix “phoenix”是一个灵活可配置的开源监控平台,主要用于监控应用程序、服务器、网络设备、docker、数据库、网络、tcp端口和http接口,在发现异常时实时推送告警信息&#x…

作者头像 李华
网站建设 2026/2/25 23:50:17

为什么tRPC-Go成为微服务架构的首选RPC框架?

为什么tRPC-Go成为微服务架构的首选RPC框架? 【免费下载链接】trpc-go A pluggable, high-performance RPC framework written in golang 项目地址: https://gitcode.com/gh_mirrors/tr/trpc-go 在当今云原生时代,构建高性能、可扩展的微服务系统…

作者头像 李华