用HAL库点亮一个LED灯
编程思路,代码,代码理解
芯片型号:
STM32F407ZGT6
参考文件:
F4 HAL库官方文档、STM32F4xx中文参考手册
基本思路:
点亮一个LED的最主要的就是控制LED对应的引脚的电平高低,如原理图可知:例如点亮LED_R,LED正极外界3.3V电压,则需要对PF6口输出低电平,即控制PF6_IO口输出低电平,形成电压差,从而点亮LED。
如原理图可知LED_R负极接芯片PF6口。
1、运用STM32CubeMX初始化
具体步骤:
①点击ACCESS TO MCU SELECTOR
②按上图所示步骤
在1处输入自己单片机型号 例如:STM32F407ZGT6。
在2处单机选择
在3处点击start project创建文件进入到配置界面
③初始化界面配置
1处可以搜索需要配置的功能,例如我需要配置IO口即可在此输入搜索GPIO
2处可以查看所有配置的列表
3处可视化芯片所有引脚
*******************************************
这种颜色表示不可配置引脚 电源专用引脚以黄色突出显示。其配置不能更改
这种颜色表示你配置了一个I/O口的功能,但是没有初始化相对应的外设功能 引脚处于no mode 状态
绿色表示配置成功
来源:【STM32】STM32CubeMX教程二--基本使用(新建工程点亮LED灯)_Z小旋的博客-CSDN博客
******************************************
4处可以搜索要用的引脚,搜索到后会在3处闪烁 例如搜索PF6,会出现如下左图
点击相应的引脚会显示出该引脚可配置的功能,点击所需要配置的功能即可,点击后出现如上右图。当右图可视化引脚冒绿光代表配置完成,可在中间框点击PF6配置更多参数。
(有需要可配置时钟初始化Clock Configuration;默认时钟选择的是内部HSI RC
-16Mhz)
1可配置时钟
2配置文件
根据自己的需要配置Name、文件位置、IDE
配置完Project后配置Code Generator
(我的一般配置)
配置的大致说明:
【STM32】STM32CubeMX教程二--基本使用(新建工程点亮LED灯)_Z小旋的博客-CSDN博客
配置完成后点击右上角GENERATE CODE生成文件如下图所示:
打开MDK-ARAM里的程序,进行第一次编译,可能会发现会有如下报错:
想要解决问题,需要在右侧Project处做如下操作:
双击Drivers/CMSIS文件,在官方下载的STM32Cube_FW_F4_V1.27.0文件夹里选择Drivers,然后选择CMSIS,然后选择Device,无脑点到底到有一个Source文件的目录下,点击Source,再无脑点到有三个文件夹构成的目录下,点击arm,寻找和自己型号匹配的启动文件,双击添加,搞定。
至此配置的初始化差不多了,可以开始写简单的电灯程序了:
③正式电灯:
main函数中的while循环(已经自动生成)
while (1) {
//对PF6口设置低电平
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_6,GPIO_PIN_RESET);
}
搞定!!
④由于我是第一次用HAL找不到看的爽的教程,所以尝试自己分析里面的内容。
附上主函数:
//main函数
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_6,GPIO_PIN_RESET);
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
HAL_StatusTypeDef HAL_Init(void) { /* Configure Flash prefetch, Instruction cache, Data cache */ #if (INSTRUCTION_CACHE_ENABLE != 0U) __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); #endif /* INSTRUCTION_CACHE_ENABLE */ #if (DATA_CACHE_ENABLE != 0U) __HAL_FLASH_DATA_CACHE_ENABLE(); #endif /* DATA_CACHE_ENABLE */ #if (PREFETCH_ENABLE != 0U) __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); #endif /* PREFETCH_ENABLE */ /* Set Interrupt Group Priority */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */ HAL_InitTick(TICK_INT_PRIORITY); /* Init the low level hardware */ HAL_MspInit(); /* Return function status */ return HAL_OK; }
HAL_Init();使能HAL
这个函数用于初始化HAL库;它一定是第一个在主程序中执行的指令,它执行以下操作:
*配置Flash预取,指令和数据缓存。
*配置SysTick每1毫秒产生一个中断,
*设置“NVIC组优先级”为“4”。
*调用用户文件中定义的HAL_MspInit()回调函数在“stm32f4xx_hal_msp.c”文件中的进行全局底层硬件初始化。
最后返回HAL使能的状态
SystemClock_Config();
顾名思义,系统时钟初始化
在这个函数中对RCC内/外振荡器(HSE, HSI, LSE和LSI)配置结构进行初始化
/** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;//使用内部竞争HSI RCC_OscInitStruct.HSIState = RCC_HSI_ON;//当然要开启HSI RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;//看不懂,默认就是这玩意 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;//锁相环结构参数 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); }
HAL_RCC_OscConfig(&RCC_OscInitStruct) 初始化配置的时钟,标准库里也有类似的操作,这个有返回值能判断是否初始化成功。如果没有初始化成功,进入到一个Error_Handler()函数,程序注释说的是可以自己编写错误报告在里面。
上面的初始化时钟在标准库编程中也有不同的实现。
/** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); }
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0)初始化CPU、
AHB、APB总线
同时也要配置总线时钟的结构体
和标准库编程一样分频差不多的配置,只不过在STM32CubeMX上配置好了
函数调用的第二个参数:FLatency:FLatency FLASH延迟时间,该参数取决于所选择的设备
同样可以判断是否配置完成。
然后有一个
MX_GPIO_Init();熟悉的GPIO初始化函数
void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOF_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET); /*Configure GPIO pin : PF6 */ GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); }
__HAL_RCC_GPIOF_CLK_ENABLE();熟悉的GPIO时钟使能
结构体配置也是和标准库函数一样的套路,能在STM32CubeMX生成
最后调用HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);将结构体写入。
和标准库一摸一样!!!!!!!!!
上述已经初始化完成了,能开始写简单的带灯了 so easy
while (1) { //对PF6口设置低电平 HAL_GPIO_WritePin(GPIOF,GPIO_PIN_6,GPIO_PIN_RESET); }
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_6,GPIO_PIN_RESET);
该函数作用是往这个指定的引脚写入低电平然后就能做到一直亮灯。
保存编译烧录and运行--->
效果:
总结:
电灯是最简单的一个案例,不管在标准库里编程还是HAL库里,找回了之前用标准库的感觉,原理大差不大,只不过调用的函数不同,配置过程有点差别,更加方便了。同时这个电灯程序让我了解基本的HAL库编程思路。
附:
STM32CubeF4 - STM32Cube MCU包,用于STM32F4系列(HAL、底层API和CMSIS(CORE、DSP和RTOS)、USB、TCP/IP、File system、RTOS和Graphic - 附带在以下ST板上运行的示例:STM32 Nucleo、探索套件和评估板) - 意法半导体STMicroelectronics