第一次使用STM32F4系列,还是费了一番周折,下面把过程写下来,希望可以对大家有所帮助
1. Pack安装
在Keil官网下载了STM32F4系列的2.6.0版PACK,安装之后打开Keil提示错误,新建工程时也找不到相应的器件,上网查找一通,最后解决问题:Keil版本我的Keil5版本是5.12,下载了5.14版就可以了
2. 新建一个LED工程模板
由于习惯了之前STM32F1xx系列的工程管理方法,于是依样画葫芦,工程源文件目录如下
+ cmsis
core_cm4.h **
core_cmFunc.h **
core_cmInstr.h **
core_cmSimd.h **
startup_stm32f446xx.s ** 芯片启动后执行的代码
stm32f446xx.h ** stm32f446xx器件头文件,包含外设地址和结构体定义
stm32f4xx.h ** stm32f4xx系列头文件,根据Keil中Option->C/C++->Preprocessor Symbols ->Define 框中定义的器件来包含不同器件的头文件,如上面的446XX
system_stm32f4xx.c ** 包含系统初始化代码,初始化了FPU,中断向量表位置和外部存储
system_stm32f4xx.h **
+ fwlib
+ Legacy
stm32_hal_legacy.h ** 这个头文件主要用于STM32Cube,这里没什么用
stm32f4xx_hal.c ** 提供了一些通用的函数,如延时函数,DBG相关函数等
stm32f4xx_hal.h **
stm32f4xx_hal_cortex.c ** 提供了Cortex内核外设的相关函数,如NVIC,MPU,Systick Timer等
stm32f4xx_hal_cortex.h **
stm32f4xx_hal_外设.c 提供各外设的驱动库函数
stm32f4xx_hal_外设.h
+ bsp
自定义外设.c
自定义外设.h
+ user
main.c **
stm32f4xx_it.c ** 包含中断ISR函数,本工程只用了Systick_Handler
stm32f4xx_it.h **
stm32f4xx_hal_conf.h ** 工程配置头文件
以上文件中,后面有“**”的表示这个文件是模板工程必须的,后面有简单的说明,下面首先描述一下头文件的组织结构:main文件中只需要包含stm32f4xx_hal.h头文件(当然还可以包含自定义外设.h),这个头文件逐层包含了所有需要的头文件
+ stm32f4xx_hal.h //包含stm32f4xx_hal_conf.h
|---+ stm32f4xx_hal_conf.h //根据工程配置,包含相应的STM32外设头文件
|---+ stm32f4xx_hal_外设.h //每个外设头文件都包含stm32f4xx_hal_def.h
|---+ stm32f4xx_hal_def.h //包含stm32f4xx.h
|---+ stm32f4xx.h //包含特定器件头文件
|---+ stm32f446xx.h
|---- system_stm32f4xx.h
|---+ core_cm4.h
|---- core_cmInstr.h
|---- core_cmFunc.h
|---- core_cmSimd.h
LED工程配置
本工程的目标要实现以下功能:
(1)系统初始化之后使用HSI作为时钟源,并且工作在180Mhz
(2)用GPIO控制LED等以100ms的周期闪烁
为此,需要在stm32f4xx_hal_conf.h中使能以下模块:
#define HAL_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
其中使能Flash模块是要使用库函数设置Flash的等待周期等; 使能PWR模块是需要对电源进行设置使芯片能工作在180Mhz
另外别忘了在Keil中Option->C/C++->Preprocessor Symbols->Define 框中输入USE_HAL_DRIVER, STM32F446xx
3. 代码分析
启动代码
启动代码和stm32f1xx系列没有什么区别
上电复位后,进入ResetHandler,然后执行System_Init()函数
图1
图2
System_Init()函数执行以下操作:
(1)如果处理器支持FPU,使能FPU
(2)强处理器的时钟设为上电默认选择:内部16Mhz时钟,不开PLL
(3)如果使用外部RAM,初始化外部RAM控制
(4)设置中断向量是在SRAM或Flash中
从System_Init()函数退出后,进入用户main函数(中间还有一些C库的处理)
main函数中首先调用了HAL_Init()函数
图3
HAL_Init()函数执行以下操作:
(1)根据配置开启或关闭指令和数据Cache,Flash的Prefetch,这些配置字是在stm32f4xx_hal_conf.h文件中定义的
(2)设置NVIC的PriorityGroup为4bit表示抢占优先级,0bit表示子优先级
(3)设置Systick定时器中断周期为1ms,这个中断周期用来作为HAL_Delay()延时函数的时基,HAL_Delay()函数 将在接下来的一些初始化操作中使用
(4)调用HAL_MspInit()函数来初始化底层的硬件,注意这个函数用__weak关键字声明,内部为空,用户可以定义自己的HAL_MspInit()函数,函数名相同,这样自定义的函数将覆盖这里的HAL_MspInit()函数,在本工程中没有写这个函数,直接在Main函数中初始化了GPIO
main函数接下来调用了SystemClock_Config()函数,这个函数不是库函数,是Nucleo的Example中提供的SystemClock_Config()函数执行以下操作
图4
图5
(1)设置内核电压等级,当处理器运行频率不高时,可以通过软件设置不同的内核电压等级来减小功耗,注意设置只能在PLL关闭的情况下才能进行,在PLL打开时,新设置的内核电压等级生效,Scale等级越低,系统频率可以运行的越高,这里设为Scale1,因为下面要把系统时钟设为最大180Mhz
(2)接着选择HSI作为芯片时钟,并将PLL输出设为180Mhz,但这时系统时钟还未切换,系统还是工作在16Mhz的内部时钟
(3)使能电源管理的OverDrive,如果要运行在最高的频率,这一步是不可少的,注意这一位只能在选择HSI或HSE作为时钟时才能进行设置
(4)选择PLL输出作为系统时钟,AHB时钟设为180Mhz,APB2时钟设为90Mhz,APB1时钟设置为45Mhz,这些都是各总线的最高工作频率,这一步结束之后,系统就工作在了最高时钟频率180MHz,注意执行这一操作的最后会用新的系统时钟设置Systick定时器,使定时器的中断周期依旧为1ms
接下来就是纯粹的用户代码了,初始化GPIO来控制LED等
图6
(1)使能GPIOA的时钟(这里可以看出类,STM32F4xx的库和STM32F10x库不同的一点,模块时钟的使能和禁用都使用了宏定义,取代以前的函数)
(2)设置PA5的属性:推挽输出,上拉,速度等级为Fast(有4个等级Low,Medium,Fast和High),这些操作和STM32F10x没有什么不同
(3)每隔100ms翻转一下IO
|