1、定义了HSE时钟频率的值
2、定义了启动HSE时钟的超时时间,HSI时钟频率的值
上诉的HSE_VALUE、HSE_STARTUP_TIMEOUT、HSI_VALUE 会在 system_stm32f4xx.c 中使用。
3、根据不同的芯片定义中断向量表结构体
4、包含一些头文件
5、重定义
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
typedef const int32_t sc32; /*!< Read Only */
typedef const int16_t sc16; /*!< Read Only */
typedef const int8_t sc8; /*!< Read Only */
typedef __IO int32_t vs32;
typedef __IO int16_t vs16;
typedef __IO int8_t vs8;
typedef __I int32_t vsc32; /*!< Read Only */
typedef __I int16_t vsc16; /*!< Read Only */
typedef __I int8_t vsc8; /*!< Read Only */
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef const uint32_t uc32; /*!< Read Only */
typedef const uint16_t uc16; /*!< Read Only */
typedef const uint8_t uc8; /*!< Read Only */
typedef __IO uint32_t vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t vu8;
typedef __I uint32_t vuc32; /*!< Read Only */
typedef __I uint16_t vuc16; /*!< Read Only */
typedef __I uint8_t vuc8; /*!< Read Only */
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
6、为每个外设声明一个结构体类型,结构体中是外设的所有寄存器
typedef struct
{
__IO uint32_t SR; /*!< ADC status register, Address offset: 0x00 */
__IO uint32_t CR1; /*!< ADC control register 1, Address offset: 0x04 */
__IO uint32_t CR2; /*!< ADC control register 2, Address offset: 0x08 */
__IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x0C */
__IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x10 */
__IO uint32_t JOFR1; /*!< ADC injected channel data offset register 1, Address offset: 0x14 */
__IO uint32_t JOFR2; /*!< ADC injected channel data offset register 2, Address offset: 0x18 */
__IO uint32_t JOFR3; /*!< ADC injected channel data offset register 3, Address offset: 0x1C */
__IO uint32_t JOFR4; /*!< ADC injected channel data offset register 4, Address offset: 0x20 */
__IO uint32_t HTR; /*!< ADC watchdog higher threshold register, Address offset: 0x24 */
__IO uint32_t LTR; /*!< ADC watchdog lower threshold register, Address offset: 0x28 */
__IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x2C */
__IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x30 */
__IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x34 */
__IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x38 */
__IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x3C */
__IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x40 */
__IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x44 */
__IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x48 */
__IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x4C */
} ADC_TypeDef;
typedef struct
{
__IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */
__IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */
__IO uint32_t CDR; /*!< ADC common regular data register for dual
AND triple modes, Address offset: ADC1 base address + 0x308 */
} ADC_Common_TypeDef;
...
...
...
...
7、内存地址分布
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000)
/*!< APB1 peripherals */
#define TIM2_BASE (APB1PERIPH_BASE + 0x0000)
#define TIM3_BASE (APB1PERIPH_BASE + 0x0400)
#define TIM4_BASE (APB1PERIPH_BASE + 0x0800)
#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00)
#define TIM6_BASE (APB1PERIPH_BASE + 0x1000)
#define TIM7_BASE (APB1PERIPH_BASE + 0x1400)
...
...
...
8、对每一个外设的基地址进行相应的结构体类型指针的强制类型转化,然后进行宏定义,这样就可以很轻松的对外设的寄存器进行操作。
#define TIM2 ((TIM_TypeDef *) TIM2_BASE)
#define TIM3 ((TIM_TypeDef *) TIM3_BASE)
#define TIM4 ((TIM_TypeDef *) TIM4_BASE)
#define TIM5 ((TIM_TypeDef *) TIM5_BASE)
#define TIM6 ((TIM_TypeDef *) TIM6_BASE)
#define TIM7 ((TIM_TypeDef *) TIM7_BASE)
#define TIM12 ((TIM_TypeDef *) TIM12_BASE)
#define TIM13 ((TIM_TypeDef *) TIM13_BASE)
#define TIM14 ((TIM_TypeDef *) TIM14_BASE)
#define RTC ((RTC_TypeDef *) RTC_BASE)
#define WWDG ((WWDG_TypeDef *) WWDG_BASE)
#define IWDG ((IWDG_TypeDef *) IWDG_BASE)
#define I2S2ext ((SPI_TypeDef *) I2S2ext_BASE)
#define SPI2 ((SPI_TypeDef *) SPI2_BASE)
#define SPI3 ((SPI_TypeDef *) SPI3_BASE)
9、对外设寄存器的位进行定义
10、包含stm32f4xx_conf.h
11、定义一些宏函数来方便开发人员对寄存器进行操作
1、包含一些头文件
#include /* 标准类型定义 */
#include /* 核心指令的访问 */
#include /* 核心功能的访问 */
#include /* 编译器特有的SIMD内联函数 */
2、关键字的重定义
3、定义内核中外设的结构体,例如常用的NVIC、SysTick
4、提供了使用 NVIC的一些函数,但是这些库函数我们在编程的时候用的都比较少,甚至基本都不用。一般我们在配置中断的 NVIC 是使用 misc.c 中的 NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)函数和NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)函数。
5、提供SysTick定时器计数初值配置函数
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } /* Reload value impossible */
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
1、包含ST库的外设文件
这个文件被包含进 stm32f4xx.h 文件。ST标准库支持所有STM32F4 型号的芯片,但有的型号芯片外设功能比较多,所以使用这个配置文件根据芯片型号增减 ST库的外设文件。针对 STM32F429 和 STM32F427 型号芯片的差异,它们实际包含不一样的头文件,我们通过宏来指定芯片的型号。
#include "stm32f4xx_adc.h"
#include "stm32f4xx_crc.h"
#include "stm32f4xx_dbgmcu.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_flash.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_i2c.h"
#include "stm32f4xx_iwdg.h"
#include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_rtc.h"
#include "stm32f4xx_sdio.h"
#include "stm32f4xx_spi.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_wwdg.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
#if defined (STM32F429_439xx) || defined(STM32F446xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_ltdc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F429_439xx || STM32F446xx */
2、 stm32f4xx_conf.h这个文件还可配置是否使用“断言”编译选项
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
在 ST 标准库的函数中,一般会包含输入参数检查,即上述代码中的“assert_param”宏,当参数不符合要求时,会调用“assert_failed”函数,这个函数默认是空的。
实际开发中使用断言时,先通过定义 USE_FULL_ASSERT 宏来使能断言,然后定义“assert_failed”函数,通常我们会让它调用 printf函数输出错误说明。使能断言后,程序运行时会检查函数的输入参数,当软件经过测试,可发布时,会取消 USE_FULL_ASSERT宏来去掉断言功能,使程序全速运行。
system_stm32f4xx.h就是对一些时钟相关的函数进行声明,具体的函数实现在system_stm32f4xx.c中。
(1)对PLL参数进行设置
#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 25
#elif defined (STM32F446xx)
#define PLL_M 8
#elif defined (STM32F411xE)
#if defined(USE_HSE_BYPASS)
#define PLL_M 8
#else
#define PLL_M 16
#endif /* USE_HSE_BYPASS */
#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx */
/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
#define PLL_Q 7
#if defined(STM32F446xx)
/* PLL division factor for I2S, SAI, SYSTEM and SPDIF: Clock = PLL_VCO / PLLR */
#define PLL_R 7
#endif /* STM32F446xx */
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx)
#define PLL_N 360
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 2
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx || STM32F446xx */
#if defined(STM32F401xx)
#define PLL_N 336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 4
#endif /* STM32F401xx */
#if defined(STM32F411xE)
#define PLL_N 400
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 4
#endif /* STM32F411xx */
(2)定义各个芯片的系统时钟频率
#if defined(STM32F40_41xxx)
uint32_t SystemCoreClock = 168000000;
#endif /* STM32F40_41xxx */
#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx)
uint32_t SystemCoreClock = 180000000;
#endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx */
#if defined(STM32F401xx)
uint32_t SystemCoreClock = 84000000;
#endif /* STM32F401xx */
#if defined(STM32F411xE)
uint32_t SystemCoreClock = 100000000;
#endif /* STM32F401xx */
(3)初始化跟系统时钟配置相关的寄存器函数
void SystemInit(void)
(4)设置系统时钟函数
static void SetSysClock(void)
(5)void SystemCoreClockUpdate(void)函数
这个暂时不用管,主要是上面两个函数,在单片机上电后会调用SystemInit函数,在SystemInit中会调用SetSysClock函数,从而完成系统时钟的配置。