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分组,添加到已存在分组

再次编译:

相关推荐
时光の尘30 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
前端拾光者1 小时前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
木子02042 小时前
前端VUE项目启动方式
前端·javascript·vue.js
endingCode2 小时前
45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
javascript·macos·typescript
嵌入式大圣2 小时前
单片机结合OpenCV
单片机·嵌入式硬件·opencv
Myli_ing3 小时前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
I_Am_Me_3 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
℘团子এ4 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
日晨难再4 小时前
嵌入式:STM32的启动(Startup)文件解析
stm32·单片机·嵌入式硬件
学习前端的小z4 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript