5.2.1、STM32Cube和HAL库模式开发流程
5.2.1.1、流程介绍
(1)环境搭建:STM32CubeMX安装、STM32xxFW安装、MDK5安装、pack包安装
(2)STM32CubeMX中创建工程、选择芯片型号、做图形化配置
(3)生成MDK版Project
(4)MDK5中打开Project,开始正式开发
5.2.1.2、实战演练
(1)打开stm32CubeMX软件后,new Project(创建工程)
(2)MCU Selector(mcu型号选择:stm32L476RGT6),设置好后点击:Part No下面对应的型号“双击”。
(3)四个系列设置:Pinout(引脚设置)、Clock Configuration(时钟配置)、Configuration(外设使能配置)、Power Consumption Calculator.(功耗计算)
(4)配置好后,在菜单栏中点击“project”-“setting”
project Nama(工程名字)/Project Location(工程地址)/Toolchain IDE(MDK-arm V5)
(5)生成工程项目:Generate code
5.2.1.3、几个小细节
(1)自动生成的Project目录结构和名字等都是既定的,最好不要改。
(2)由CubeMX工程到MDK工程师单向的,不能逆向同步
(3)最好在CubeMX中一次配完一个模块,在生成MDK工程,因为如果再次生成则会覆盖掉之前生成的MDK工程中同一个模块c文件,这样如果你刚好又已经编辑过了那部分就丢了
(4)STM32CubeMX工具只是生成工程和外设初始代码,大量开发工作还是要靠自己的。
(5)HAL库是一套体系,有自己的架构,必须理解透彻,否则会无处下爪的感觉
(6)因为HAL库很庞大,整个编译一次很久,所以建议要点build而不是rebuild
5.2.2、STM32CubeMX生成的工程解读
5.2.2.1、工程目录介绍
(1)查看stm32CubeMX生成的工程文件
·Drivers
·CMSIS
·Device
·DSP_Lib
·Include
·Lib
·RTOS
·STM32L4xx_HAL_Driver
·Inc
·Src
·Inc
main.h
stm32l4xx_hal_conf.h
stm32l4xx_it.h
·MDK-ARM
·DebugConfig
·RTE
·TEST
TEST.uvprojx
·Src
main.c
stm32l4xx_hal_msp.c
stm32l4xx_it.c
system_stm32l4xx.c
5.2.2.2、工程配置项细节
5.2.2.3、源码分析与学习方法
(1)先理清条理,搞清楚是怎么从Cube配置到MDK工程的
(2)建立SI工程,协助分析HAL库源码
(3)先从时钟、gpio等模块学起,掌握这套体系架构
(4)逐步扩展到其他外设模块,学习HAL库的使用
5.2.3、STM32HAL源码分析1
5.2.3.1、SI工程建立
5.2.3.2、从启动代码开始
5.2.3.3、main函数分析
*************************************************************************************************************************
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
******************************************************************************************************************
5.2.4、STM32HAL源码分析2
5.2.4.1、HAL_Init函数详解
*****************************************************************************************************************
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch, Instruction cache, Data cache */
/* Default configuration at reset is: */
/* - Prefetch disabled */
/* - Instruction cache enabled */
/* - Data cache enabled */
#if (INSTRUCTION_CACHE_ENABLE == 0)
__HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
#endif /* INSTRUCTION_CACHE_ENABLE */
#if (DATA_CACHE_ENABLE == 0)}
********************************************************************************************************************
5.2.5、STM32HAL源码分析3
5.2.5.1、SystemClock_Config
*******************************************************************************************************************
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Initializes the CPU, AHB and APB busses clocks */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 40;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the main internal regulator output voltage */}
***************************************************************************************************************
5.2.5.2、MX_GPIO_Init
***************************************************************************************************************
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
/*
do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN); \
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN); \
UNUSED(tmpreg); \
} while(0)
}
do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN); \
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOAEN); \
UNUSED(tmpreg); \
} while(0)
********************************************************************************************************
5.2.6、STM32Cube和HAL库点亮LED实战
5.2.6.1、在CubeMX工具中的开发
(1)查看原理图确定LED对应的GPIO号,USE_LED对应PB2
(2)CubeMX新建工程兵配置GPIO
(3)配置工程,并生成MDK project
5.2.6.2、在MDK5中开发
(1)找到main函数中的while处
(2)查看GPIO的HAL库函数,添加LED操作代码
*******************************************************************************************************
//500ms点亮一次LED灯。
while (1)
{
HAL_GPIO_WritePin(USR_LED_GPIO_Port, USR_LED_Pin, GPIO_PIN_RESET);
/* USER CODE END WHILE */
HAL_Delay(500);
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(USR_LED_GPIO_Port, USR_LED_Pin, GPIO_PIN_SET);
HAL_Delay(500);
}
********************************************************************************************************
(3)精确延时用HAL_Delay函数
*******************************************************************************************************
#define HAL_MAX_DELAY 0xFFFFFFFFU
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a period to guaranty minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait++;
}
while((HAL_GetTick() - tickstart) < wait)
{
}
}
*************************************************************************************************
5.2.6.3、烧录到开发板并运行
(1)STLINK接线(SWDIO、SWCLK、GND)
(2)MDK中debug中配置是用STLINK调试和下载,注意选择正确的flash烧录算法
(3)烧录并运行,注意板子供电用CROUSB或电池供电
5.2.7、STM32Cube和HAL库时钟设置实战
5.2.7.1、实验1:更改时钟频率设置
(1)先备份原来的main.c和其他时钟相关部分
(2)更改主时钟到80MHz并重新生产工程,重新编译烧录运行看效果
(3)对比新生成的时钟代码部分和以前的
(4)额外实验:可以在main.c的while循环中各部分添加自定义代码,看哪些不会被覆盖
5.2.7.2、实验2:使用外部晶振
(1):打开HSE实验
(2):打开LSE实验
5.2.8、STM32Cube和HAL库GPIO实战
5.2.8.1、HAL库中GPIO驱动详解
********************************************************************************************************
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
/** @addtogroup GPIO_Exported_Functions_Group2 IO operation functions
/* IO operation functions *****************************************************/void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
*****************************************************************************************************
5.2.8.2、GPIO实战
(1)保存初始MDK工程
(2)查看原理图确定其余2个LED的引脚:SD_EN对应PA15,GPS_EN对应的PB12
(3)在CubeMX中配置
(4)重新生成MDK project
(5)对比新生成的GPIO部分代码和以前的
(6)编译烧录执行验证
5.2.9、HAL库体系的头文件包含
(1)分析main.h
(2)分析STM32L4xx_hal.h
5.2.9.1、从main包含的头文件说起
第一条线:main.c中包含stm32L4xx_hal.h,再包含了stm32L4xx_hal_conf.h,然后再包含了各个模块的hal库头文件。
第二条线:只要包含了stm32L4xx.h,就会间接包含到所对应系列型号的STM32L4476xx.h
stm32L4xx_gpio.h->stm32L4_hal_def.h->stm32L4xx.h->stm32L476xx.h