一:新建工程文件夹

  1. 新建一个工程文件夹,命名为:STM32_DEMO

  2. 打开工程目录,新建以下6个文件夹,其中Drivers分别新建Inc和Src文件夹,各文件夹用途如下:

    Project(存放Keil工程文件);
    
    Core(存放内核、启动文件);
    
    Drivers(存放标准库外设驱动);
    
    Drivers/Inc(存放外设头文件,在Drivers文件夹内新建Inc子文件夹);
    
    Drivers/Src(存放外设源文件,在Drivers文件夹内新建Src子文件夹);
    
    User(存放用户代码);
    
    System(存放自定义工具函数,暂空);
    
    Output(存放编译输出文件,暂空)。
  3. 新建完成后,总根目录仅显示6个文件夹,无任何零散文件,这是工程清爽的核心基础,如下:

二:从标准库复制必需文件

先解压标准库(这里用的是STM32F10x_StdPeriph_Lib_V3.5.0),找到对应路径,按以下步骤复制到我们新建的对应文件夹中,只复制必需文件,不多余复制

1. Core文件夹(内核+启动文件,必加,缺一不可)

标准库路径1:(内核库文件)

ST标准外设库\STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\CMSIS\CM3\CoreSupport

标准库路径2:(系统时钟文件)

ST标准外设库\STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x

标准库路径3:(启动文件)

ST标准外设库\STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm

复制路径1的core_cm3.ccore_cm3.h,路径2中的system_stm32f10x.csystem_stm32f10x.hstm32f10x.h以及路径3的startup_stm32f10x_md.s(我这里用的STM32F103C8T6是中等容量芯片,所以选择md版本,不同芯片按需选择)到工程的Core文件夹,最终如图所示:

2. Drivers文件夹(标准库外设驱动)

Drivers/Inc标准库路径:

ST标准外设库\STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\STM32F10x_StdPeriph_Driver\inc

Drivers/Src标准库路径:

ST标准外设库\STM32F10x_StdPeriph_Lib_V3.6.0\Libraries\STM32F10x_StdPeriph_Driver\src

分别复制对应文件夹的全部文件到Drivers文件夹的Inc/Src文件夹中,最终如图所示:

3. User文件夹(用户代码,必加,缺则报错)

从标准库的路径中,复制以下文件到User文件夹:

标准库路径:

ST标准外设库\STM32F10x_StdPeriph_Lib_V3.6.0\Project\STM32F10x_StdPeriph_Template

复制其中的main.c、stm32f10x_it.cstm32f10x_it.h以及stm32f10x_conf.h到工程的User文件夹中,最终结果如图:

4.System/Project和Output文件夹

暂时保持空文件夹即可:

System:后续可添加自己写的延时函数(delay.c/delay.h)、系统配置函数(sys.c/sys.h)等;

Output:编译时Keil会自动生成中间文件、.hex文件等,无需手动操作。

Project:后续新建工程存放地。

三:新建KEIL工程

这一步是避免工程杂乱的核心,严格按步骤操作,不要将工程文件放在根目录

1.打开Keil5 MDK-ARM,点击菜单栏Project → New μVision Project;

2.弹出保存工程窗口,路径选择总根目录下的Project文件夹,工程名命名为project,点击保存;

3.弹出Select Device for Target窗口,在搜索框输入STM32F103C8,找到STMicroelectronics → STM32F103C8,选中后点击OK。

4.弹出Run-Time Environment窗口(提示添加初始化代码),直接点击Cancel(不要自动添加,否则会生成冗余文件,打乱我们的规范结构)。

此时,Keil工程文件(.uvprojx、.uvoptx)会自动保存到Project文件夹,总根目录依然只有6个文件夹,极度清爽,如图:

四:配置工程分组&添加文件(只加.c,不加.h!)

1.点击Keil左侧Project面板中的Manage Project Items(三个小方块图标);

2.在弹出的窗口中,点击Groups下方的New,依次新建4个分组,与文件夹对应,如图:

3.向分组添加文件

选中某个分组,点击Add Files,找到对应工程文件夹下的.c文件添加,绝对不要添加.h文件!添加完成后如图所示:

五:工程关键配置

1. Target页:切换编译器

进入Target标签页,找到Code Generation选项,将编译器切换为ARM Compiler V5.06(标准库仅支持V5,用V6会报naked function错误)。

2.C/C++页:配置头文件路径&全局宏

1.进入C/C++标签页,找到Include Paths(头文件路径),点击右侧的「...」,添加以下4个路径(对应我们的文件夹,路径用「../」表示上一级目录):

  - ../Core(Core文件夹的头文件路径);
  - ../User(User文件夹的头文件路径);
  - ../Drivers/Inc(Drivers的头文件路径);
  - ../System(System文件夹的头文件路径)。

找到Preprocessor Symbols(全局宏定义),在Define框中输入以下内容(逗号分隔,无空格):

