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

再次编译:

相关推荐
顾辰呀7 分钟前
css 文字一行没有放满不进行换行
前端·javascript·css·vue.js·css3
q567315239 分钟前
Python 中的字符串匹配算法
android·java·javascript·python·算法
nixiaoge33 分钟前
Web前端第二次作业
前端·javascript·css3
安冬的码畜日常37 分钟前
【玩转 Postman 接口测试与开发2_005】第六章:Postman 测试脚本的创建(上)
javascript·测试工具·单元测试·postman·bdd·chai
Gavin_9151 小时前
【JavaScript】数组-集合-Map-对象-Class用法一览
开发语言·前端·javascript
琴~~2 小时前
前端根据后端返回的文本流逐个展示文本内容
前端·javascript·vue
zhaocarbon2 小时前
el-scrollbar 动态更新内容 鼠标滚轮无效
前端·javascript·vue.js
一纸忘忧2 小时前
Nuxt 3.14 发布!全新功能与性能提升
前端·javascript·vue.js
少年姜太公2 小时前
【ES6】让你彻底搞懂const ,let和var的区别
javascript
Whappy0013 小时前
6. STM32之TIM实验--编码器接口()--(实验5:PWM驱动直流电机)
stm32·单片机·嵌入式硬件