创建基于HAL库的空项目
为了更贴近实际生产的项目结构, 修改项目目录结构
创建目录结构如下:
├─Drivers ----------------------------- 官方HAL库, SMSIS启动文件等
│ ├─CMSIS
│ │ └─Include
│ └─STM32L4xx_HAL_Driver ------------- HAL库
│ ├─Inc
│ └─Src
├─Inc -------------------------------- 应用头文件
├─MDK-ARM ----------------------------- Keil工程及编译中间文件
└─Src --------------------------------- 应用源文件
拷贝文件
From:
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\CMSIS\Include
拷贝整个Include文件夹
To:
Test04\Drivers\CMSIS\Include
From:
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\CMSIS\Device\ST\STM32L4xx\Include
在这个目录下拷贝如下3个文件
stm32l4xx.h
stm32l475xx.h
system_stm32l4xx.h
To:
Test04\Drivers\CMSIS\Include
From:
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\arm\startup_stm32l475xx.s
To:
Test04\Drivers\CMSIS\Include
From:
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\STM32L4xx_HAL_Driver\Inc
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\STM32L4xx_HAL_Driver\Src
Inc和Src目录整体拷贝
To:
Test04\Drivers\STM32L4xx_HAL_Driver
From:
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\system_stm32l4xx.c
To:
重命名为 stm32l4xx_hal_conf.h
Test05\Inc\stm32l4xx_hal_conf.h
From:
stm32cubel4_v1-18-0\STM32Cube_FW_L4_V1.18.0\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_conf_template.h
To:
Test05\Inc\stm32l4xx_hal_conf.h
编写代码
stm32-world\Test04\Inc\main.h
c
#ifndef MAIN_H
#define MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32l4xx_hal.h"
#ifdef __cplusplus
}
#endif
#endif
stm32-world\Test04\Src\main.c
c
#include "main.h"
int main(void) {
HAL_Init(); // 1. 初始化HAL库(配置SysTick等)
while (1) {
}
}
stm32-world\Test04\Inc\stm32l4xx_it.h
c
#ifndef __STM32L4xx_IT_H
#define __STM32L4xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* 核心:SysTick 中断,每 1ms 触发一次,用于 HAL_Delay() */
void SysTick_Handler(void);
#ifdef __cplusplus
}
#endif
#endif /* __STM32L4xx_IT_H */
stm32-world\Test04\Src\stm32l4xx_it.c
c
#include "stm32l4xx_it.h"
#include "stm32l4xx_hal.h"
void SysTick_Handler(void) {
HAL_IncTick(); // 每1ms触发一次,增加HAL计数值
}
系统时钟初始化
使用HAL库实现前文:
STM32L475基于完全空白的项目,完成时钟树初始化配置并验证
同样的操作.
bsp_clock.c
c
#include "bsp_clock.h"
#include "stm32l4xx_hal.h"
#include "stm32l4xx_hal_rcc.h"
#include "stm32l4xx_hal_pwr.h"
#include "stm32l4xx_hal_flash.h"
/**
* @brief 系统时钟 HSE (8MHz) -> PLL -> 80MHz
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 1. 配置主调压器输出电压以支持 80MHz 频率 (Range 1) */
__HAL_RCC_PWR_CLK_ENABLE();
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
// TODO:: 错误处理
// Error_Handler();
}
/* 2. 配置 HSE 并初始化 PLL */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 选择晶振类型为外部高速晶振
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 开启外部晶振
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 开启PLL锁相环
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL时钟源为外部晶振
/* 8MHz(HSE) / 1(M) * 20(N) / 2(R) = 80MHz */
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
// TODO:: 错误处理
// Error_Handler();
}
/* 3. 配置系统时钟源 (SYSCLK) 及总线分频 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK
| RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1
| RCC_CLOCKTYPE_PCLK2; // 指定分频操作所覆盖的总线类型
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 选择PLL为主时钟
// 显式地设置AHB和APB预分频器对应的总线频率
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 80MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // 80MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 80MHz
/* 4. 设置 Flash 等待周期 */
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
// TODO:: 错误处理
// Error_Handler();
}
}
上述代码需要注意的是, 引入头文件时有顺序要求, 先引入stm32l4xx_hal.h, 然后再引入其他, 否则会报编译错误.
bsp_clock.h
c
#ifndef __BSP_CLOCK_H
#define __BSP_CLOCK_H
void SystemClock_Config(void);
#endif