STM32F10X_MD,USE_STDPERIPH_DRIVER说明:
- STM32F10X_MD:指定STM32F103C8T6为中等容量芯片(MD=Medium Density);
- USE_STDPERIPH_DRIVER:启用标准库外设驱动,否则无法使用GPIO、RCC等外设函数。

最终效果如图所示:

3.Output页:配置编译输出路径(保持清爽)

进入Output标签页,勾选Create HEX File(必须勾选,否则编译后不会生成.hex文件,无法下载到芯片), 点击Select Folder for Objects,找到总根目录下的Output文件夹,选中后点击OK;
(可选)进入Listing标签页,同样将Select Folder for Listings选择为Output文件夹,让编译日志也统一归档。
配置完成后,所有编译产生的中间文件、.hex文件、日志文件都会自动保存到Output文件夹,根目录和Project文件夹不会出现任何编译产物,保持清爽。

4. 4.Debug页:配置下载器(解决下载报错)

进入Debug标签页,在Debugger下拉框中,选择你的下载器(ST-LINK选ST-Link Debugger,J-LINK选J-LINK / J-Trace Cortex)。


点击右侧的Settings,进入下载器配置窗口,点击Flash Download,勾选Reset and Run 。


进入Pack标签页,取消勾选Enable(关闭Keil对芯片型号的严格校验,进一步避免下载报错)。

六:点灯测试(验证工程是否搭建成功)

工程搭建完成后,用最简单的板载LED闪烁代码测试,确保编译、下载无报错,工程正常运行。

打开User文件夹下的main.c,删除原有内容,复制以下代码(适配STM32F103C8T6板载LED,引脚为PC13):

#include "stm32f10x.h"

// 简单延时函数(毫秒级)
void delay_ms(uint32_t ms)
{
    uint32_t i,j;
    for(i=ms; i>0; i--)
        for(j=7200; j>0; j--);
}

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStruct; // GPIO配置结构体

    // 1. 开启GPIOC时钟(使用外设前必须开启对应时钟)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    // 2. 配置PC13引脚(板载LED引脚)为推挽输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;    // 选择PC13引脚
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度50MHz
    GPIO_Init(GPIOC, &GPIO_InitStruct);       // 应用配置到GPIOC

    // 3. 循环让LED闪烁
    while(1)
    {
        GPIO_ResetBits(GPIOC, GPIO_Pin_13); // LED亮(PC13低电平)
        delay_ms(500);                      // 延时500ms
        GPIO_SetBits(GPIOC, GPIO_Pin_13);   // LED灭(PC13高电平)
        delay_ms(500);                      // 延时500ms
    }
}

点击编译下载程序到开发板上,开发板板载LED会循环闪烁(亮500ms、灭500ms),说明工程建立成功,完全正常。

七:高频报错

1. 报错:core_cm3.c: error: non-ASM statement in naked function is not supported

  • 原因:使用了ARM Compiler V6编译器,标准库不兼容;

  • 解决方案:Target页将编译器切换为V5编译器。

2. 报错:stm32f10x.h: error: 'stm32f10x_conf.h' file not found

  • 原因:未将stm32f10x_conf.h文件复制到User文件夹,或头文件路径配置错误;

  • 解决方案:将stm32f10x_conf.h复制到User文件夹,同时在C/C++页确认添加了「../User」路径。

3. 报错:Undefined symbol GPIO_Init / RCC_APB2PeriphClockCmd

  • 原因:未将对应的外设.c文件添加到Drivers分组(比如用了GPIO却没加stm32f10x_gpio.c);

  • 解决方案:在Drivers分组添加对应的.c文件(点灯必加stm32f10x_gpio.c、stm32f10x_rcc.c)。

4. 报错:Connection refused due to device mismatch!

  • 原因:芯片型号校验不通过,或工程芯片选择错误;

  • 解决方案:Debug页取消Verify Device ID,Pack页取消Enable勾选,同时确认工程芯片选择为STM32F103C8。

5. 问题:工程文件夹杂乱,根目录出现大量零散文件

  • 原因:Keil工程文件放在根目录,或编译输出路径未指定到Output文件夹;

  • 解决方案:将Keil工程文件移到Project文件夹,Output页将编译输出路径指定到Output文件夹。

八:工程模板使用技巧

新建项目时,直接复制STM32_DEMO总根目录,重命名为新项目名称,打开Project文件夹下的工程文件,修改工程名,根据项目需求,在Drivers分组添加对应的外设.c文件,修改User文件夹下的main.c,编写自己的代码,无需重新配置工程,直接编译下载即可。

最终工程文件夹目录如图:

九:写在后面

本文所有代码均在STM32F103C8T6上实测通过,可直接复制到 工程中使用,无需修改任何参数。

本博客仅记录自己的学习进程,无任何商业用途,基于论坛上已经存在的内容结合自己实操过程完成了此博客,自己也做了一些细节验证,在此记录下来作为学习沉淀。如有侵权,联系速删。

附:

STM32F10x_StdPeriph_Lib_V3.5.0 官方下载链接:https://www.st.com.cn/zh/embedded-software/stm32-standard-peripheral-library.html

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