STMicroelectronics 系列:STM32L4 系列_(7).STM32L4系列的编程模型
STM32L4系列的编程模型
在上一节中,我们介绍了STM32L4系列的基本架构和特点。接下来,我们将深入探讨STM32L4系列的编程模型,包括其内存模型、中断系统、外设控制和低功耗特性等方面。
内存模型
STM32L4系列微控制器提供了丰富的内存资源,包括闪存(Flash)、静态随机存取存储器(SRAM)和系统存储器(System Memory)。了解这些内存资源的组织方式和访问方式对于高效编程至关重要。
闪存(Flash)
闪存主要用于存储程序代码和常量数据。STM32L4系列通常具有128KB到1MB的闪存容量,具体取决于不同的型号。闪存的访问速度较快,但写入和擦除速度较慢,且有写入次数的限制。
闪存操作示例
以下是一个简单的示例,展示如何在STM32L4上编写和读取闪存数据。我们将使用STM32CubeMX生成的代码框架,并通过HAL库进行操作。
#include "stm32l4xx_hal.h"
// 定义闪存地址
#define FLASH_USER_START_ADDR ADDR_FLASH_PAGE_10 /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR (ADDR_FLASH_PAGE_10 + 0x400) /* End @ of user Flash area */
#define FLASH_USER_DATA_OFFSET 0x400 /* Data start address in user Flash area */
#define DATA_LENGTH 4 /* Length of data to program */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_FLASH_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_FLASH_Init();
uint32_t data_to_program[DATA_LENGTH] = {0x11223344, 0x55667788, 0x99AABBCC, 0xDDEEFF00};
uint32_t data_read[DATA_LENGTH];
// 编程闪存
if (HAL_FLASH_Unlock() != HAL_OK) {
Error_Handler();
}
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_USER_START_ADDR + (i * 4), data_to_program[i]) != HAL_OK) {
Error_Handler();
}
}
HAL_FLASH_Lock();
// 读取闪存
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
data_read[i] = *(__IO uint32_t*)(FLASH_USER_START_ADDR + (i * 4));
}
// 检查读取的数据是否与编程的数据一致
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
if (data_read[i] != data_to_program[i]) {
Error_Handler();
}
}
// 成功读取数据
while (1) {
// 空循环
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
// 例如:配置LED引脚
}
static void MX_FLASH_Init(void)
{
// 闪存初始化
// 例如:设置闪存访问参数
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
SRAM
SRAM用于存储变量和堆栈等动态数据。STM32L4系列通常具有64KB到320KB的SRAM容量,具体取决于不同的型号。SRAM的访问速度非常快,且没有写入次数的限制。
SRAM操作示例
以下是一个简单的示例,展示如何在STM32L4上使用SRAM。
#include "stm32l4xx_hal.h"
// 定义SRAM变量
uint32_t sram_data[DATA_LENGTH];
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
// 写入SRAM数据
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
sram_data[i] = 0x11223344 + i;
}
// 读取SRAM数据
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
if (sram_data[i] != (0x11223344 + i)) {
Error_Handler();
}
}
// 成功读取数据
while (1) {
// 空循环
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
// 例如:配置LED引脚
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
系统存储器(System Memory)
系统存储器主要用于存储启动代码和一些重要的系统参数。系统存储器的容量较小,但访问速度较快。系统存储器通常用于存储引导加载程序(Bootloader)和一些固件更新相关的数据。
系统存储器操作示例
以下是一个简单的示例,展示如何在STM32L4上使用系统存储器。
#include "stm32l4xx_hal.h"
// 定义系统存储器地址
#define SYSTEM_MEMORY_ADDR 0x1FFF0000
#define DATA_LENGTH 4
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
uint32_t system_memory_data[DATA_LENGTH];
// 读取系统存储器数据
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
system_memory_data[i] = *(__IO uint32_t*)(SYSTEM_MEMORY_ADDR + (i * 4));
}
// 检查读取的数据
for (uint32_t i = 0; i < DATA_LENGTH; i++) {
if (system_memory_data[i] != (0x11223344 + i)) {
Error_Handler();
}
}
// 成功读取数据
while (1) {
// 空循环
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
// 例如:配置LED引脚
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
中断系统
STM32L4系列微控制器具有强大的中断处理能力,可以处理各种外设和内部事件的中断。了解中断系统的工作原理和配置方法对于编写高效、可靠的嵌入式程序非常重要。
中断向量表
中断向量表(Vector Table)位于闪存的起始地址,包含所有中断和异常的处理函数地址。可以通过配置寄存器改变中断向量表的位置,以便在不同的启动模式下使用不同的中断处理函数。
中断向量表配置示例
以下是一个简单的示例,展示如何配置中断向量表。
#include "stm32l4xx_hal.h"
// 定义中断向量表地址
#define CUSTOM_VECTOR_TABLE_ADDR 0x08000800
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_NVIC_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_NVIC_Init();
// 设置中断向量表地址
SCB->VTOR = CUSTOM_VECTOR_TABLE_ADDR;
while (1) {
// 空循环
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
// 例如:配置LED引脚
}
static void MX_NVIC_Init(void)
{
// NVIC初始化
// 例如:配置外部中断
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
// 外部中断0处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// GPIO中断回调函数
if (GPIO_Pin == GPIO_PIN_0) {
// 处理GPIO_PIN_0的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
中断优先级
STM32L4系列的中断系统支持可配置的中断优先级。每个中断向量可以设置两个优先级:抢占优先级(Preemption Priority)和子优先级(Subpriority)。抢占优先级决定了中断是否可以打断其他正在处理的中断,子优先级用于在相同抢占优先级的中断之间进行调度。
中断优先级配置示例
以下是一个简单的示例,展示如何配置中断优先级。
#include "stm32l4xx_hal.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_NVIC_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_NVIC_Init();
while (1) {
// 空循环
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
// 例如:配置LED引脚
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
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);
}
static void MX_NVIC_Init(void)
{
// NVIC初始化
// 例如:配置外部中断
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0); // 设置抢占优先级为1,子优先级为0
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
HAL_NVIC_SetPriority(EXTI1_IRQn, 2, 0); // 设置抢占优先级为2,子优先级为0
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
}
void EXTI0_IRQHandler(void)
{
// 外部中断0处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void EXTI1_IRQHandler(void)
{
// 外部中断1处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// GPIO中断回调函数
if (GPIO_Pin == GPIO_PIN_0) {
// 处理GPIO_PIN_0的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
} else if (GPIO_Pin == GPIO_PIN_1) {
// 处理GPIO_PIN_1的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
外设控制
STM32L4系列微控制器集成了丰富的外设,如GPIO、定时器、ADC、DAC、USART、SPI、I2C等。了解如何配置和使用这些外设是编写嵌入式应用程序的基础。
GPIO配置
GPIO(General Purpose Input/Output)是STM32L4系列中最基本的外设之一。可以通过配置寄存器设置GPIO的模式、速度和上拉/下拉电阻。
GPIO配置示例
以下是一个简单的示例,展示如何配置GPIO。
#include "stm32l4xx_hal.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
HAL_Delay(500); // 延时500ms
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
// 外部中断0处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// GPIO中断回调函数
if (GPIO_Pin == GPIO_PIN_0) {
// 处理GPIO_PIN_0的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
定时器配置
定时器是STM32L4系列中常用的外设之一,可以用于产生周期性中断、测量时间间隔、生成PWM信号等。
定时器配置示例
以下是一个简单的示例,展示如何配置和使用定时器。
#include "stm32l4xx_hal.h"
TIM_HandleTypeDef htim2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start_IT(&htim2); // 启动定时器并使能中断
while (1) {
// 空循环
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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);
}
static void MX_TIM2_Init(void)
{
// 定时器初始化
__HAL_RCC_TIM2_CLK_ENABLE();
htim2.Instance = TIM2;
htim2.Init.Prescaler = 8000 - 1; // 预分频器,80MHz / 8000 = 10kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 10000 - 1; // 计数器周期,10000 * 10us = 100ms
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
Error_Handler();
}
// 配置NVIC
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
void TIM2_IRQHandler(void)
{
// 定时器2中断处理函数
HAL_TIM_IRQHandler(&htim2);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// 定时器周期中断回调函数
if (htim->Instance == TIM2) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
}
ADC配置
ADC(Analog-to-Digital Converter)用于将模拟信号转换为数字信号。STM32L4系列通常具有多个ADC通道,可以配置不同的采样率和分辨率。了解如何配置和使用ADC对于处理模拟输入信号至关重要。
ADC配置示例
以下是一个简单的示例,展示如何配置和使用ADC。
#include "stm32l4xx_hal.h"
ADC_HandleTypeDef hadc1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
while (1) {
uint32_t adc_value = 0;
// 启动ADC转换
if (HAL_ADC_Start(&hadc1) == HAL_OK) {
// 等待ADC转换完成
if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK) {
// 获取ADC转换值
adc_value = HAL_ADC_GetValue(&hadc1);
}
// 停止ADC转换
HAL_ADC_Stop(&hadc1);
}
// 处理ADC值
if (adc_value > 2048) {
// 如果ADC值大于2048,点亮LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
} else {
// 如果ADC值小于或等于2048,熄灭LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
HAL_Delay(500); // 延时500ms
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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);
// 配置ADC输入引脚
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
static void MX_ADC1_Init(void)
{
// ADC1初始化
__HAL_RCC_ADC12_CLK_ENABLE();
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = DISABLE; // 单通道模式
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.LowPowerAutoPowerOff = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
Error_Handler();
}
// 配置ADC通道
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Error_Handler();
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
while (1) {
// 空循环
}
}
DAC配置
DAC(Digital-to-Analog Converter)用于将数字信号转换为模拟信号。STM32L4系列通常具有多个DAC通道,可以配置不同的输出模式和分辨率。
DAC配置示例
以下是一个简单的示例,展示如何配置和使用DAC。
#include "stm32l4xx_hal.h"
DAC_HandleTypeDef hdac1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DAC1_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DAC1_Init();
while (1) {
// 设置DAC输出值
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
HAL_Delay(1000); // 延时1000ms
// 设置DAC输出值
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 1024);
HAL_Delay(1000); // 延时1000ms
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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);
// 配置DAC输出引脚
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
static void MX_DAC1_Init(void)
{
// DAC1初始化
__HAL_RCC_DAC1_CLK_ENABLE();
hdac1.Instance = DAC1;
hdac1.Initresolution = DAC_RESOLUTION_12B;
hdac1.Init.DataAlignment = DAC_DATAALIGN_12B_R;
hdac1.InitTro = DISABLE;
hdac1.Init.Trigger = DAC_TRIGGER_NONE;
hdac1.Init.WaveGeneration = DAC_WAVE_NONE;
if (HAL_DAC_Init(&hdac1) != HAL_OK) {
Error_Handler();
}
// 配置DAC通道
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK) {
Error_Handler();
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
while (1) {
// 空循环
}
}
低功耗特性
STM32L4系列微控制器具有多种低功耗模式,如睡眠模式(Sleep Mode)、停止模式(Stop Mode)和待机模式(Standby Mode)。这些模式可以显著减少功耗,延长电池寿命。理解如何配置和使用这些低功耗模式对于开发低功耗应用非常重要。
睡眠模式
在睡眠模式下,CPU停止工作,但系统时钟和外设继续运行。可以通过不同的触发源(如中断、事件等)唤醒CPU。
睡眠模式配置示例
以下是一个简单的示例,展示如何配置和使用睡眠模式。
#include "stm32l4xx_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_TogglePin(GPIOA, GPIO_PIN_5);
// 进入睡眠模式
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
// 延时500ms
HAL_Delay(500);
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
// 外部中断0处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// GPIO中断回调函数
if (GPIO_Pin == GPIO_PIN_0) {
// 处理GPIO_PIN_0的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
while (1) {
// 空循环
}
}
停止模式
在停止模式下,CPU和大部分外设停止工作,只有某些低功耗外设(如RTC、I2C等)继续运行。可以通过外部中断或复位唤醒CPU。
停止模式配置示例
以下是一个简单的示例,展示如何配置和使用停止模式。
#include "stm32l4xx_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_TogglePin(GPIOA, GPIO_PIN_5);
// 进入停止模式
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 延时500ms
HAL_Delay(500);
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
// 外部中断0处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// GPIO中断回调函数
if (GPIO_Pin == GPIO_PIN_0) {
// 处理GPIO_PIN_0的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
while (1) {
// 空循环
}
}
待机模式
在待机模式下,CPU和所有外设停止工作,只有RTC和某些低功耗外设可以继续运行。可以通过外部唤醒引脚或复位唤醒CPU。
待机模式配置示例
以下是一个简单的示例,展示如何配置和使用待机模式。
#include "stm32l4xx_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_TogglePin(GPIOA, GPIO_PIN_5);
// 进入待机模式
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_PWR_EnterSTANDBYMode();
// 延时500ms
HAL_Delay(500);
}
}
void SystemClock_Config(void)
{
// 系统时钟配置
// 例如:设置系统时钟为80MHz
}
static void MX_GPIO_Init(void)
{
// GPIO初始化
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 配置LED引脚
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_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置NVIC
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
// 外部中断0处理函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// GPIO中断回调函数
if (GPIO_Pin == GPIO_PIN_0) {
// 处理GPIO_PIN_0的中断
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 切换LED状态
}
}
void Error_Handler(void)
{
// 错误处理函数
// 例如:点亮错误指示灯
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
while (1) {
// 空循环
}
}
通过以上示例,我们可以看到STM32L4系列微控制器在内存模型、中断系统、外设控制和低功耗特性方面的强大功能和灵活性。这些功能使得STM32L4系列非常适合各种嵌入式应用,从简单的控制任务到复杂的低功耗应用。希望这些示例能帮助你更好地理解和使用STM32L4系列微控制器。
作者:kkchenkx