2. STM32 HAL库MDK工程模板创建

工程结构参考引用自正点原子

1. 新建工程文件夹

新建一个工程目录,在里边创建一下子目录

2. 目录说明

文件夹 说明
Drivers 存放与硬件相关的驱动层文件
Middlewares 存放中间层文件
Output 存放工程编译输出文件
Projects 存放 MDK工程文件
User 存放 HAL库用户配置文件、main.c、中断处理文件,以及分散加载文件

2.1 Drivers文件夹

文件夹 作用
BSP 存放开发板板级支持包驱动代码,如各种外设驱动
CMSIS 存放 CMSIS 底层代码,如启动文件(.s 文件)等
SYSTEM 存放系统级核心驱动代码,如 sys.c、delay.c 和 usart.c 等
STM32F1xx_HAL_Driver 存放 ST 提供的 F1 系列 HAL 库驱动源码

2.2 Middlewares文件夹

这个文件夹主要存放的是中间层代码(组件/Lib 等),比如:FATFS、USB、LWIP、FreeRTOS,各种 GUI 等等。但作为模板工程,文件夹暂时空置即可。

2.3 Output文件夹

该文件夹用于存放编译器编译工程输出的中间文件,比如:.hex、.bin、.o 文件等。

2.4 Projects文件夹

该文件夹用于存放编译器(MDK、 IAR 等)工程文件,我们主要用 MDK,为了方便区分,在该文件夹下新建: MDK-ARM 文件夹,用于存放 MDK 的工程文件。

2.5 User文件夹

该文件夹用于存放用户编写的代码,如:HAL 库用户配置文件、main.c 文件、中断处理文件,以及分散加载文件等。

3. 工程框架配置

3.1 新建工程

打开keil, 新建工程

3.2 选择芯片

需要提前安装对应的固件包,可以参考:https://blog.csdn.net/qq_51355375/article/details/143273553

本模板使用的时stm32f103c8t6,选择如下, 选定后点ok

跳过即可

3.3 删除文件夹

因为定义了Output文件夹用于存放编译器编译工程输出的中间文件, 所以删除Listings和Objects两个文件夹

4. 添加文件

4.1 复制HAL 库驱动代码

使用stm32CubeMX 下载固件包

选择需要的版本, 这里选历史版本1.8

等待下载完成后,查看下载目录

去对应的目录下找对应固件驱动包

复制STM32Cube_FW_F1_V1.8.0\Drivers\STM32F1xx_HAL_Driver下的Inc和Src目录到我们自己的Drivers\STM32F1xx_HAL_Driver下

4.2 HAL 库用户配置文件和中断处理文件到我们的 User 文件夹

从官方STM32Cube_FW_F1_V1.8.0\Projects\STM3210E_EVAL\Templates 下的Inc 和 Src 文件夹里面,在这两个文件夹里面找到:stm32f4xx_it.c、stm32f4xx_it.h、stm32f4xx_hal_conf.h 这三个文件,并且拷贝到我们的 User 文件夹下。

4.3 设置工程名和分组名

在 Project→Target 上右键,选择 Manage Project Items...进入工程管理界面

设置工程名字为:Template,并设置四个分组:

Startup(存放启动文件)、User(存放 main.c 等用户代码)、Drivers/SYSTEM(存放系统级驱

动代码)Driver/STM32F1xx_HAL_Driver(存放 HAL 库代码)、Readme(存放工程说明文件),

设置好之后,我们点击 OK,回到 MDK 主界面,可以看到我们设置的工程名和分组名如图

这里我们只是新建了一个简单的工程,并没有添加 BSP、Middlewares 等分组,后面随着工

程复杂程度的增加,我们需要一步步添加对应的分组。为了让工程结构清晰,尽量让 MDK 的工程分组和我们前面新建的工程文件夹对应起来,由于 MDK 分组不支持多级目录,因此我们将路径也带入分组命名里面,以便区分。如:User 分组对应 User 文件夹里面的源码,Drivers/SYSTEM 分组,对应 Drivers/SYSTEM文件夹里面的源码,Drivers/BSP 分组对应 Drivers/BSP 文件夹里面的源码等。

4.4 添加启动文件

复制CMSIS 文件夹

复制上边cubeMx下载的官方包里STM32Cube_FW_F1_V1.8.0\Drivers下的CMSIS 文件夹 下的所有内容到我们自己的工程模板下的Drivers\CMSIS文件夹

由于固件包里面的 CMISIS 兼容了太多芯片,导致非常大, 需要根据实际情况,对其进行了大幅精简

