STM32芯片编程指南(1)— 点亮LED
首先实现,使用STM32芯片点亮LED
以下是一个通用的示例,假设你使用的是STM32CubeIDE和CubeMX进行开发,并将LED连接到STM32的GPIO引脚上。
这个示例假设你将LED连接到了STM32的GPIO引脚PA5上。
#include "main.h"
#include "stm32f4xx_hal.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1) {
// 点亮LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_Delay(1000); // 延迟1秒
// 关闭LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_Delay(1000); // 延迟1秒
}
}
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 CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/** 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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
Error_Handler();
}
}
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
这段代码中,通过HAL_GPIO_WritePin()
函数控制了GPIO引脚PA5的电平,从而控制LED的点亮和关闭。在main()
函数的无限循环中,LED会每隔一秒交替点亮和关闭。
记得根据你的具体硬件连接和使用的STM32芯片型号进行必要的修改,包括修改引脚号、时钟设置等。此外,这个示例使用了HAL库函数,如果你使用的是其他库或者裸机编程,可能需要做相应的调整。
什么是HAL库
HAL库(Hardware Abstraction Layer)是由STMicroelectronics提供的一组预先编写好的函数,用于与STM32系列微控制器进行交互。这些函数封装了对硬件寄存器的访问,使得你可以更方便地编写代码而无需直接操作底层寄存器。
HAL库的优点在于它提供了一种抽象层,使得代码更易读、易写和可移植。它简化了与硬件的交互,允许你专注于应用程序的开发而不是底层硬件的细节。
你可以直接使用HAL库函数来开发STM32应用程序。ST提供了完整的文档和示例代码,帮助你了解如何使用这些函数。通常,你需要设置好硬件初始化,然后使用HAL库函数来操作GPIO、定时器、串口等外设,实现你的应用逻辑。
在使用HAL库时,需要包含对应的库文件,并进行相应的配置。使用CubeMX可以方便地生成初始化代码和配置,然后在IDE中使用HAL库函数来编写应用程序。
记住,尽管HAL库简化了开发流程,但有时在对性能或资源使用有严格要求的场景下,直接操作寄存器可能更为灵活和高效。选择使用HAL还是直接操作寄存器,取决于你的项目需求和个人偏好。
对SystemClock_Config的解释
SystemClock_Config
函数是用来配置STM32微控制器的系统时钟的函数。
在STM32中,系统时钟的配置非常重要,因为它决定了微控制器的运行速度和各种外设的时钟频率。
这个函数通常是由CubeMX自动生成的,用于初始化系统时钟。让我们来解释一下这个函数的主要部分:
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 配置主时钟源和PLL(锁相环) */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/* 配置系统时钟 */
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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
Error_Handler();
}
}
-
配置主时钟源和PLL:
RCC_OscInitStruct
结构体用于配置时钟源。在这个例子中,使用外部晶振(HSE)作为主时钟源,然后配置PLL来产生系统所需的时钟频率。这里设置了PLL的各种参数,比如分频器的值,以及输出频率等。HAL_RCC_OscConfig(&RCC_OscInitStruct)
调用函数应用这些配置并启动时钟源和PLL。
-
配置系统时钟:
RCC_ClkInitStruct
结构体用于配置系统时钟。在这个例子中,选择将系统时钟源设置为PLL输出,并且设置了AHB(高速总线)、APB1和APB2(外设总线)的分频器。HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5)
调用函数应用这些配置,并设置相应的FLASH存储器延迟以匹配新的时钟频率。
总的来说,SystemClock_Config
函数的目的是配置系统时钟源和时钟分频器,确保微控制器能够以期望的频率稳定运行。这样可以确保外设的时钟频率正确,并保证整个系统的稳定性和性能。
PLL(Phase-Locked Loop,相位锁定环是一种电路系统,用于产生稳定的输出信号,
其频率和相位与输入信号相关联。它是用于调整和稳定频率的重要电路组件,广泛应用于通信、计算机、数字信号处理和各种电子设备中。
PLL的工作原理:
基本组成部分:一个典型的PLL包括三个主要部分:相频比较器(Phase Detector)、电压控制振荡器(Voltage-Controlled Oscillator,VCO)、反馈回路(Feedback Loop)。
输入信号与VCO:输入信号与VCO连接,VCO产生一个频率可调的输出信号。
相频比较器:相频比较器检测输入信号和VCO输出信号之间的相位差异,并将这种差异转换成一个控制信号。
控制信号和VCO:控制信号被发送到VCO,用来调整VCO的输出频率,使得VCO输出的信号的相位和频率与输入信号匹配或者锁定。
反馈回路:将VCO输出信号反馈给相频比较器,使得它能够不断地检测和修正输入信号和VCO输出信号之间的相位差,以保持它们保持同步或锁定。
PLL的应用:
时钟生成:在数字电路中,PLL经常被用于产生精确的时钟信号,用于各种系统中的时序控制。
频率合成器:PLL可以将一个较低频率的参考信号转换成一个更高频率的输出信号。
通信系统:在调制解调器和无线通信中,PLL用于产生调制解调的本地振荡信号。
数字信号处理:用于时序同步和数据采样等方面。
对MX_GPIO_Init的解释
MX_GPIO_Init
是由 STM32CubeMX 自动生成的初始化函数之一,
用于初始化 STM32 微控制器的 GPIO(通用输入输出)引脚。
示例代码结构:
以下是一个示例代码结构,展示了一个由 STM32CubeMX 自动生成的 MX_GPIO_Init
函数:
void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/* Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
解释:
-
启用 GPIO 时钟:
__HAL_RCC_GPIOA_CLK_ENABLE()
:启用 GPIOA 端口的时钟。这个函数确保了你要使用的 GPIO 端口的时钟被启用,以便使用这些 GPIO 引脚。
-
配置 GPIO 引脚:
GPIO_InitStruct
是一个GPIO_InitTypeDef
结构体类型的变量,用于配置特定的 GPIO 引脚。GPIO_InitStruct.Pin = GPIO_PIN_5;
:指定要配置的引脚是 PA5。GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
:配置引脚为推挽输出模式。这意味着这个引脚可以输出高电平或低电平,而不是输入模式或开漏输出。GPIO_InitStruct.Pull = GPIO_NOPULL;
:禁用了上下拉电阻。这意味着在配置为输入模式时,引脚上不会有上拉或下拉电阻。GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
:设置引脚的速度为低速。这表示引脚的驱动能力较低。
-
设置引脚输出电平:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
:将 PA5 引脚的输出电平设置为低电平。在这里,GPIO_PIN_RESET
表示低电平。
-
初始化 GPIO 引脚:
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
:使用上述配置初始化 GPIOA 的引脚,这里是 PA5。
这个函数的作用是配置特定 GPIO 引脚的工作模式、输入/输出特性和电气特性。