STMicroelectronics 系列:STM32L4 系列_(4).STM32L4系列的外设功能
STM32L4系列的外设功能
1. ADC(模数转换器)
1.1 ADC概述
模数转换器(Analog-to-Digital Converter, ADC)是STM32L4系列微控制器中的一个重要外设,用于将模拟信号转换为数字信号。STM32L4系列的ADC具有高精度、低功耗和多种工作模式,可以满足不同应用需求。
1.2 ADC配置
1.2.1 ADC配置步骤
-
使能ADC时钟:通过RCC(Reset and Clock Control)配置使能ADC的时钟。
-
配置ADC参数:设置分辨率、采样时间、连续转换模式等。
-
配置GPIO:将要用作模拟输入的引脚配置为模拟输入模式。
-
初始化ADC:调用库函数初始化ADC模块。
-
启动ADC转换:通过软件或硬件触发启动ADC转换。
-
读取转换结果:从ADC的数据寄存器中读取转换结果。
1.2.2 代码示例
以下是一个简单的代码示例,展示了如何配置和使用STM32L4系列的ADC来读取一个模拟输入引脚的电压值。
#include "stm32l4xx_hal.h"
// 定义ADC句柄
ADC_HandleTypeDef hadc1;
// 定义ADC通道
#define ADC_CHANNEL 0
// 初始化ADC
void ADC_Init(void) {
// 使能ADC时钟
__HAL_RCC_ADC_CLK_ENABLE();
// 配置ADC参数
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为12位
hadc1.Init.ScanConvMode = DISABLE; // 单通道模式
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc1.Init.NbrOfConversion = 1; // 1个转换
hadc1.Init.DiscontinuousConvMode = DISABLE; // 连续转换模式
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
hadc1.Init.NbrOfDiscConversion = 1; // 1个不连续转换
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 无外部触发
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置ADC通道
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL; // 选择通道0
sConfig.Rank = ADC_REGULAR_RANK_1; // 通道1
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间为3个ADC时钟周期
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; // 设置为模拟输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 启动ADC转换并读取结果
uint16_t ADC_Read(void) {
uint32_t conversion_value = 0;
// 启动ADC转换
if (HAL_ADC_Start(&hadc1) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
// 等待转换完成
if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) != HAL_OK) {
// 转换失败处理
Error_Handler();
}
// 读取转换结果
conversion_value = HAL_ADC_GetValue(&hadc1);
// 停止ADC转换
if (HAL_ADC_Stop(&hadc1) != HAL_OK) {
// 停止失败处理
Error_Handler();
}
return conversion_value;
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
ADC_Init(); // 初始化ADC
while (1) {
uint16_t adc_value = ADC_Read(); // 读取ADC值
// 进一步处理ADC值
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
1.3 ADC中断和DMA
1.3.1 ADC中断
ADC中断可以用于在转换完成时通知CPU进行处理。通过配置ADC的中断,可以提高系统的响应速度和效率。
#include "stm32l4xx_hal.h"
// 定义ADC句柄
ADC_HandleTypeDef hadc1;
// 定义ADC通道
#define ADC_CHANNEL 0
// 定义转换结果变量
uint16_t adc_value = 0;
// ADC初始化
void ADC_Init(void) {
// 使能ADC时钟
__HAL_RCC_ADC_CLK_ENABLE();
// 配置ADC参数
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为12位
hadc1.Init.ScanConvMode = DISABLE; // 单通道模式
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc1.Init.NbrOfConversion = 1; // 1个转换
hadc1.Init.DiscontinuousConvMode = DISABLE; // 连续转换模式
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
hadc1.Init.NbrOfDiscConversion = 1; // 1个不连续转换
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 无外部触发
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; // 转换结束选择
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置ADC通道
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL; // 选择通道0
sConfig.Rank = ADC_REGULAR_RANK_1; // 通道1
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间为3个ADC时钟周期
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; // 设置为模拟输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 使能ADC中断
HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}
// ADC中断处理函数
void ADC1_2_IRQHandler(void) {
HAL_ADC_IRQHandler(&hadc1);
}
// ADC转换完成回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
adc_value = HAL_ADC_GetValue(hadc); // 读取转换结果
// 进一步处理ADC值
}
// 启动ADC转换
void ADC_Start(void) {
if (HAL_ADC_Start_IT(&hadc1) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
ADC_Init(); // 初始化ADC
while (1) {
ADC_Start(); // 启动ADC转换
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
1.3.2 ADC DMA
DMA(Direct Memory Access)可以用于在ADC转换完成后自动将数据传输到指定的内存区域,从而减少CPU的负担。通过配置ADC的DMA,可以实现高效的数据采集。
#include "stm32l4xx_hal.h"
// 定义ADC句柄
ADC_HandleTypeDef hadc1;
// 定义DMA句柄
DMA_HandleTypeDef hdma_adc1;
// 定义ADC通道
#define ADC_CHANNEL 0
// 定义转换结果缓冲区
uint16_t adc_buffer[100];
// ADC初始化
void ADC_Init(void) {
// 使能ADC时钟
__HAL_RCC_ADC_CLK_ENABLE();
// 配置ADC参数
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为12位
hadc1.Init.ScanConvMode = DISABLE; // 单通道模式
hadc1.Init.ContinuousConvMode = ENABLE; // 连续转换模式
hadc1.Init.NbrOfConversion = 1; // 1个转换
hadc1.Init.DiscontinuousConvMode = DISABLE; // 连续转换模式
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
hadc1.Init.NbrOfDiscConversion = 1; // 1个不连续转换
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; // 转换结束选择
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置ADC通道
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL; // 选择通道0
sConfig.Rank = ADC_REGULAR_RANK_1; // 通道1
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间为3个ADC时钟周期
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; // 设置为模拟输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置DMA
__HAL_RCC_DMA1_CLK_ENABLE(); // 使能DMA1时钟
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; // 从外设到内存
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; // 外设不递增
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; // 内存递增
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // 半字对齐
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // 半字对齐
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW; // 低优先级
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) {
// DMA初始化失败处理
Error_Handler();
}
// 将DMA句柄与ADC句柄关联
__HAL_LINKDMA(&hadc1, hdmaReg, hdma_adc1);
// 使能DMA中断
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
// DMA中断处理函数
void DMA1_Channel1_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_adc1);
}
// 启动ADC转换
void ADC_Start(void) {
if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 100) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
ADC_Init(); // 初始化ADC
while (1) {
ADC_Start(); // 启动ADC转换
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
2. DAC(数模转换器)
2.1 DAC概述
数模转换器(Digital-to-Analog Converter, DAC)是STM32L4系列微控制器中的另一个重要外设,用于将数字信号转换为模拟信号。STM32L4系列的DAC具有高精度和多种输出模式,可以用于生成波形、控制模拟电压等。
2.2 DAC配置
2.2.1 DAC配置步骤
-
使能DAC时钟:通过RCC配置使能DAC的时钟。
-
配置DAC参数:设置输出模式、数据对齐方式等。
-
配置GPIO:将要用作DAC输出的引脚配置为DAC输出模式。
-
初始化DAC:调用库函数初始化DAC模块。
-
设置DAC输出值:通过软件设置DAC的输出值。
2.2.2 代码示例
以下是一个简单的代码示例,展示了如何配置和使用STM32L4系列的DAC来生成一个模拟电压值。
#include "stm32l4xx_hal.h"
// 定义DAC句柄
DAC_HandleTypeDef hdac1;
// 定义DAC通道
#define DAC_CHANNEL 1
// DAC初始化
void DAC_Init(void) {
// 使能DAC时钟
__HAL_RCC_DAC1_CLK_ENABLE();
// 配置DAC参数
hdac1.Instance = DAC1;
hdac1.Init.Resolution = DAC_RESOLUTION_12B; // 设置分辨率为12位
hdac1.Init.DataAlignment = DAC_DATAALIGN_RIGHT; // 右对齐
hdac1.Init.Mode = DAC_MODE_NORMAL; // 正常模式
if (HAL_DAC_Init(&hdac1) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置DAC通道
DAC_ChannelConfTypeDef sConfig = {0};
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE; // 禁用采样保持
sConfig.DAC_Trigger = DAC_TRIGGER_NONE; // 无触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; // 启用输出缓冲
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_1; // 选择PA1
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; // 设置为模拟输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 设置DAC输出值
void DAC_SetValue(uint16_t value) {
if (HAL_DAC_SetValue(&hdac1, DAC_CHANNEL, DAC_ALIGN_12B_R, value) != HAL_OK) {
// 设置值失败处理
Error_Handler();
}
}
// 启动DAC转换
void DAC_Start(void) {
if (HAL_DAC_Start(&hdac1, DAC_CHANNEL) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
DAC_Init(); // 初始化DAC
while (1) {
DAC_SetValue(2048); // 设置DAC输出值为2048 (1/2 Vref)
HAL_Delay(1000); // 延时1秒
DAC_SetValue(0); // 设置DAC输出值为0 (0 V)
HAL_Delay(1000); // 延时1秒
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
3. TIM(定时器)
3.1 TIM概述
定时器(Timer## 3. TIM(定时器)
3.1 TIM概述
定时器(Timer)是STM32L4系列微控制器中的一个非常重要的外设,用于生成定时中断、PWM信号、测量信号周期和频率等。STM32L4系列的定时器种类丰富,包括通用定时器、基本定时器、高级定时器和低功耗定时器,每种定时器都有不同的特性和应用场景。
3.2 TIM配置
3.2.1 TIM配置步骤
-
使能定时器时钟:通过RCC(Reset and Clock Control)配置使能定时器的时钟。
-
配置定时器参数:设置定时器的时基、预分频器、计数模式等。
-
配置定时器中断:如果需要使用定时器中断,配置相应中断。
-
初始化定时器:调用库函数初始化定时器模块。
-
启动定时器:通过软件或硬件触发启动定时器。
-
处理定时器中断:在中断服务函数中处理定时器中断事件。
3.2.2 代码示例
以下是一个简单的代码示例,展示了如何配置和使用STM32L4系列的定时器来生成定时中断。
#include "stm32l4xx_hal.h"
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义中断优先级和子优先级
#define TIM_PRESCALER 10000
#define TIM_PERIOD 10000
// 定时器初始化
void TIM_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = TIM_PRESCALER - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = TIM_PERIOD - 1; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置定时器中断
TIM_HandleTypeDef *htim = &htim2;
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
// 使能定时器更新中断
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
}
// 定时器中断处理函数
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
// 定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 定时器2更新中断处理
// 进一步处理定时中断事件
}
}
// 启动定时器
void TIM_Start(void) {
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
TIM_Init(); // 初始化定时器
while (1) {
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
3.3 TIM高级功能
3.3.1 PWM输出
PWM(Pulse Width Modulation)信号是一种通过改变脉冲宽度来控制信号的方式,广泛用于电机控制、LED调光等领域。STM32L4系列的定时器可以轻松配置为PWM输出模式。
#include "stm32l4xx_hal.h"
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义PWM通道
#define PWM_CHANNEL TIM_CHANNEL_1
// 定义PWM参数
#define PWM_PERIOD 10000
#define PWM_PULSE 5000
// PWM初始化
void PWM_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = 10000 - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = PWM_PERIOD - 1; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置PWM通道
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
sConfigOC.Pulse = PWM_PULSE; // 脉冲宽度
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 高电平有效
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 禁用快速模式
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, PWM_CHANNEL) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; // 选择TIM2复用功能
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 启动PWM输出
void PWM_Start(void) {
if (HAL_TIM_PWM_Start(&htim2, PWM_CHANNEL) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 设置PWM脉冲宽度
void PWM_SetPulse(uint32_t pulse) {
if (HAL_TIM_PWM_SetCompare(&htim2, PWM_CHANNEL, pulse) != HAL_OK) {
// 设置脉冲宽度失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
PWM_Init(); // 初始化PWM
while (1) {
PWM_Start(); // 启动PWM输出
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
3.3.2 信号输入捕获
定时器还可以用于捕获外部信号的周期和频率。通过配置定时器的输入捕获通道,可以实现对脉冲信号的精确测量。
#include "stm32l4xx_hal.h"
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义输入捕获通道
#define IC_CHANNEL TIM_CHANNEL_1
// 输入捕获初始化
void IC_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = 10000 - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = 65535; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_IC_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置输入捕获通道
TIM_IC_InitTypeDef sConfigIC = {0};
sConfigIC.Channel = IC_CHANNEL; // 选择通道1
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; // 上升沿触发
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直接输入捕获
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; // 不分频
sConfigIC.ICFilter = 0; // 无滤波
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, IC_CHANNEL) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; // 选择TIM2复用功能
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 使能定时器中断
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
// 使能输入捕获中断
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC1);
}
// 定时器中断处理函数
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
// 输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
uint32_t captured_value = HAL_TIM_ReadCapturedValue(htim, IC_CHANNEL);
// 进一步处理捕获值
}
}
// 启动输入捕获
void IC_Start(void) {
if (HAL_TIM_IC_Start_IT(&htim2, IC_CHANNEL) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
IC_Init(); // 初始化输入捕获
while (1) {
IC_Start(); // 启动输入捕获
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
3.4 TIM与其他外设的协同使用
3.4.1 TIM与ADC的协同使用
定时器可以与ADC协同使用,通过定时器的触发信号启动ADC转换,实现周期性的数据采集。
#include "stm32l4xx_hal.h"
// 定义ADC句柄
ADC_HandleTypeDef hadc1;
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义ADC通道
#define ADC_CHANNEL 0
// 定义定时器通道
#define TIM_CHANNEL TIM_CHANNEL_1
// ADC初始化
void ADC_Init(void) {
// 使能ADC时钟
__HAL_RCC_ADC_CLK_ENABLE();
// 配置ADC参数
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为12位
hadc1.Init.ScanConvMode = DISABLE; // 单通道模式
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换模式
hadc1.Init.NbrOfConversion = 1; // 1个转换
hadc1.Init.DiscontinuousConvMode = DISABLE; // 连续转换模式
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO; // 由定时器2的TRGO触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
hadc1.Init.NbrOfDiscConversion = 1; // 1个不连续转换
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; // 上升沿触发
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置ADC通道
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL; // 选择通道0
sConfig.Rank = ADC_REGULAR_RANK_1; // 通道1
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间为3个ADC时钟周期
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; // 设置为模拟输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 定时器初始化
void TIM_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = 10000 - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = 10000 - 1; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置定时器TRGO触发
TIM_MasterConfigTypeDef sMasterConfig = {0};
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // 触发事件为更新事件
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主从模式
if (HAL_TIM_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
// 配置同步失败处理
Error_Handler();
}
// 使能定时器中断
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
// 使能定时器更新中断
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);
}
// 定时器中断处理函数
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
// 定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 定时器2更新中断处理
// 进一步处理定时中断事件
}
}
// 启动定时器
void TIM_Start(void) {
if (HAL_TIM_Base_Start(&htim2) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 启动ADC转换并读取结果
uint16_t ADC_Read(void) {
uint32_t conversion_value = 0;
// 启动ADC转换
if (HAL_ADC_Start(&hadc1) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
// 等待转换完成
if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) != HAL_OK) {
// 转换失败处理
Error_Handler();
}
// 读取转换结果
conversion_value = HAL_ADC_GetValue(&hadc1);
// 停止ADC转换
if (HAL_ADC_Stop(&hadc1) != HAL_OK) {
// 停止失败处理
Error_Handler();
}
return conversion_value;
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
ADC_Init(); // 初始化ADC
TIM_Init(); // 初始化定时器
while (1) {
TIM_Start(); // 启动定时器
uint16_t adc_value = ADC_Read(); // 读取ADC值
// 进一步处理ADC值
}
}
// 系统时钟配置函数## 3. TIM(定时器)
### 3.1 TIM概述
定时器(Timer)是STM32L4系列微控制器中的一个非常重要的外设,用于生成定时中断、PWM信号、测量信号周期和频率等。STM32L4系列的定时器种类丰富,包括通用定时器、基本定时器、高级定时器和低功耗定时器,每种定时器都有不同的特性和应用场景。
### 3.2 TIM配置
#### 3.2.1 TIM配置步骤
1. **使能定时器时钟**:通过RCC(Reset and Clock Control)配置使能定时器的时钟。
2. **配置定时器参数**:设置定时器的时基、预分频器、计数模式等。
3. **配置定时器中断**:如果需要使用定时器中断,配置相应中断。
4. **初始化定时器**:调用库函数初始化定时器模块。
5. **启动定时器**:通过软件或硬件触发启动定时器。
6. **处理定时器中断**:在中断服务函数中处理定时器中断事件。
#### 3.2.2 代码示例
以下是一个简单的代码示例,展示了如何配置和使用STM32L4系列的定时器来生成定时中断。
```c
#include "stm32l4xx_hal.h"
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义中断优先级和子优先级
#define TIM_PRESCALER 10000
#define TIM_PERIOD 10000
// 定时器初始化
void TIM_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = TIM_PRESCALER - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = TIM_PERIOD - 1; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置定时器中断
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
// 使能定时器更新中断
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);
}
// 定时器中断处理函数
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
// 定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 定时器2更新中断处理
// 进一步处理定时中断事件
}
}
// 启动定时器
void TIM_Start(void) {
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
TIM_Init(); // 初始化定时器
while (1) {
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
3.3 TIM高级功能
3.3.1 PWM输出
PWM(Pulse Width Modulation)信号是一种通过改变脉冲宽度来控制信号的方式,广泛用于电机控制、LED调光等领域。STM32L4系列的定时器可以轻松配置为PWM输出模式。
#include "stm32l4xx_hal.h"
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义PWM通道
#define PWM_CHANNEL TIM_CHANNEL_1
// 定义PWM参数
#define PWM_PERIOD 10000
#define PWM_PULSE 5000
// PWM初始化
void PWM_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = 10000 - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = PWM_PERIOD - 1; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置PWM通道
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
sConfigOC.Pulse = PWM_PULSE; // 脉冲宽度
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 高电平有效
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 禁用快速模式
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, PWM_CHANNEL) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; // 选择TIM2复用功能
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 启动PWM输出
void PWM_Start(void) {
if (HAL_TIM_PWM_Start(&htim2, PWM_CHANNEL) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 设置PWM脉冲宽度
void PWM_SetPulse(uint32_t pulse) {
if (HAL_TIM_PWM_SetCompare(&htim2, PWM_CHANNEL, pulse) != HAL_OK) {
// 设置脉冲宽度失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
PWM_Init(); // 初始化PWM
while (1) {
PWM_Start(); // 启动PWM输出
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
3.3.2 信号输入捕获
定时器还可以用于捕获外部信号的周期和频率。通过配置定时器的输入捕获通道,可以实现对脉冲信号的精确测量。
#include "stm32l4xx_hal.h"
// 定义定时器句柄
TIM_HandleTypeDef htim2;
// 定义输入捕获通道
#define IC_CHANNEL TIM_CHANNEL_1
// 输入捕获初始化
void IC_Init(void) {
// 使能定时器时钟
__HAL_RCC_TIM2_CLK_ENABLE();
// 配置定时器参数
htim2.Instance = TIM2;
htim2.Init.Prescaler = 10000 - 1; // 预分频器
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = 65535; // 计数周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
if (HAL_TIM_IC_Init(&htim2) != HAL_OK) {
// 初始化失败处理
Error_Handler();
}
// 配置输入捕获通道
TIM_IC_InitTypeDef sConfigIC = {0};
sConfigIC.Channel = IC_CHANNEL; // 选择通道1
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; // 上升沿触发
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直接输入捕获
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; // 不分频
sConfigIC.ICFilter = 0; // 无滤波
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, IC_CHANNEL) != HAL_OK) {
// 通道配置失败处理
Error_Handler();
}
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0; // 选择PA0
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; // 选择TIM2复用功能
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 使能定时器中断
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
// 使能输入捕获中断
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC1);
}
// 定时器中断处理函数
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}
// 输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
uint32_t captured_value = HAL_TIM_ReadCapturedValue(htim, IC_CHANNEL);
// 进一步处理捕获值
}
}
// 启动输入捕获
void IC_Start(void) {
if (HAL_TIM_IC_Start_IT(&htim2, IC_CHANNEL) != HAL_OK) {
// 启动失败处理
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void) {
// 用户自定义的错误处理
while (1) {
// 无限循环
}
}
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
IC_Init(); // 初始化输入捕获
while (1) {
IC_Start(); // 启动输入捕获
// 其他任务
}
}
// 系统时钟配置函数
void SystemClock_Config(void) {
// 配置系统时钟
// 该函数的具体实现根据实际硬件配置进行
}
作者:kkchenkx