,最简单做法是只保留Device和Include目录,也可以不精简

右键打开项目管理

在刚才添加的\Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates\arm目录下找到对应的启动文件。

点Add 后如下则添加成功

点击ok后工程目录变化

4.5 添加 SYSTEM 源码

这里使用的文件直接是复制原子的工程中的

同样操作如上,添加三个目录下的源文件到SYSTEM分组即可

4.6 添加USER分组

同样操作如上,将Users目录下的源文件到Users分组即可

4.7 添加驱动添加驱动文件

同样如上操作,将Drivers\STM32F1xx_HAL_Driver\Src 目录下的文件添加到对应分组,可以添加全部或者只添加对应的。

5. 魔术棒设置

5...1 Target选项卡

5.2 Output

5.3 Listing选项卡

经过 Output 和 Listing 这两步设置,原来存储在 Objects 和 Listings 文件夹的内容(中间文

件)就都改为输出到 Output 文件夹

5.4 C/C++选项卡

下图 define 中间定义用英文逗号分隔

引用原子的相对路径解释:

上图中我们设置了 6 个头文件包含路径,其中 3 个在 Drivers 文件夹下,一个在 User 文件
夹下,一个在 Middlewares 文件夹下。为避免频繁设置头文件包含路径,正点原子最新源码的
include 全部使用相对路径,也就是我们只需要在头文件包含路径里面指定一个文件夹,那么该
文件夹下的其他文件夹里面的源码,如果全部是使用相对路径,则无需再设置头文件包含路径
了,直接在 include 里面就指明了头文件所在。
关于相对路径,这里大家记住 3 点:
1,默认路径就是指 MDK 工程所在的路径,即.uvprojx 文件所在路径(文件夹)
2,"./"表示当前目录(相对当前路径,也可以写做".\")
3,"../"表示当前目录的上一层目录(也可以写做"..\")

再举个例子,在完成上图所示的头文件包含路径设置以后,我们在代码里面编写:
#include "./SYSTEM/sys/sys.h"
即表示当前头文件包含路径所指示的 4 个文件夹里面,肯定有某一个文件夹包含了:
SYSTEM/sys/sys.h 的路径,实际上就是在 Drivers 文件夹下面,两者结合起来就相当于:
#include "../../Drivers/SYSTEM/sys/sys.h"
这就是相对路径。它既可以减少头文件包含路径设置(即减少 MDK 配置步骤,免去频繁
设置头文件包含路径的麻烦),同时又可以很方便的知道头文件具体在那个文件夹,因此我们推
荐在编写代码的时候使用相对路径。

5.5 设置 Debug 选项卡

5.6 设置 Utilities 选项卡

6. 添加 main.c,并编写代码

在 MDK 主界面,右键选择Users分组, 添加新项目到分组

点Add添加后,打开项目管理发现main.c也已经新建并加入了分组

编写测试代码:

#include "SYSTEM/sys/sys.h"
#include "SYSTEM/uart1/uart1.h"
#include "SYSTEM/delay/delay.h"

#define LED_CLK()       __HAL_RCC_GPIOB_CLK_ENABLE()
#define LED_GPIO        GPIOB
#define LED_PIN         GPIO_PIN_8


void led_init(void);                       /* LED初始化函数声明 */

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    printf("running...\r\n");
    while(1)
    { 
        HAL_GPIO_WritePin(LED_GPIO,LED_PIN,GPIO_PIN_SET);
        delay_ms(500);
        HAL_GPIO_WritePin(LED_GPIO,LED_PIN,GPIO_PIN_RESET);
        delay_ms(500); 
    }
}

/**
 * @brief       初始化LED相关IO口, 并使能时钟
 * @param       无
 * @retval      无
 */
void led_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    LED_CLK();                                             /* IO口时钟使能 */

    gpio_initstruct.Pin = LED_PIN;                         /* LED0引脚 */
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    gpio_initstruct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    HAL_GPIO_Init(LED_GPIO, &gpio_initstruct);             /* 初始化LED0引脚 */
}

注意: 这里要注意头文件的引入方式

修改代码:

编译下载验证:

出现错误

移除这三个

报错:

需要将: Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates 下的 system_stm32f1xx.c 添加到Users分组下, 右键Users分组,添加到已存在分组

再次编译:

相关推荐
燃先生._.23 分钟前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
析木不会编程2 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
black^sugar2 小时前
纯前端实现更新检测
开发语言·前端·javascript
2401_857600954 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600954 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL4 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据4 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
2402_857583494 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js