STM32应用的三种框架
应用代码+设备寄存器
应用代码+标准库+设备寄存器
应用代码+OS+标准库+设备寄存器
STM32 固件库结构
STM32 官方标准固件库简介
ST(意法半导体)为了方便用户开发程序,提供了一套丰富的 STM32F4 固件库。到底什么是固件库?
stm32的库函数开发实际就是使用已经封装好的API接口,是由意法半导体公司(stm32的厂商)定义的,不是标准C语言库。这些已经封装号的API接口就是搭建工程时,放入工程的.c文件和.h文件
固件库文件夹介绍
把STM32F4()官方库下载解压后,里面会包含如下几个子目录:
_htmresc:
? 这个目录包含了网页页面资源,如图片等.
Libraries:
这个目录包含两个子目录CMSIS和STM32F4xx_StdPeriph_Driver,这两个目录包含固件库核心的所有子文件夹和文件。
Libraryies目录里面的文件在我们建立工程的时候都会使用到,我们无须修改(也不建议修改)其文件内容。
CMSIS
CMSIS 文件夹存放的是符合 CMSIS 规范的一些文件。包括 STM32F4 核内外设访问层代码,DSP 软件库,RTOS API,以及 STM32F4 片上外设访问层代码等。我们后面新建工程的时候会从这个文件夹复制一些文件到我们工程。
DSP_Lib MDK项目文件,示例和源文件等。用于Cortex-M0,Cortex-M3,Cortex-M4处理器的CMSIS DSP软件库。
Include CMSIS核心支持和CMSIS DSP包含文件。
Lib CMSIS DSP库。
RTOS CMSIS RTOS API模板头文件。
Driver CMSIS外围设备驱动程序接口。
Pack CMSIS软件包。安装软件,设备支持,API和示例项目的机制。
SVD CMSIS SVD架构文件和转换实用程序。
STM32F4xx_StdPeriph_Driver
此目录下放的是 STM32F4 标准外设固件库源码文件和对应的头文件。
又包含inc 和src两个子目录,src 目录下面放的是 stm32f4xx_ppp.c 格式的固件库源码文件,主要是各种对STM32 硬件接口操作的驱动代码。inc目录下放的是 stm32f4xx_ppp.h 格式的固件库头文件。
头文件每一个.c 文件和一个相应的.h 文件对应,无需改动。
如:stm32f4xx_gpio.c/stm32f4xx_gpio.h 包含对GPIO口操作的各函数实现。
Project:
STM32F4xx_StdPeriph_Examples
STM32F4xx_StdPeriph_Examples 存放的的 ST 官方提供的固件实例源码,在以后的开发过程中,**可以参考修改这个官方提供的实例来快速驱动自己的外设,**很多开发板的实例都参考了官方提供的例程源码,这些源码对以后的学习非常重要。
STM32F4xx_StdPeriph_Templates
这个目录包含了在IAR,KEIL, RAIONANCE,TASKING,TrueSTUDIO工具链下的标准的工程模板**,**其中如下几个.c和.h文件,在我们的工程中需要用到(可以原样拷贝到我们的工程目录下去):
? stm32f4xx_conf.h : 配置文件
? stm32f4xx_it.c : 包含中断处理源文件
? stm32f4xx_it.h : 包含各中断处理函数原型及声明的头文件
? main.c : main函数入口
? main.h : 头文件
? system_stm32f4xx.c :包含系统时钟树初始化,PLL配置,初始化flash等
Utilities:
文件下就是官方评估板的一些对应源码。
stm32f4xx_dsp_stdperiph_lib_um.chm
根目录中还有一个 stm32f4xx_dsp_stdperiph_lib_um.chm 文件,直接打开可以知道,这是一个固件库的帮助文档**,这个文档非常有用,**只可惜是英文的,在开发过程中,这个文档会经常被使用到
固件库关键文件介绍
在介绍一些关键文件之前,首先我们来看看一个基于固件库的 STM32F4 工程需要哪些关
键文件,这些文件之间有哪些关联关系。其实这个可以从 ST 提供的英文版的说明里面找到。
core_cm4.h
位置
\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Libraries\CMSIS\Include
介绍
这个就是 CMSIS 核心文件,提供进入 M4 内核接口,这是 ARM 公司提供,对所有
CM4 内核的芯片都一样。你永远都不需要修改这个文件,所以这里我们就点到为止。
stm32f4xx.h
位置
\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Libraries\CMSIS\Device\ST\STM32F4xx\Include
介绍
stm32f4xx.h 是 STM32F4 片上外设访问层头文件。这个文件就相当重要了,只要你做
STM32F4 开发,你几乎时刻都要查看这个文件相关的定义。
这个文件打开可以看到,里面非常多的结构体以及宏定义。这个文件里面主要是系统寄存器定义申明以及包装内存操作,对于这里是怎样申明以及怎样将内存操作封装起来的。同时该文件还包含了一些时钟相关的定义,FPU 和 MPU 单元开启定义,中断相关定义等等。
system_stm32f4xx.h
位置
\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Libraries\CMSIS\Device\ST\STM32F4xx\Include 下面
介绍
system_stm32f4xx.h 是片上外设接入层系统头文件。主要是申明设置系统及总线时钟相关的函数。
与其对应的源文件 system_stm32f4xx.c 在目录\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Templates 可以找到。
这个里面有一个非常重要的 SystemInit()函数申明,这个函数在我们系统启动的时候都会调用,用来设置系统的整个系统和总线时钟。
stm32f4xx_it.c和stm32f4xx_it.h
位置
\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Templates
介绍
这几个文件我们新建工程也有用到。stm32f4xx_it.c 和 stm32f4xx_it.h 里面是外设处理和中断服务函数,中断服务函数也可以随意编写在工程里面的任意一个文件里面,个人觉得这个文件没太大意义。
stm32f4xx_conf.h
位置
\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Project\STM32F4xx_StdPeriph_Templates
介绍
stm32f4xx_conf.h 是外设驱动配置文件。文件打开可以看到一堆的#include,这里你建立工程的时候,可以注释掉一些你不用的外设头文件。这里相信大家一看就明白。
对于上图中的 misc.c,misc.h,stm32f4xx_ppp.c,stm32f4xx_ppp.h 以及 stm32f4xx_rcc.c 和
stm32f4xx_rcc.h 文件,是 STM32F4 标准的外设库文件。
misc.c 和 misc.h
目录
Libraries\STM32F4xx_StdPeriph_Driver。
介绍
misc.c 和 misc.h 是定义中断优先级分组以及 Systick 定时器相关的函数。
stm32f4xx_rcc.h
目录
Libraries\STM32F4xx_StdPeriph_Driver。
介绍
stm32f3xx_rcc.c 和 stm32f4xx_rcc.h 是**与 RCC 相关的一些操作函数,作用主要是一些时钟的配置和使能。**在任何一个 STM32 工程 RCC 相关的源文件和头文件是必须添加的。
stm32f4xx_ppp.c 和 stm32f4xx_ppp.h
目录
Libraries\STM32F4xx_StdPeriph_Driver。
介绍
对于文件 stm32f4xx_ppp.c 和 stm32f4xx_ppp.h,这就是 stm32F4 标准外设固件库对应的源文件和头文件。包括一些常用外设 GPIO,ADC,USART 等。
Application.c
目录
一般在keil搭建工程的User文件夹。
介绍
文件 Application.c 实际就是说是应用层代码。这个文件名称可以任意取了。我们工程中,直接取名为 main.c文件。
startup_stm32f40_41xxx.s
目录
\STM32F4xx_DSP_StdPeriph_Lib_V1.4.0\Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm。
介绍
对于不同型号的 STM32F4 系列对应的启动文件也不一样。我们的开发板是 STM32F407 系列所以我们选择的启动文件为startup_stm32f40_41xxx.s。
启动文件的作用是引导进入main 函数。Reset_Handler 中断函数是唯一实现了的中断处理函数,其他的中断函数基本都是死循环。Reset_handler 在我们系统启动的时候会调用,下面让我们看看 Reset_handler 这段代码:
;Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
这段代码的作用是在系统复位之后引导进入 main 函数,**同时在进入 main 函数之前,首先要调用 SystemInit 系统初始化函数。**后面我们会介绍怎样建立基于 V1.8 版本固件库的工程模板。
keil5 STM32固件库工程创建
目录结构
根目录
在建立工程前,我们建议大家在电脑的某个目录下建立一个文件夹,如:STM32F4_CODE作为该开发板所有工程的根目录**。后面所有创建的关于该开发板的工程都可以放在该文件夹下面。
子目录
所有工程都需要用到一些公共的文件,如:stm32固件库等,所以我们在根目录下面创建几个子目录:CORE,OBJ,FWLIB,SYSTEM,USER。至于这些文件夹名字,实际上是可以任取的,我们这样取名只是为了方便识别。对于这些文件夹用来存放什么文件,我们后面的步骤会一一提到。
CORE:
该目录存放启动文件和与内核相关的代码文件;
FWLIB:
该目录存放STM32固件库的源代码文件;
OBJ
该目录存放编译后可下载到开发板的hex文件;
SYSTEM:
该目录存放一些用户常用的通用模块(如:延时,定时器等);
USER:
该目录存放用户的工程代码文件(建议大家每个工程在USER目录下面建一个src目录);
拷贝公用文件
把公用的文件拷贝到相应的目录下去
CORE目录存放的文件
把启动文件和内核相关的头文件拷贝到我们建立的CORE目录下去,如下:
startup_stm32f40_41xxx.s: 启动文件,在STM32官方固件库的目录: **STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm****下
core_cmd4.h:
core_cmFunc.h:
core_cmInstr.h:
core_cmSimd.h:
以上几个文件在STM32官方固件库的目录:STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries\CMSIS\Include
拷贝完成
CORE目录下文件如图:
FWLIB目录存放的文件
把STM32官方的固件库里的源码文件拷贝到FWLIB目录下去
把STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries\STM32F4xx_StdPeriph_Driver下的文件夹inc和src*拷贝到我们建立的FWLIB 目录下去。
src 存放的是固件库的.c 文件,inc 存放的是对应的.h 文件,您不妨打开这两个文件目录过目一下里面的文件,每个外设对应一个.c 文件和一个.h 头文件。
拷贝完成
建立Keil用户工程
以上两个步骤做完后,就可以建立用户自己的工程啦**,而且以后也无须重复上面两个步骤, 因为基于该芯片的所有的工程代码都需要上面两个文件夹的代码。
工程专用文件夹
在创建工程前,建议大家在USER目录下,建立一个以工程名命名的文件夹,如project_1,后面有关该工程的所有文件都放在该目录下,如图:
?
创建工程
打开Keil,点击 “Project”-> “New uVision Project…”创建一个新工程界面如下:
自定义工程名
接下来,选择工程文件存放目录,给工程取个名字,再保存如下图:
选择芯片型号
安装对应的芯片包
一定要安装对应的器件 pack 才会显示选择芯片的选项**!!**
选择芯片型号
接下来,会弹出一个“Device”界面,定位到STMicroelectronics 下面的 STM32F407ZG(针对我们的 ExplorerSTM32 板子是这个型号)。选择我们的芯片型号STMicroelectronics→STM32F4 Series→STM32F407→STM32F407ZG,点“OK”(如果使用的是其他系列的芯片,选择相应的型号就可以了,例如我们的战舰 STM32 开发板是STM32F103ZE**。**)如下图:
配置运行环境
接下来,会出现一个“Manage Run-Time Environment”的界面,这是 MDK5 新增的一个功能,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们不做介绍。该步骤可以省略,直接点“Cancel”即可:
工程搭建完成
查看工程目录下的文件
USER/project_1目录文件
接下来,我们看看USER/project_1目录下面包含如下几个文件,如下图:
工程管理文件
这些文件,都是KEIL自动帮我们创建的,其中**project_1.uvprojx是keil工程管理文件,**非常关键,不能轻易删除,MDK51.4生成的工程文件是以.uvprojx 为后缀。
Listings 和 Objects 文件夹
Listings 和 Objects 文件夹是 MDK 自动生成的文件夹,用于存放编译过程产生的中间文件。
建立src文件夹
另外为了方便管理和结构清晰,我建议大家在project_1目录下创建一个src的文件夹,用于存放我们自己的代码文件,如下图:
Src下的文件
把应用模板代码文件拷贝到 project_1/src下面:
? stm32f4xx.h:
? system_stm32f4xx.h:
这两个头文件是STM32F4 工程非常关键的两个头文件。在目录STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries\CMSIS\Device\ST\STM32F4xx\Include下。
? stm32f4xx_conf.h: 配置文件
? stm32f4xx_it.c: 包含中断处理源文件
? stm32f4xx_it.h: 包含各中断处理函数原型及声明的头文件
? main.c: main函数入口
? main.h: 头文件
? **system_stm32f4xx.c:**系统时钟树初始化,PLL配置,初始化flash等
上面几个文件是,每个stm32应用程序都需要的文件,在STM32官方库模板STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Project\STM32F4xx_StdPeriph_Templates我们可以直接拷贝过来。如下图:
增加功能代码
我们在这些应用代码的基础上,增加我们功能代码即可。
工程文件管理
前面的这些步骤,只是把相关的代码文件拷贝到相应的目录下面而已,Keil工程根本不知道有这些代码,所以我们需要把相应的代码文件加入到keil工程中去。按如下步骤来:
打开工程分组
在keil中打开我们的工程,在左边的工程界面,右击“Target 1”-> 选中“Manage Project Items**…”,如下图:
添加分组和源文件
按照我们之前的建议,我们可以把一个keil5工程的代码分为四组:
CORE: 这个代码分组主要是芯片的启动文件,以及与内核相关的头文件
FWLIB: 这个代码分组主要是STM32官方库代码
SYSTEM: 这个代码分组主要存一些通用系统功能模块代码
USER: 这个代码分组就是存用户应用程序框架代码
? 而且这些代码分组的基本的源代码文件,已经在相应的目录下面了,我们只需要在“Manage Project Items**…”这个界面增加分组和增加相应的源文件就可以了。
新建分组文件夹
点击“Manage Project Items…”这个功能界面主要是为工程添加代码分组,以及为每个代码分组添加源代码文件.
Project Targets 一栏,我们可以将 Target 名字修改为 Template,然后在 Groups 一栏删掉一个 Source Group1,建立三个 Groups:USER,CORE,FWLIB。然后点击 OK,可以看到我们的 Target名字以及 Groups 情况如下图其界面如下:
CORE分组及其源码文件
下图所示为增加CORE分组及为该分组增加源码文件:
(注意,默认添加的时候文件类型为.c,也就是添加 startup_stm32f40_41xxx.s 启动文件的时候,你需要选择文件类型为 All files才能看得到这个文件 )
FWLIB分组及其源代码文件
下面增加FWLIB分组,FWLIB分组的源代码文件,就是STM32官方库的源码文件。
点击“Add Files…”然后所有的文件选中(Ctrl+A),前面创建的目录FWLIB/src目录下面所有 .c文件以及FWLIB/inc目录下面所有的.h文件**,然后点击 Add,然后 Close.可以看到 Files 列表下面包含我们添加的文件,如下图:
但是有一个文件 stm32f4xx_fmc.c掉,不要删掉 stm32f4xx_fsmc.c比较特殊。这个文件是STM32F42和STM32F43系列才用到,在我们目前的芯片(STM32F407)上面用不到,所以我们在这里把它从FWLIB分组的源码文件列表中删除。
这里需要说明一下,对于我们写代码,**如果我们只用到了其中的某个外设,我们就可以不用添加没有用到的外设的库文件。**例如我只用 GPIO,我可以只用添加stm32f4xx_gpio.c 而其他的可以不用添加。这里我们全部添加进来是为了后面方便,不用每次添加,当然这样的坏处是工程太大,编译起来速度慢,用户可以自行选择。
USER分组及其源代码文件
再按同样的方法,增加USER分组,源码列表(USER/project_1/src目录下面的.c/.h文件),如下图所示:除stm32f4xx,system_stm32f4xx两个文件。
SYSTEM分组及其源代码文件
(待创建,目前该分组下面没有源码文件)
HARDWARE分组及其源代码文件
(待创建,目前该分组下面没有源码文件)
工程文件分组完成
添加完分组和源码文件后,点击“OK”, 工程列表如下:
至此,工程管理的源码文件就都添加完毕了。下面就需要配置keil工程,来编译了。
编译keil工程
添加头文件路径
进入添加路径
keil编译时需要指定头文件的搜索路径
?
添加路径
根据我们的工程实际来增加头文件的路径,如我的例子上面需要增加三个头文件的路径: CORE, FWLIB\inc, USER\project_1\src,这里大家务必要仔细,固件库存放的头文件子目录是\FWLIB\inc,不是 FWLIB\src。**很多朋友都是这里弄错导致报很多奇怪的错误。**增加完后的界面如下:
后面点出“OK”就可以完成头文件搜索路径的添加了。
生成HEX文件
编译工程的时候,我们一般需要生成 Hex文件,以方便后面烧写程序。在编译之前我们首先要选择编译中间文件编译后的存放目录。
默认文件夹
USER\project_1下的Objects文件夹
添加全局宏定义
对于STM32F40系列的工程,我们还需要添加两个全局宏定义标识符。
添加方法是:点击图标 -> 点击**选项,然后在“Define”输入框内,输入:STM32F40_41xxx,USE_STDPERIPH_DRIVER。请大家注意这是两个宏标识符 STM32F40_41xxx和USE_STDPERIPH_DRIVER,它们之间用逗号分隔。如下图所示:
点击“OK”即可。
自定义文件夹
方法是删除USER\project_1下的Objects文件夹。点击魔术棒 ,然后选择“Output”选项下面的“Select folder for objects…”,然后选择目录为我们上面新建的 OBJ 目录。
配置选项
同时将下方的三个选项框都勾上,按下步骤:
这里说明一下步骤 4 的意义。
Create HEX File 选项选上是要求编译之后生成 HEX 文件。
Browse Information 选项选上是方便我们查看工程中的一些函数变量定义。
修改必要的文件
我们要将 USER 分组下面的 stm32f4xx_it.c 文件内容清空。
stm32f4xx_it.c 文件
删除32行
或者删掉其中的 32 行对main.h 头文件的引入
删除144行
以及 144 行 SysTick_Handler 函数内容,
System_stm32f4xx.c 文件
修改时钟参数PLL_M
这里还有个非常重要的关键点,就是系统时钟的配置,这里我们要修改 System_stm32f4xx.c 文件,把 PLL 第一级分频系数 M 修改为 8,这样使主时钟频率为 **168MHz。**修改方法如下:
/************* PLL Parameters ******/
\#if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx)
|| defined (STM32F401xx)
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
**#define PLL_M 8****//****PLL_M 这里我们要修改为 8,这样我们的系统时钟就是 168MHz。**
\#else /* STM32F411xE */
\#if defined (USE_HSE_BYPASS)
\#define PLL_M 8
\#else /* STM32F411xE */
\#define PLL_M 16
\#endif /* USE_HSE_BYPASS */
\#endif
stm32f4xx.h文件
同时,我们要在 stm32f4xx.h 里面修改外部时钟 HSE_VALUE 值为 8MHz,因为探索者开发板的外部高速时钟用的晶振为8M,修改为符合我们硬件的值即可。具体修改方法如下:
#if !defined (HSE_VALUE)
\#define HSE_VALUE ((uint32_t)**8000000**) /*!< Value of the External oscillator in Hz */
\#endif /* HSE_VALUE */
编译测试
Main()内容替换
在编译之前,我们先把 main.c 文件里面的内容替换为如下内容,直接复制即可。非探索者开发板可用其他代码测试。(注意在代码最后添加一个换行,否则会有警告):
#include "stm32f4xx.h"
void Delay(__IO uint32_t nCount);
void Delay(__IO uint32_t nCount)
{
while(nCount--){}
}
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOF, &GPIO_InitStructure);
while(1){
GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
Delay(0x7FFFFF);
GPIO_ResetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
Delay(0x7FFFFF);
}
}
编译
点击编译按键[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ecsXfEh6-1626354285355)(image-20210715201737515.png)],进行编译,结果界面如下:
编译完成的中间文件及可执行文件(xxx.hex)默认在目录project_1/Objects/目录下如果修改了hex文件目录为OBJ如下图所示**。**
将 hex 文件下载到开发板,会发现两个 led 灯不停的闪烁。
添加常用源文件
SYSTEM文件夹
实际上经过前面的步骤,我们的工程模板已经建立完成。但是在我们通常有一个 SYSTEM 文件夹,存放的是我们每个工程都要使用到的共用代码,分别为 sys,usart,delay。
工程举例
以正点原子实验 0 Template 工程模板为例。
找到模板中的文件
首先,打开实验 0 Template 工程模板的工程目录如下:
可以看到有一个 SYSTEM 文件夹,进入 SYSTEM 文件夹,里面有三个子文件夹分别为
**delay,sys,usart,**每个子文件夹下面都有相应的.c 文件和.h 文件。
复制到创建的工程中
我们将 SYSTEM 文件夹和里面的三个子文件夹复制到我们刚才创建的工程根目录中。如下图。
添加到工程分组
将这三个目录下面的源文件加入到工程分组,在工程中新建一个组,命名为 SYSTEM,然后加入这三个文件 夹下面的**.c** 文件分别为 sys.c,delay.c,usart.c
然后点击“OK”之后可以看到工程中多了一个 SYSTEM 组,下面有 3 个.c 文件。
添加头文件路径
将头文件路径加入到 PATH 中,用之前讲解的编译keil工程第一步的方法。
最后点击 OK。这样我们的工程模板就彻底完成了。
|