
新建HAL版本MDK工程: Q1 M- }* g2 ~, \ 在前面的章节我们介绍了STM32H7xx官方固件包的一些知识,本章我们将讲解新建HAL库版本的MDK工程的详细步骤。我们把本章新建好的工程放在光盘里,路径:4,程序源码\2,标准例程-HAL库版本\实验0 基础入门实验\实验0-3,新建工程实验-HAL库版本,大家在学习新建工程过程中间遇到一些问题,可以直接打开这个工程,然后对比学习。 0 _# c9 q( T+ j 8.1 新建HAL库版本MDK工程 本节我们将教大家如何新建一个STM32H750的HAL库版本MDK5工程。为了方便大家参考,我们将本节最终新建好的工程模板存放在A盘:4、程序源码\2,标准例程-HAL库版本\实验0 基础入门实验\实验0-3,新建工程实验-HAL库版本,如遇新建工程问题,请打开该实验对比。 整个新建过程比较复杂,我们将其拆分为5个步骤进行讲解,请准备大概2个小时时间,耐心细致的做完!对你后续的学习非常有帮助!# B/ P! H2 p9 s( [, y0 m4 S$ a 在新建工程之前,首先我们要做如下准备: 1、 STM32Cube官方固件包:我们使用的固件包版本是STM32Cube_FW_H7_V1.6.0,固件包路径:A盘8,STM32参考资料1,STM32CubeH7固件包。 2、开发环境搭建:参考本书第三章相关内容。 8.1.1 新建工程文件夹1 U) U7 A$ H- Y# ^0 m* |: ` 新建工程文件夹分为2个步骤:1,新建工程文件夹;2,拷贝工程相关文件。 1.新建工程文件夹6 u9 |# G' I. _( K7 r8 n! |" e( G2 F- p 首先我们在桌面新建一个工程根目录文件夹,后续的工程文件都将在这个文件夹里建立,我们把这个文件夹重命名为:实验0-3,新建工程实验-HAL库版本。如图8.1.1.1所示:2 @2 A( y+ g' s- u! a ![]() 图8.1.1.1 新建工程根目录文件夹; R) u/ w8 a; P* o4 L 为了让工程的文件目录结构更加清晰易懂,我们会在工程根目录文件夹下建立以下几个文件夹,每个文件夹名称及其作用如表8.1.1.1所示:8 z. s& l# V) F1 ]& W& z r& n7 x/ M1 i2 W ![]() : H$ P7 d9 |% `; L! r3 K4 E, t' G 表8.1.1.1 工程根目录新建文件夹及其作用 新建完成以后,最后得到我们的工程根目录文件夹如图8.1.1.2所示。 6 V" D7 }; @8 s* E- I ![]() 图8.1.1.2 工程根目录文件夹& n5 D: R* }# X 另外我们的工程根文件目录下还有一个名为keilkill.bat的可执行文件,双击便可执行。其作用是删除编译器编译后的无关文件,减少工程占用的内存,方便打包。还有一个名为readme的记事本文件,其作用是介绍本实验的各种信息。 工程根目录及其相关文件夹新建好以后,我们需要拷贝一些工程相关文件过来(主要是在Drivers文件夹里面),以便等下的新建工程需要。 2. 拷贝工程相关文件+ N. A$ V, ^7 y4 l3 |9 v/ r0 c2 _* }: @ 接下来,我们按图8.1.1.2的根目录文件夹顺序介绍每个文件夹及其需要拷贝的文件。; e6 e$ z' f6 \# U8 }3 G Drivers文件夹- A. i" a' I# ]! H 该文件夹用于存放与硬件相关的驱动层文件,一般包括如表8.1.1.2所示的三个文件夹:, U; Z3 o! G+ w8 {2 u, ~# f2 c4 d. @ ![]() 表8.1.1.2 Drivers包含文件夹& g# e$ v9 @$ a; G& G9 U+ S& v i BSP文件夹,用于存放正点原子提供的板级支持包驱动代码,如:LED、蜂鸣器、按键等。本章我们暂时用不到该文件夹,不过可以先建好备用。, q& y" Q' m) O( @ CMSIS文件夹,用于存放CMSIS底层代码(ARM和ST提供),如:启动文件(.s文件)、stm32h7xx.h等各种头文件。该文件夹我们可以直接从STM32CubeH7固件包(路径:A盘8,STM32参考资料1,STM32CubeH7固件包)里面拷贝,不过由于固件包里面的CMISIS兼容了太多芯片,导致非常大(300多MB),因此我们根据实际情况,对其进行了大幅精简,精简后的CMSIS文件夹大小为2.3MB左右。精简后的CMSIS文件夹大家可以在:A盘4,程序源码1,标准例程-HAL库版本 文件夹里面的任何一个实验的Drivers文件夹里面拷贝过来。* J$ {2 C& Q% J' F9 ]* u# {4 X/ U9 c9 L SYSTEM文件夹,用于存放正点原子提供的系统级核心驱动代码,如:sys.c、delay.c和usart.c等,方便大家快速搭建自己的工程。该文件同样可以从:A盘4,程序源码1,标准例程-HAL库版本 文件夹里面的任何一个实验的Drivers文件夹里面拷贝过来。 STM32H7xx_HAL_Driver文件夹,用于存放ST提供的H7xx HAL库驱动代码。该文件夹我们可以直接从STM32CubeH7固件包里面拷贝。直接拷贝“STM32CubeH7固件包Drivers”路径下的“STM32H7xx_HAL_Driver”文件夹到我们工程的Drivers下,只保留Inc和Src文件夹即可。 执行完以上操作后,Drivers文件夹最终结构如图8.1.1.3所示:. g$ J$ l1 w. k( y; |. ^" N ![]() 图8.1.1.3 工程根目录下的Drivers文件夹4 h( [0 @% K6 c; h" k 关于工程根目录下的Drivers文件操作到这里就完成了,可以说步骤是有点多。在此过程遇到问题的话,请大家多参考我们提供的实验0-3,新建工程实验-HAL库版本工程,一步步操作。 Middlewares文件夹 该文件夹用于存放正点原子和其他第三方提供的中间层代码(组件/Lib等),如:USMART、MALLOC、TEXT、FATFS、USB、LWIP、各种OS、各种GUI等等。本章我们暂时用不到该文件夹,不过可以先建好备用,后面的实验将会陆续添加各种文件。7 u! l' a9 D- Q1 m Output文件夹, @" s$ M5 W$ ?+ Y 该文件夹用于存放编译器编译工程输出的中间文件,比如:.hex、.bin、.o文件等等。这里不需要操作,后面只需要在MDK里面设置该文件夹为编译过程中间文件的存放文件夹就行。 Projects文件夹 该文件夹用于存放编译器(MDK、IAR等)工程文件,我们主要用MDK,为了方便区分,我们在该文件夹下新建:MDK-ARM文件夹,用于存放MDK的工程文件,如图8.1.1.4所示: 2 d$ W6 _, q5 z' ?0 p- B/ n1 s, _ ![]() ' f/ V8 s* I z/ d2 Y" V 图8.1.1.4 在Projects文件夹下新建MDK-ARM文件夹 User文件夹* `' f) u1 o3 @: F. y8 k User文件夹用于存放HAL库用户配置文件、main.c文件、中断处理文件,以及分散加载文件。# Y% f ~. `0 S3 |" l# k$ [ 我们首先从官方固件包里面直接拷贝官方的模板工程下的HAL库用户配置文件和中断处理文件到我们的User文件夹里。官方的模板工程路径:STM32Cube_FW_H7_V1.6.0\Projects\ STM32H750B-DK\Templates\Template_Project,打开Template_Project文件夹,如图8.1.1.8所示。 ![]() - s Z3 [* z6 \6 k. H 图8.1.1.8 官方模板工程根目录 我们需要的文件就在Inc和Src文件夹里面,在这两个文件夹里面找到:stm32h7xx_it.c、stm32h7xx_it.h、stm32h7xx_hal_conf.h这三个文件,并且拷贝到我们的User文件夹下。! q; Z- ?/ `6 j0 E( j% s& V 最后在User文件夹下新建一个命名为SCRIPT的文件夹,用于存放分散加载文件。分散加载文件直接在我们的实验0-2,新建工程实验-HAL库版本工程对应位置拷贝过来,后面再给大家讲解。main.c文件我们也是放在User文件夹里面的,后面在MDK里面教大家新建.c文件并保存。, U4 o7 T$ }# p E1 k: d# o 8.1.2 新建一个工程框架. ]' G- z. U, q; j5 _" q) D* ? 首先,打开MDK软件。然后点击ProjectNew uVision Project如图8.1.2.1所示:4 T8 A+ |- \* q# j ![]() ; v" x/ O7 b1 y0 Z: ? 图8.1.2.1 新建MDK工程5 S+ s" i! i! | 然后弹出工程命名和保存的操作窗口,我们将工程文件保存路径设置在上一节新建的工程文件夹内,具体路径为:桌面实验0-2,新建工程实验-寄存器版本ProjectsMDK-ARM,工程名字我们取:atk_h750,最后点击保存即可。具体操作窗口如图8.1.2.2所示:: J- `5 N& [, B+ ^1 {4 f) V ![]() 图8.1.2.2 保存工程界面 之后,弹出器件选择对话框,如图8.1.2.3所示。因为MiniPRO STM32H750开发板所使用的STM32型号为STM32H750VBT6,所以我们选择:STMicroelectronicsSTM32H7 SeriesSTM32H750STM32H750VBTx(如果使用的是其他系列的芯片,选择相应的型号就可以了,特别注意:一定要安装对应的器件pack才会显示这些内容哦!!如果没得选择,请关闭MDK,然后安装 A盘:6,软件资料\1,软件\MDK5\ Keil.STM32H7xx_DFP.2.5.0.pack这个安装包后重试)。 ; e; |+ t- B, M ![]() 图8.1.2.3 器件选择界面 点击OK,MDK会弹出Manage Run-Time Environment对话框,如图8.1.2.4所示:! |/ L/ w* q5 X) M" q* ` ![]() 图8.2.1.4 Manage Run-Time Environment界面 这是MDK5新增的一个功能,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们不做介绍。所以在图8.1.2.4所示界面,我们直接点击Cancel,即可,得到如图8.1.2.5所示界面:' t, W/ d" D T( \ ![]() 图8.1.2.5 工程初步建立 此时,我们打开MDK-ARM文件夹,会看到MDK在该文件夹下自动创建了3个文件夹(DebugConfig、Listings和Objects),如图8.1.2.6所示:- Y4 e( t8 u9 J2 N: p ![]() - ~1 `/ [) T% c& J2 f2 v4 h 图8.1.2.6 MDK新建工程时自动创建的文件夹* f0 j4 ]5 L' n; l- h; g 这三个文件夹的作用如表8.1.2.1所示: ![]() + ^: L3 }& g& [; F 表8.1.2.1 三个文件夹及其作用 编译过程产生的链接列表、调试信息、预览、lib等文件,统称为中间文件。为了统一管理,方便使用,我们会把输出在Listings和Objects文件夹的内容,统一改为输出到Output文件夹(通过魔术棒设置),我们先把MDK自动生成的这两个文件夹(Listings和Objects)删除。7 Z8 \* N6 h2 j, Y3 g* F 至此,我们还只是建了一个框架,还有好几个步骤要做,比如添加文件、魔术棒设置、编写main.c等。- t7 @7 s9 \; P 8.1.3 添加文件 本节将分5个步骤:1,设置工程名和分组名;2,添加启动文件;3,添加SYSTEM源码4,添加 User 源码;5,添加 STM32H7xx_HAL_Driver 源码。1 @& t. p, z- u# l% K 1.设置工程名和分组名 在ProjectTarget上右键,选择Manage Project Items…(方法一)或在菜单栏点击品字形红绿白图标(方法二)进入工程管理界面,如图8.1.3.1所示: ![]() ?+ ?% m3 E" o: }4 _* y 图8.1.3.1 进入工程管理界面 在工程管理界面,我们可以执行设置工程名字(Project Targets)、分组名字(Groups)以及添加每个分组的文件(Files)等操作。我们设置工程名字为:Template,并设置四个分组:Startup(存放启动文件)、User(存放main.c等用户代码)、Drivers/SYSTEM(存放系统级驱动代码)、Readme(存放工程说明文件),如图8.1.3.2所示: 9 b1 ~$ s# H0 Z8 x, B ![]() 图8.1.3.2 设置工程名和分组名 设置好之后,我们点击OK,回到MDK主界面,可以看到我们设置的工程名和分组名如图8.1.3.3所示: * ?0 `) r+ O0 L4 K ![]() ; L% Q6 o9 t. i, ~& N5 J% i 图8.1.3.3 设置成功 这里我们只是新建了一个简单的工程,并没有添加BSP、Middlewares等分组,后面随着工程复杂程度的增加,我们需要一步步添加对应的分组。 注意:为了让工程结构清晰,我们会尽量让MDK的工程分组和我们前面新建的工程文件夹对应起来,由于MDK分组不支持多级目录,因此我们将路径也带入分组命名里面,以便区分。如:User分组对应User文件夹里面的源码,Drivers/SYSTEM分组,对应Drivers/SYSTEM文件夹里面的源码,Drivers/BSP分组对应Drivers/BSP文件夹里面的源码等。- w& c$ V; _, K6 o 2. 添加启动文件: ] w1 j" k8 p% c" S8 g4 r5 r 启动文件(.s文件)包含STM32的启动代码,其主要作用包括:1、堆栈(SP)的初始化;2、初始化程序计数器(PC);3、设置向量表异常事件的入口地址;4、调用main函数等,是每个工程必不可少的一个文件,我们在本书第九章会有详细介绍。 启动文件由ST官方提供,存放在STM32CubeH7软件包的:DriversCMSISDevice STSTM32H7xxSourceTemplatesarm文件夹下。因为我们开发板使用的是STM32H750VBT6,对应的启动文件为:startup_stm32h750xx.s,为了节省空间,在精简版CMSIS文件夹里面我们把其他启动文件都删了。, u! T6 m2 j* Q7 G 关于启动文件的说明,我们就介绍这么多,接下来我们看如何添加启动文件到工程里面。我们有两种方法给MDK的分组添加文件:1,双击Project下的分组名添加。2,进入工程管理界面添加。 这了我们使用方法1添加(路径:实验0-3,新建工程实验-HAL库版本\Drivers\CMSIS! A; C- o# u. ?& i0 i8 M Device\ST\STM32H7xx\Source\Templates\arm),如图8.1.3.4所示:( {/ z4 h X- D9 |7 R3 m* M + z% G/ O5 ?, F2 E+ R4 ] ![]() ) Q9 z" n; d5 p8 x# N 图8.1.3.4 双击分组添加启动文件(startup_stm32h750xx.s)4 W% ^ R7 G! a* w+ x, h 上图中,我们也可以点击Add按钮进行文件添加。添加完后,点击Close,完成启动文件 添加,得到工程分组如图8.1.3.5所示: ![]() % `2 `9 c9 B: C5 J# o' h 图8.1.3.5 启动文件添加成功 3. 添加SYSTEM源码7 R' ~8 g: q" O P) Q$ X 这里我们在工程管理界面(方法2)进行SYSTEM源码添加。点击:按钮,进入工程管理界面,选中Drivers/SYSTEM分组,然后点击:Add Files,进入文件添加对话框,依次添加delay.c、sys.c和usart.c到该分组下,如图8.1.3.6所示: ![]() 图8.1.3.6 添加SYSTEM源码8 z. v! K _7 u* `9 m 注意:这些源码都是在第8.1.1小节的第二步拷贝过来的,如果之前没拷贝,是找不到这些源码的。添加完成后,如图8.1.3.7所示: 4 ?# D0 |0 ^% P0 N ![]() 图8.1.3.7 SYSTEM源码添加完成- K2 G8 q: n% ]; }9 g 4. 添加User源码 这里我们在工程管理界面(方法2)进行User源码添加。点击:按钮,进入工程管理界面,选中User分组,然后点击:Add Files,进入文件添加对话框,依次添加stm32h7xx_it.c和system_stm32h7xx.c到该分组下,如图8.1.3.8所示: $ B# w$ F7 d! i2 n8 Y' s ![]() 7 b+ q* n" a5 r1 e/ q 图8.1.3.8 添加User源码 注意:这些源码都是在第8.1.1小节的第二步拷贝过来的,如果之前没拷贝,是找不到这些源码的。添加完成后,如图8.1.3.9所示: ![]() , k0 g$ T# U8 J6 w7 A$ [1 c 图8.1.3.9 User源码添加完成 5. 添加STM32H7xx_HAL_Driver源码 接下来我们往Drivers/STM32H7xx_HAL_Driver分组里添加文件。点击:按钮,进入工程管理界面,选中Drivers/STM32H7xx_HAL_Driver分组,然后点击:Add Files,进入文件添加对话框,依次添加stm32h7xx_hal.c、stm32h7xx_hal_cortex.c、stm32h7xx_hal_dma.c、stm32h7xx_hal_gpio.c、stm32h7xx_hal_pwr.c、stm32h7xx_hal_pwr_ex.c、stm32h7xx_hal_rcc.c、stm32h7xx_hal_rcc_ex.c、stm32h7xx_hal_uart.c、stm32h7xx_hal_uart_ex.c、stm32h7xx_hal_usart.c和stm32h7xx_hal_usart_ex.c到该分组下,如图8.1.3.10所示:8 U! ~) N' E( @9 O9 i' K5 M % V# X7 m6 L. B; } ![]() 1 I* M5 [8 J' @' f3 x* i& Y 图8.1.3.10 添加STM32H7xx_HAL_Driver源码 H0 t9 ?3 q, \) C# \% y 添加完成后,如图8.1.3.11所示:: X/ x1 M) ~: F* ~# o+ k+ e! w) J U" h* g; z' a4 q ![]() 图8.1.3.11 STM32H7xx_HAL_Driver源码添加完成 可以看到分组中有些.c文件有个小钥匙的符号,这是因为官方的固件包的文件设置了只读权限,我们取消只读权限就好了,方法如图8.1.2.12所示。& L2 P; z7 d" w/ p) q 4 w# d, h6 H6 V ![]() 7 O5 z$ s9 _" C, U" |5 W& P 图8.1.2.12 取消工程文件夹的只读权限 8.1.4 魔术棒设置 为避免编写代码和编译报错,我们需要通过魔术棒对MDK工程进行相关设置。在MDK主界面,点击:(魔术棒图标,即Options for Target按钮),进入工程设置对话框,我们将进行如下几个选项卡的设置。# V6 |' n, E3 V6 S 1.设置Target选项卡# @5 ]! l8 W! F; p$ s2 h 在魔术棒Target选项卡里面,我们进行如图8.1.4.1所示设置:/ ^6 m8 t5 y2 s* A ' d* p, h5 `1 c' q% `1 U/ l( q ![]() 图8.1.4.1 Target选项卡设置 上图中,我们设置芯片所使用的外部晶振频率为8Mhz,选择ARM Compiler版本为:Use default compiler version 5(即AC5编译器)。 这里我们说明一下AC5和AC6编译的差异,如表8.1.4.2所示: 0 z d5 `# y) o0 [: ]3 j4 I7 F ![]() 表8.1.4.1 AC5&AC6简单对比2 P( F `3 {5 P 由于AC5对中文支持比较好,且兼容性相对好一点,为了避免不必要的麻烦,我们推荐大家使用AC5编译器。为了让大家自由选择,我们正点原子的源码,也是支持AC6编译器的,不过在选项卡设置上稍有差异,具体差异如表8.1.4.2所示: ![]() ) d8 o' f5 P, [2 t; s' `+ Z4 W 表8.1.4.2 AC5&AC6设置差异5 {; D. o/ f7 |# s" r- o' q$ [4 M5 m4 E 2. 设置Output选项卡2 R+ L) O4 t) D9 q 在魔术棒Output选项卡里面,进行如图8.1.4.2所示设置: [0 j/ y/ D0 p2 C 9 Y; C- Z9 a! X" X1 h! R" B8 k* ] ![]() $ n9 E; G. e5 B3 X$ V 图8.1.4.2 设置Output选项卡 注意,我们勾选:Browse Information,用于输出浏览信息,这样就可以使用go to definition查看函数/变量的定义,对我们后续调试代码比较有帮助,如果不需要调试代码,则可以去掉这个勾选,以提高编译速度。$ x* k* n! E4 _& l6 @ 3. 设置Listing选项卡* X% b" I9 ~7 e% S 在魔术棒Listing选项卡里面,进行如图8.1.4.3所示设置:! v- v. X! e& K! |! E+ a $ ~) K3 F K7 [( P/ B ![]() 0 H: Q" O; T" w 图8.1.4.3 设置Listing选项卡! t: r% ]" ?0 _. B! X- J 经过Output和Listing这两步设置,原来存储在Objects和Listings文件夹的内容(中间文件)就都改为输出到Output文件夹了。" e+ Q" {7 [$ ?! n3 j+ W 4. 设置C/C++选项卡 在魔术棒C/C++选项卡里面,进行如图8.1.4.4所示设置:) J. }$ s5 l7 Q+ Q0 b " x7 L; D/ u& o& c1 S: W ![]() 图8.1.4.4 设置C/C++选项卡 在②处设置了全局宏定义:STM32H750xx,用于定义所用STM32型号,在stm32h7xx.h里面会用到该宏定义。 在③处设置了优化等级为-O0,可以得到最好的调试效果,当然为了提高优化效果提升性能并降低代码量,可以设置-O1~-O3,数字越大效果越明显,不过也越容易出问题。注意:当使用AC6编译器的时候,这里推荐默认使用-O1优化。; D4 q9 m9 j) d7 Q/ @0 M; J9 h 在④处勾选C99模式,即使用C99 C语言标准。 在⑤处,我们可以进行头文件包含路径设置,点击此按钮,进行如图8.1.4.5所示设置: ![]() 4 x8 _& O( C8 W' v/ i8 W+ P) [ 图8.1.4.5 设置头文件包含路径$ A- H3 H4 D4 z% O4 Z 上图中我们设置了4个头文件包含路径,其中3个在Drivers文件夹下,一个在User文件夹下。为避免频繁设置头文件包含路径,正点原子最新源码的include全部使用相对路径,也就是我们只需要在头文件包含路径里面指定一个文件夹,那么该文件夹下的其他文件夹里面的源码,如果全部是使用相对路径,则无需再设置头文件包含路径了,直接在include里面就指明了头文件所在。% U! b: w$ @- F, ]3 j( r 关于相对路径,这里大家记住3点:) M$ `) G- P- G! | 1,默认路径就是指MDK工程所在的路径,即.uvprojx文件所在路径(文件夹) 2,“./”表示当前目录(相对当前路径,也可以写做“.\”) 3,“…/”表示当前目录的上一层目录(也可以写做“…\”) 举例来说,上图中:…\Drivers\CMSIS\Device\ST\STM32H7xx\Include,前面两个“…\”,表示Drivers文件夹在当前MDK工程所在文件夹(MDK-ARM)的上2级目录下,具体解释如图8.1.4.6所示: " V, f; W9 n3 t, h( Z$ x ![]() % v _' h8 {1 `) H, n 图8.1.4.6 …\Drivers\CMSIS\Device\ST\STM3H7xx\Include的解释# T% O' ?3 p2 f: e 上图表示根据头文件包含路径:…\Drivers\CMSIS\Device\ST\STM32H7xx\Include,编译器可以找到⑥处所包含的这些头文件,即代码里面可以直接include这些头文件使用。; i# `8 E4 ~2 @; ] 再举个例子,在完成如图6.1.4.5所示的头文件包含路径设置以后,我们在代码里面编写: #include “./SYSTEM/sys/sys.h”, T1 S+ K7 O* p$ `6 } 即表示当前头文件包含路径所指示的4个文件夹里面,肯定有某一个文件夹包含了:SYSTEM/sys/sys.h的路径,实际上就是在Drivers文件夹下面,两者结合起来就相当于:* x4 D& P9 C6 X' y #include “…/…/Drivers/SYSTEM/sys/sys.h” 这就是相对路径。它既可以减少头文件包含路径设置(即减少MDK配置步骤,免去频繁设置头文件包含路径的麻烦),同时又可以很方便的知道头文件具体在那个文件夹,因此我们推荐在编写代码的时候使用相对路径。 a' u; ]; U/ z# [9 D$ I5 a f 关于相对路径,我们就介绍这么多,大家搞不明白的可以在网上搜索相关资料学习,也可以在后面的学习,分析我们其他源码,慢慢体会,总之不难,但是好用。 最后,我们如果使用AC6编译器,则在图6.1.4.4的Misc Controls处需要设置:-Wno-invalid-source-encoding,避免中文编码报错,如果使用AC5编译器,则不需要该设置!!5 o- \2 F- R; S/ ~+ ^3 Y2 m4 ~ 5. 设置Debug选项卡 在魔术棒Debug选项卡里面,进行如图8.1.4.7所示设置: ![]() ' q* p. I. b0 l 图8.1.4.7 Debug选项卡设置 图中,我们选择使用:CMSIS-DAP仿真器,使用SW模式,并设置最大时钟频率为10Mhz,以得到最高下载速度。当我们将仿真器和开发板连接好,并给开发板供电以后,仿真器就会找到开发板芯片,并在SW Device窗口显示芯片的IDCODE、Device Name等信息(图中⑤处),当无法找到时,请检查供电和仿真器连接状况。4 i" P" y1 U- l/ H, t u$ _ 6. 设置Utilities选项卡5 v) r2 ]3 x8 C2 n* _ 在魔术棒Debug选项卡里面,进行如图8.1.4.8所示设置: ![]() 图8.1.4.8 Utilities选项卡设置 图中⑥处下载算法STM32H750,是MDK默认添加的,针对STM32H750系列产品。除此之外,我们还要添加算法,点击⑦处按钮添加即可。添加好算法后,设置算法使用的 RAM 地址和大小,这里设置的起始地址为:0X2000 0000(DTCM),大小为:0X3000。必须按这个大小设置,否则下载会出错(无法加载算法)。 7. 添加分散加载文件) w! y+ U7 w# T( P; h9 A0 s& a 由于STM32H750VBT6芯片内部的FLASH的空间比较少(只有128KB)。对于大的工程,这个FLASH空间是不够用的,为了解决这个问题,同时方便后续工程的新建,我们统一使用分散加载的方式来决定FLASH内存的分配,而不用MDK默认的设置。关于分散加载是什么?我们后面8.3小节会讲解,请大家先跟着我们把新建工程完成。 分散加载的文件已经为大家准备好了,可以在实验0-3,新建工程实验-HAL库版本\User\SCRIPT,或者在(A盘)/程序源码/STM32启动文件/分散加载_HAL库版本/SCRIPT中拷贝qspi_code.scf文件到我们的工程User\SCRIPT路径下,如图8.1.4.9所示。 ) G- ^2 T; t" R" n$ l9 V ![]() 图8.1.4.9 拷贝分散加载文件到工程3 h: f+ t" ~' p 注意:这里的分散加载文件寄存器跟HAL库是不一样的,我们建立HAL库工程,所以必需用HAL库版本的分散加载文件。 接下来我们需要对MDK进行配置,相当于把分散加载文件关联到工程里。方法:点击魔术棒, Linker选项卡取消勾选:Use Memory Layout from Target DialogScatter File路径选择SCRIPT文件夹 选择qspi_code.scf文件,然后,在disable Warnings一栏,添加:6314,6329,屏蔽6314和6329这两个警告。如不屏蔽,当分散加载里面有某些段(section)没用到,则会报警告,所以我们需要屏蔽这两个警告。如图8.1.4.10所示。' i# r. X/ w1 l ![]() # X- C2 U# L, Q: x) g1 }# k 图8.1.4.10 添加分散加载文件 至此,添加分散加载文件的相应操作就完成了。 8.1.5 添加main.c,并编写代码 在MDK主界面,点击:,新建一个main.c文件,并保存在User文件夹下。然后双击User分组,弹出添加文件的对话框,将User文件夹下的main.c文件添加到User分组下。得到如图8.1.5.1所示的界面: ![]() Z% a0 |7 e9 ]" v I: i 图8.1.5.1 在User分组下加入main.c文件 至此,我们就可以开始编写我们自己的代码了。我们在main.c文件里面输入如下代码:
此部分代码,在A盘4,程序源码1,标准例程-HAL库版本 实验0 基础入门实验实验0-3,新建最工程实验-HAL库版本Usermain.c里面有,大家可以自己输入,也可以直接拷贝。强烈建议自己输入,以加深对程序的理解和印象!! 注意,这里的include就是使用的相对路径,关于相对路径,请参考前面C/C++选项卡设置章节进行学习。 编写完main.c,我们点击:(Rebuild)按钮,编译整个工程,编译结果如下图所示:/ e, z5 [2 J8 m a9 Y. H 图8.1.5.2 编译结果4 [ |" v& E, b% ~% _' ^% Y 编译结果可以看到1个错误,0个警告。这个错误说找不到main.h,因为我们也不需要用到main.h,双击这个错误会弹出下面的stm32h7xx_it.c文件对应包含main.h的语句。我们只需要把它删除,然后重新编译,如图8.1.5.3所示。0 r2 Y8 l- k( {* ^1 | 7 R* Y: G8 p3 K w+ e7 J ![]() 图8.1.5.3 删除包含main.h的语句 编译后发现又有一个警告,警告HAL_IncTick函数没有声明,如图8.1.5.4所示。1 u9 Z) q" O) |# ~ 3 H0 \, P; S' s6 ^' r# Y0 e8 m7 d ![]() 图8.1.5.4 编译报警告- E+ p6 O/ K, V, Z 因为这个函数是在stm32h7xx_hal.c定义了,并且在stm32h7xx_hal.h声明了。我们把stm32h7xx_hal.h包含进来即可。这里还有一个原因是整个工程没有包含stm32h7xx_hal.h的语句,我们需要用到它,所以在这里把它包含进来。官方的main.h是有包含这个头文件的。我们不用main.h文件,我们在stm32h7xx_it.c文件刚才删除包含main.h的语句的位置,编写包含stm32h7xx_hal.h语句,如图8.1.5.5所示。 & w* i2 s$ {, r5 u# E: I ![]() 图8.1.5.5 包含stm32h7xx_hal.h头文件到工程& I) T" f, f! A; X4 R 再进行编译就会发现0错误0警告,结果如图8.1.5.6所示。1 K; b6 h3 l" r& c7 Z. D . m: ~6 ^, Z# u _% E% ] ![]() 图8.1.5.6 编译结果 编译结果提示:代码总大小(Porgram Size)为:FLASH占用13520字节(Code + RO + RW),SRAM占用2008字节(RW + ZI);并成功创建了Hex文件(可执行文件,放在Output目录下)。+ N4 E" z% A" ]( _ 总结:如果编译提示有错误/警告,请根据提示,从第一个错误/警告开始解决,直到0错误0警告。如果出错,很有可能是之前的操作存在问题,请对照教程找问题。1 r( e7 K% x2 l7 @% ]" b 另外,我们在Readme分组下还没有添加任何文件,由于只是添加一个说明性质的文件(.txt),并不是工程必备文件,因此这里我们就不添加了,开发板光盘的源码我们是有添加的,大家可以去参考一下。% w. ]8 y2 R* h: |% u& B8 S, {+ M 至此,新建HAL库版本MDK工程完成。 8.2 下载验证5 w9 ~! W& G5 D 这里我们继续使用DAP仿真器下载,在MDK主界面,点击:(下载按钮,也可以按键盘快捷键:F8),就可以将代码下载到开发板,如图8.2.1所示: ![]() 6 o( O% _3 O1 o, r: b9 Z9 u, v. Q 图8.2.1 下载成功 上图提示:Application running…,则表示代码下载成功,且开始运行。此时,看到RGB的红、蓝、绿三种灯轮流亮,类跑马灯。如果有朋友没能下载成功,请看第四章寻找问题,或者直接对照我们提供的实验0-3,新建工程实验-HAL库版本工程设置。9 h+ M* j0 R1 Y# g+ c9 k2 ? 8.3 分散加载文件简介 ARM芯片用于在链接时指定存储器分配方案的文件,称之为分散加载文件(.sct),它可以将不同的代码(.o文件)放在不同的存储空间。关于分散加载的详细介绍,请参考:A盘8,STM32参考资料4,分散加载分散加载文件浅释.pdf,这是周立功公司的一份文档资料,详细介绍了.sct文件的基础概念、语法及应用实例说明,对学习分散加载非常有帮助,请大家务必先学习一下这个文档。 本节,我们仅对.sct文件进行一个简介,方便大家学习。 首先明确一个概念:MDK编译任何STM32工程,都会需要用到分散加载文件。分散加载文件的来源有两种方式: 1,通过MDK自己生成; 2,通过用户指定(用户自己编写); 首先,我们来看MDK自己生成的.sct文件。/ |4 p" X5 W" Z5 k+ d 选择本章新建工程MDK的魔术棒Linker选项卡里面,进行如图8.3.1所示的设置:# k% m6 u, }" q/ u& R# C * y2 r( b8 O6 V0 i7 c( b" W ![]() 图8.3.1 勾选Use Memory Layout from Target Dialog选项 勾选Use Memory Layout from Target Dialog选项后,MDK就会根据Target选项卡里面的相关设置来决定存储器分配,如图8.3.2所示: 2 l( k+ i+ Y) A# t3 I5 i ![]() 2 {5 h8 | P# Y) h4 @$ u# n2 ?' j 图8.2.2 MDK默认的存储器分配+ K9 ^2 j; }0 G* w* f# d# D 标号①,是MDK的只读存储区域(ROM)和可读写存储区域(RAM)的配置区域。 标号②处,说明默认将所有的代码(Code + RO Data + RW Data)都存放到IROM1指定的地址范围上。其起始地址为:0X0800 0000,大小为:0X20000。 标号③处,说明默认将所有的变量及堆栈(RW Data + ZI Data)都存放在IRAM1和IRAM2指定的地址范围上。IRAM1的起始地址为:0X2000 0000,大小为:0X20000;IRAM2的起始地址为:0X2400 0000,大小为:0X80000;变量的具体位置由编译器自动分配。! _- z6 i: @5 D' j; F, T1 t9 l 在完成以上两步操作以后,对MDK进行一次编译,在编译成功后,MDK会自动生成一个以工程名命名的.sct文件,存放在Output文件夹里面,如图8.2.3所示:9 _; l& n2 u) g. q$ n ![]() ! r+ S1 d. m8 h 图8.2.3 MDK自动生成的分散加载文件7 V2 n/ M1 K4 Q8 T$ C' e& w- [ 打开上图中的test.sct文件,其内容如下:
其中:5 m Y% n, }* k. H7 g$ a6 \! [ ER_IROM1为ROM区域,存放:Code + RO Data + RW Data等只读数据,由:.ANY (+RO)指定,即所有只读数据,都存放在这个区域。 RW_IRAM1和RW_IRAM2为RAM区域,存放:RW Data + ZI Data等可读写数据,由:.ANY (+RW +ZI)指定,即所有的可读写数据,都存放在这两个区域,具体存放位置由MDK编译器自动分配。6 o! }% ] _2 T+ y8 e; O: ^5 S& E *.o (RESET, +First):表示优先(+FIRST)将RESET(即中断向量表)段放这个域的起始位置,实际上就是把中断向量表拷贝到最开始的位置。 (InRoot$$Sections):表示将所有用到的库段放到root区,如:__main.o、__scatter*.o和__dc*.o等。 以上,就是MDK自动生成的.sct文件简介。 接下来,我们看用户指定.sct文件的实现方式。选择本章新建工程MDK的魔术棒Linker选项卡里面,进行如图8.3.4所示的设置:9 a0 E( F3 j9 J9 L ![]() 2 g. ^8 s5 ~* L/ @+ E 图8.2.4 取消Use Memory Layout from Target Dialog选项. H! U9 r, L/ x 标号①,取消Use Memory Layout from Target Dialog选项,使用用户自定义分散加载文件。 标号②,新建工程时,已选择SCRIPT\qspi_code_scf.scf分散加载文件。% N! O( l# A: z1 F( F- a 标号③,点击Edit按钮,即可在MDK里面打开qspi_code_scf.scf分散加载文件。 qspi_code.scf的内容如下: 1 D2 L# O, f# h2 I
/* H7的QSPI接口不支持读时写,因此必须把以下3个文件放到内部FLASH,以保证可以 对QSPI FLASH的写入 */3 c) E& s2 U8 ?/ z$ v 1 C7 t3 x1 D6 e( C% N4 ?" O
相比于MDK自己生成的分散加载文件,我们自己编写的相对复杂一些,qspi_code.scf分散加载文件包含2个加载域,3个运行域,分别是: LR_m_stmflash加载域,起始地址为:m_stmflash_start(宏定义,实际值:0X0800 0000),大小为:m_stmflash_size(宏定义,实际值:0X20000)。它包含二个运行域分别是: ER_m_stmflash运行域,起始地址为:m_stmflash_start(宏定义,实际值:0X0800 0000),大小为:m_stmflash_size(宏定义,实际值:0X20000)。1 z0 k: |! k6 l% @) S RW_m_stmsram运行域,起始地址为:m_stmsram_start(宏定义,实际值:0X2400 0000)大小为:m_stmsram_size(宏定义,实际值:0X80000)。 LR_m_qspiflash加载域,起始地址为:m_qspiflash_start(宏定义,实际值:0X9000 0000)大小为:m_qspiflash_size(宏定义,实际值:0X80000)。它包含一个运行域:7 b' v7 ~ C4 v; M3 r6 O ER_m_qspiflash运行域,起始地址为:m_qspiflash_start(宏定义,实际值:0X9000 0000)大小为:m_qspiflash_size(宏定义,实际值:0X80000)。( ^0 ~6 \+ \% N; M3 K; Y7 Y 具体的存储器分配情况为: ER_m_stmflash运行域,包含:*.o (RESET, +First)开始到delay.o结束的相关代码,这些代码运行在内部FLASH,可以得到最佳的性能。需要注意的是:这些代码大部分都是必须放到内部FLASH,否则无法正常运行!! ER_m_qspiflash运行域,所有没有在ER_m_stmflash运行域指定的代码,都被放在这个运行域,这些代码运行在外部SPI FLASH,速度比内部FLASH慢一些。1 k# z* I- L7 A* e/ x RW_m_stmsram运行域,所有变量及堆栈(RW Data + ZI Data)都存放在这个运行域。; i8 R. o% Z8 `; L4 O 以上分散加载文件,由正点原子编写,为了方便大家使用,不用频繁修改.sct文件,特意将.ANY ROM区域放在外部SPI FLASH,这样大家在新增.c参与编译时,默认就是存放在外部SPI FLASH的,这样使用起来就更方便。 注意事项:6 ~# @+ H2 q) k) ?4 J# U 1、如果你新增的代码,对速度有要求,可以将其对应的.o添加到内部FLASH,即放在:ER_m_stmflash运行域。& x" @9 f- Q8 m( } 2、如果添加新代码后,程序无法正常运行(通常表现为黑屏/不启动),可以尝试将新增的.o放到ER_m_stmflash运行域后(重新编译)再尝试。如果还不行,可以尝试将所有代码都放到ER_m_stmflash运行域后再尝试。6 K4 x% E% J9 M+ Z- E& r. }. z 至此,分散加载文件就给大家介绍完了。 O% e3 T. W/ d/ [2 X2 x% u ————————————————$ o2 R6 {0 ?" O0 T0 d% h 版权声明:正点原子 9 c1 s( s5 _' i/ T( e0 J- \ 9 }4 @: w3 G: E: I% N* y6 k8 M |
【2025·STM32峰会】GUI解决方案实训分享2-编译运行TouchGFX咖啡机例程(含桌面仿真)
【2025·STM32峰会】GUI解决方案实训分享1-对LVGL咖啡机例程的牛刀小试以及问题排查
实战经验 | 关于STM32H7使用LL库生成ADC代码工作异常问题说明
实战经验 | 关于STM32H745的MC SDK电机控制工程问题的解决办法
【H745I GUI】1.GreenHouse 灯光控制
【Wio Lite AI视觉开发套件】+移植TensorFlow Lite
STM32H745I-DISCO脉冲宽度调制(PWM)
STM32H745I-DISCO串口通信,输入输出
拷打cubemx【002】——自定义还需基于芯片的工程
STM32硬件结构学习