建立相关文件夹如图所示
FWLIB放官方固件库文件,HARDWARE放自己编写的.C,.H文件,USER放主函数文件,工程,启动文件等。
1,首先,打开 MDK(以下将 MDK5 简称为 MDK)软件。然后点击 Project---New uVision Project ,然后保存在USER文件夹下,工程名自取。
2,选择 STMicroelectronics--STM32F4 Series--STM32F407--STM32F407ZGT6(如果使用的是其他系列的芯片,选择相应的型号就可以了,特别注意: 一定要安装对应的器件 pack
才会显示这些内容哦!!)。
3,点击 OK, MDK 会弹出 Manage Run-Time Environment 对话框 。这是 MDK5 新增的一个功能,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们
不做介绍。所以在图 3.2.4 所示界面,我们直接点击 Cancel,即可。得到如图所示界面:
4,到这里,我们还只是建了一个框架,还需要添加启动代码,以及.c 文件等。这里我们先介绍一下启动代码: 启动代码是一段和硬件相关的汇编代码。 是必不可少的! 这代码主要作用如
下:
1、堆栈(SP)的初始化;
2、初始化程序计数器(PC);
3、设置向量表异常事件的入口地址;
4、调用 main 函数。感兴趣的朋友可以自己去分析这部分代码。
ST 公司为 STM32F40x 和 STM32F41x 系列的 STM32F4 提供了一个共同的启动文件,名字为: startup_stm32f40_41xxx.s。 我们开发板使用的是 STM32F407ZGT6, 属于 STM32F40x 系列
里面的,所以直接使 startup_stm32f40_41xxx.s 这个启动文件即可。 不过这个启动文件,我们做了一点点修改,具体是 Reset_Handler 函数,该函数修改后代码如下:
Reset_Handler PROC EXPORT Reset_Handler [WEAK] ;IMPORT SystemInit ;寄存器代码,不需要在这里调用 SystemInit 函数, ;故屏蔽掉,库函数版本代码,可以留下 ;不过需要在外部实现 SystemInit 函数,否则会报错. IMPORT __main LDR R0, =0xE000ED88 ;使能浮点运算 CP10,CP11 LDR R1,[R0] ORR R1,R1,#(0xF << 20) STR R1,[R0] ;LDR R0, =SystemInit ;寄存器代码,未用到,屏蔽 ;BLX R0 ;寄存器代码,未用到,屏蔽 LDR R0, =__main BX R0 ENDP
这段代码,我们主要加入了开启 STM32F4 硬件 FPU 的代码,以使能 STM32F4 的浮点运算单元。其中, 0xE000ED88 就是协处理器控制寄存器(CPACR)的地址,该寄存器的第 20~23
位用来控制是否支持浮点运算,这里我们全设置为 1,以支持浮点运算。关于 CPACR 寄存器的详细描述,见《STM32F3 与 F4 系列 Cortex M4 内核编程手册.pdf》第 4.6.1 节。另外,寄存器
版本,我们还屏蔽了 SystemInit 函数的调用,如果是库函数版本,可以取消这个函数的注释,并在外部实现 SystemInit 函数。
特别注意:我们在汇编代码里面使能了 FPU,所以在 MDK 里面,我们也要设置使用 FPU,否则可能代码会无法运行,设置方法如下:选择 Options for Target ‘Target1’ ,打开 Target 选
项卡,在 Code Generation 里面,选择 Use FPU,如图 所示:
这样, MDK 编译生成的代码,就可以直接使用硬件 FPU 了,其实就 2 个步骤: 1,设置CPACR 寄存器 20~23 位全为 1,使能硬件 FPU。 2,设置 MDK 选型,选择 Use FPU。另外,
图 中, MDK 默认 STM32F4 外部晶振为 12M,我们板子用的 8M,所以这里设置为 8Mhz。修改后的这个启动文件 startup_stm32f40_41xxx.s 拷贝到刚刚新建的USER文件夹里面。
5,在图中,我们找到 Target1--Source Group1--双击--设置打开文件类型为 Asm Source file--选择 startup_stm32f40_41xxx.s--点击 Add,如图所示:
添加完后,我们得到如图所示的界面:
至此,我们就可以开始编写自己的代码了。
由于上面我们还没有任何代码在工程里面,这里我们把系统代码 COPY 过来(即 SYSTEM文件夹的代码,该文件夹由 ALIENTEK 提供,可以在光盘任何一个实例的工程目录下找到,不过不要
拷贝错了! 不要把库函数代码的系统文件夹拷贝到寄存器代码里面用,反之亦然! 这些代码在任何 STM32F40x/STM32F41x 的芯片上都是通用的,可以用于快速构建自己的工程)。
SYSTEM 文件夹下包含了 delay、 sys、 usart 等三个文件夹。分别包含了 delay.c、 sys.c、 usart.c及其头文件。通过这 3 个 c 文件,可以快速的给任何一款 STM32F4 构建最基本的框架。使用
起来是很方便的。
具体可以百度学习一下。
6,然后在 Target 目录树上点击右键--Manage Project Items, 弹出如图 所示对话框:
在上面对话框的中间栏,点新建(用红圈标出) 按钮(也可以通过双击下面的空白处实现),新建 USER 和 SYSTEM 两个组。 然后点击 Add Files 按钮,把 SYSTEM 文件夹三个子文件夹里
面的: sys.c、 usart.c、 delay.c 加入到 SYSTEM 组中。注意: 此时 USER 组下还是没有任何文件,
得到如图所示的界面:
点击 OK,退出该界面返回 IDE。 这时,我们在 Target1 树下发现多了 2 个组名,就是我们刚刚新建的 2 个组。如图 所示:
7,接着,我们新建一个 test.c 文件,并保存在 USER 文件夹下。 然后双击 USER 组,会弹出加载文件的对话框,此时我们在 USER 目录下选择 test.c 文件,加入到 USER 组下。 得到如图
所示的界面:
至此,我们就可以开始编写我们自己的代码了。 我们在 test.c 文件里面输入如下代码:
#include "sys.h" #include "usart.h" #include "delay.h" int main(void) { u8 t=0; Stm32_Clock_Init(336,8,2,7);//初始化时钟为 168Mhz delay_init(168); //初始化延时函数 uart_init(84,115200); //串口初始化为 115200 while(1) { printf("t:%d\r\n",t); delay_ms(500); t++; } }
如果我们此时编译的话, 生成的过程文件,还是会存放在 USER 文件夹下,所以,我们先设置输出路径,再编译。 点击 (Options for Target 按钮),弹出 Options for Target’ Target 1’
对话框,选择 Output 选项卡--选中 Create Hex File(用于生成 Hex 文件,后面会用到)--点击Select Folder for Objects--找到 OBJ 文件夹--点击 OK。
接着,再设置 Listings 文件路径,在上文的基础上,打开 Listing 选项卡--点击 Select Folder for Listings--找到 OBJ 文件夹--点击 OK。
8,现在我们再次点击 (Options for Target 按钮),弹出 Options for Target’ Target 1’ 对话框,选择 C/C++选项卡,如图 所示:
这里特别提醒大家: 图中 1 处设置的 STM32F40_41xxx 宏,是为了兼容低版本的 MDK(比如 MDK4/MDK3 等)才添加的, MDK5 在你选择器件的时候,就会内部定义这个宏,因此在
MDK5 下面,这里不设置也是可以的。但是为了兼容低版本的 MDK,我们还是将这个宏添加进来。
图中 2 处是编译器优化选项,有-O0~-O3 四种选择(default 则是-O2),值越大,优化效果越强,但是仿真调试效果越差。这里我们选择-O0 优化,以得到最好的调试效果,方便开发代
码,在代码调试结束后,大家可以选择-O2 之类的优化,得到更好的性能和更少的代码占用量。
图中 3 处, One ELF Section per Function 主要是用来对冗余函数的优化。通过这个选项,可以在最后生成的二进制文件中将冗余函数排除掉,以便最大程度地优化最后生成的二进制代
码,所以,我们一般勾选上这个,这样可以减少整个程序的代码量。
然后在 Include Paths 处(4 处),点击 5 处的按钮。在弹出的对话框中加入 SYSTEM 文件夹下的 3 个文件夹名字,把这几个路径都加进去(此操作即加入编译器的头文件包含路径, 后
面会经常用到)。如图 所示:
点击 OK 确认,回到 IDE,此时再点击 按钮,(bulid)编译一次,发现没错误了,得到如图 所示的界面:
因为我们之前选择了生成 Hex 文件,所以在编译的时候, MDK 会自动生成 Hex 文件(图中圈出部分),这个文件在 OBJ 文件夹里面,串口下载的时候,我们就是下载这个文件到
STM32F4 里面的,这个在后面的程序下载一节会介绍。
这里有的朋友编译后,可能会出现一个警告: warning: #1-D last line of file ends without anewline。这个警告是在告诉我们,在某个 C 文件的最后,没有输入新行,我们只需要双击这个
警告,跳转到警告处,然后在后面输入多一个空行就好了。
至此,一个完整的 STM32F4 开发工程在 MDK5 下建立了。 接下来我们就可以进行代码下载和仿真调试了。
关于代码,其实就是配置系统时钟,开启外设时钟,配置外设,功能代码,一般就是这样的流程
**************************************************************************************************
文本美化,主要是设置一些关键字、注释、数字等的颜色和字体。 前面我们在介绍 MDK5新建工程的时候看到界面如图 3.2.23 所示,这是 MDK 默认的设置, 可以看到其中的关键字和
注释等字体的颜色不是很漂亮,而 MDK 提供了我们自定义字体颜色的功能。我们可以在工具条上点击扳手图样 (配置对话框)弹出如图 所示界面:
在该对话框中,先设置 Encoding 为:Chinese GB2312(Simplified),然后设置 Tab size 为: 4。以更好的支持简体中文(否则,拷贝到其他地方的时候,中文可能是一堆的问号),同时 TAB
间隔设置为 4 个单位。然后,选择: Colors&Fonts 选项卡,在该选项卡内,我们就可以设置自己的代码的子体和颜色了。由于我们使用的是 C 语言,故在 Window 下面选择: C/C++ Editor Files
在右边就可以看到相应的元素了。如图 示:
然后点击各个元素修改为你喜欢的颜色(注意双击,且有时候可能需要设置多次才生效,MDK 的 bug),当然也可以在 Font 栏设置你字体的类型,以及字体的大小等。设置成之后,点
击 OK, 就可以在主界面看到你所修改后的结果 。
这就比开始的效果好看一些了。 字体大小,则可以直接按住: ctrl+鼠标滚轮,进行放大或者缩小,或者也可以在刚刚的配置界面设置字体大小。
细心的读者可能会发现,上面的代码里面有一个 u8,还是黑色的,这是一个用户自定义的关键字,为什么不显示蓝色(假定刚刚已经设置了用户自定义关键字颜色为蓝色)呢?这就又
要回到我们刚刚的配置对话框了,单这次我们要选择 User Keywords 选项卡,同样选择: C/C++Editor Files,在右边的 User Keywords 对话框下面输入你自己定义的关键字
图 3.3.5 中我定义了 u8、 u16、 u32 等 3 个关键字,这样在以后的代码编辑里面只要出现这三个关键字,肯定就会变成蓝色。点击 OK,再回到主界面,可以看到 u8 变成了蓝色了
快速定位函数/变量被定义的地方 :右键
快速注释与快速消注释 :
**************************************************************************
串口只能下载代码,并不能实时跟踪调试,而利用调试工具,比如 JLINK、 ULINK、 STLINK等就可以实时跟踪程序, 从而找到你程序中的 bug, 使你的开发事半功倍。这里我们以 JLINK
V8 为例,说说如何在线调试 STM32F4。
JLINK V8 支持 JTAG 和 SWD, 同时 STM32F4 也支持 JTAG 和 SWD。所以,我们有 2 种方式可以用来调试, JTAG 调试的时候,占用的 IO 线比较多,而 SWD 调试的时候占用的 IO 线
很少,只需要两根即可。
JLINK V8 的驱动安装比较简单, 我们在这里就不说了。在安装了 JLINK V8 的驱动之后,我们接上 JLINK V8,并把 JTAG 口插到 ALIENTEK 探索者 STM32F4 开发板上,打开之前
新建的工程, 点击 ,打开 Options for Target 选项卡,在 Debug 栏选择仿真工具为 J-LINK/J-TRACE Cortex,如图 所示:
上图中我们还勾选了 Run to main(),该选项选中后, 只要点击仿真就会直接运行到 main 函数, 如果没选择这个选项,则会先执行 startup_stm32f40_41xxx.s 文件的 Reset_Handler,再跳到
main 函数。
然后我们点击 Settings,设置 J-LINK 的一些参数,如图 4.2.2 所示:
图 中,我们使用 J-LINK V8 的 SW 模式调试,因为我们 JTAG 需要占用比 SW 模式多很多的 IO 口,而在 ALIENTEK 探索者 STM32F4 开发板上这些 IO 口可能被其他外设用到,可
能造成部分外设无法使用。所以,我们建议大家在调试的时候,一定要选择 SW 模式。Max Clock,可以点击 Auto Clk 来自动设置, 图 中我们设置 SWD 的调试速度为 10Mhz,这里,如果你
的 USB 数据线比较差,那么可能会出问题,此时, 你可以通过降低这里的速率来试试。
单击 OK,完成此部分设置,接下来我们还需要在 Utilities 选项卡里面设置下载时的目标编程器,如图 所示:
图中, 我们直接勾选 Use Debug Driver,即和调试一样,选择 JLINK 来给目标器件的FLASH 编程, 然后点击 Settings,设置如图所示:
这里 MDK5 会根据我们新建工程时选择的目标器件,自动设置 flash 算法。我们使用的是STM32F407ZGT6, FLASH 容量为 1M 字节, 所以 Programming Algorithm 里面默认会有 1M 型
号的 STM32F4xx FLASH 算法。 特别提醒: 这里的 1M flash 算法,不仅仅针对 1M 容量的STM32F4,对于小于 1M FLASH 的型号,也是采用这个 flash 算法的。 最后, 选中 Reset and Run
选项,以实现在编程后自动运行, 其他默认设置即可。设置完成之后,如上图 所示。
在设置完之后,点击 OK,然后再点击 OK,回到 IDE 界面,编译一下工程。 然后点击:
(开始/停止仿真按钮),开始仿真(如果开发板的代码没被更新过,则会先更新代码(即下载
代码),再仿真, 你也可以通过按 load按钮,只下载代码,而不进入仿真。 特别注意:开发板上的 BOOT0和 BOOT1 都要设置到 GND,否则代码下载后不会自动运行的!), 如图所示:
因为我们之前勾选了 Run to main()选项,所以,程序直接就运行到了 main 函数的入口处。另外,此时 MDK 多出了一个工具条, 这就是 Debug 工具条,这个工具条在我们仿真的时候是
非常有用的,下面简单介绍一下 Debug 工具条相关按钮的功能。 Debug 工具条部分按钮的功能如图 所示:
复位:其功能等同于硬件上按复位按钮。相当于实现了一次硬复位。 按下该按钮之后, 代码会重新从头开始执行。
执行到断点处:该按钮用来快速执行到断点处,有时候你并不需要观看每步是怎么执行的,而是想快速的执行到程序的某个地方看结果,这个按钮就可以实现这样的功能,前提是你在查
看的地方设置了断点。
停止运行:此按钮在程序一直执行的时候会变为有效,通过按该按钮,就可以使程序停止下来,进入到单步调试状态。
执行进去: 该按钮用来实现执行到某个函数里面去的功能,在没有函数的情况下,是等同于执行过去按钮的。
执行过去:在碰到有函数的地方,通过该按钮就可以单步执行过这个函数,而不进入这个函数单步执行。
执行出去:该按钮是在进入了函数单步调试的时候,有时候你可能不必再执行该函数的剩
余部分了,通过该按钮就直接一步执行完函数余下的部分,并跳出函数,回到函数被调用的位
置。
执行到光标处:该按钮可以迅速的使程序运行到光标处,其实是挺像执行到断点处按钮功能,但是两者是有区别的,断点可以有多个,但是光标所在处只有一个。
汇编窗口:通过该按钮,就可以查看汇编代码,这对分析程序很有用。
堆栈局部变量窗口:通过该按钮, 显示 Call Stack+Locals 窗口,显示当前函数的局部变量及其值,方便查看。
观察窗口: MDK5 提供 2 个观察窗口(下拉选择),该按钮按下,会弹出一个显示变量的窗口, 输入你所想要观察的变量/表达式,即可查看其值, 是很常用的一个调试窗口。
内存查看窗口: MDK5 提供 4 个内存查看窗口(下拉选择), 该按钮按下,会弹出一个内存查看窗口,可以在里面输入你要查看的内存地址,然后观察这一片内存的变化情况。是很常
用的一个调试窗口
这里stlink与jlink其实用法是一样的,选着对应的选项即可。