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配置步骤
  1. 使能ADC时钟:通过RCC(Reset and Clock Control)配置使能ADC的时钟。

  2. 配置ADC参数:设置分辨率、采样时间、连续转换模式等。

  3. 配置GPIO:将要用作模拟输入的引脚配置为模拟输入模式。

  4. 初始化ADC:调用库函数初始化ADC模块。

  5. 启动ADC转换:通过软件或硬件触发启动ADC转换。

  6. 读取转换结果:从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配置步骤
  1. 使能DAC时钟:通过RCC配置使能DAC的时钟。

  2. 配置DAC参数:设置输出模式、数据对齐方式等。

  3. 配置GPIO:将要用作DAC输出的引脚配置为DAC输出模式。

  4. 初始化DAC:调用库函数初始化DAC模块。

  5. 设置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配置步骤
  1. 使能定时器时钟:通过RCC(Reset and Clock Control)配置使能定时器的时钟。

  2. 配置定时器参数:设置定时器的时基、预分频器、计数模式等。

  3. 配置定时器中断:如果需要使用定时器中断,配置相应中断。

  4. 初始化定时器:调用库函数初始化定时器模块。

  5. 启动定时器:通过软件或硬件触发启动定时器。

  6. 处理定时器中断:在中断服务函数中处理定时器中断事件。

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

物联沃分享整理
物联沃-IOTWORD物联网 » STMicroelectronics 系列:STM32L4 系列_(4).STM32L4系列的外设功能

发表回复