本帖最后由 正点原子运营 于 2024-4-11 15:26 编辑
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板
2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版
6)正点原子STM32技术交流QQ群:725095144
本章将介绍使用STM32F103的高级定时器输出多个频率、占空比相同但相位不同的PWM。通过本章的学习,读者将学习到高级定时器输出比较的匹配时输出翻转模式的使用。 本章分为如下几个小节: 22.1 硬件设计 22.2 程序设计 22.3 下载验证
22.1 硬件设计 22.1.1 例程功能 1. PC6和PC7引脚输出频率同为500Hz,但相位相差25%的PWM 2. LED0闪烁,提示程序正在运行 22.1.2 硬件资源 1. LED LED0 - PB5 2. TIM8 CH1 - PC6 CH2 - PC7
22.1.3 原理图 本章实验使用的TIM8为STM32F103的片上资源,因此没有对应的连接原理图。
22.2 程序设计 22.2.1 HAL库的TIM驱动 本章实验将使用TIM8输出四个频率、占空比相同,但相位不同的PWM,其具体步骤如下: ①:初始化定时器输出比较 ②:配置定时器输出比较通道 ③:开始定时器输出比较 在HAL库中对应的驱动函数如下: ①:初始化定时器输出比较 该函数用于初始化定时器输出比较,其函数原型如下所示: - HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef *htim);
复制代码该函数的形参描述,如下表所示: 表22.2.1.1 函数HAL_TIM_OC_Init()形参描述 该函数的返回值描述,如下表所示: 表22.2.1.2 函数HAL_TIM_OC_Init()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- TIM_HandleTypeDef tim_handle = {0};
-
- /* 初始化TIM8输出比较 */
- tim_handle.Instance = TIM8;
- tim_handle.Init.Prescaler = 72 - 1;
- tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
- tim_handle.Init.Period = 1000 - 1;
- tim_handle.Init.AutoReloadPreload =TIM_AUTORELOAD_PRELOAD_ENABLE;
- tim_handle.Init.RepetitionCounter = 0;
- HAL_TIM_OC_Init(&tim_handle);
- }
复制代码②:配置定时器输出比较通道 该函数用于配置定时器的输出比较通道,其函数原型如下所示: - HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel( TIM_HandleTypeDef *htim,
- TIM_OC_InitTypeDef*sConfig,
- uint32_t Channel);
复制代码该函数的形参描述,如下表所示: 表22.2.1.3 函数HAL_TIM_OC_ConfigChannel()形参描述 该函数的返回值描述,如下表所示: 表22.2.1.4 函数HAL_TIM_OC_ConfigChannel()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- TIM_OC_InitTypeDeftim_oc_init_struct = {0};
-
- /* 配置定时器通道1输出比较 */
- tim_oc_init_struct.OCMode = TIM_OCMODE_TOGGLE;
- tim_oc_init_struct.Pulse = 500 - 1;
- tim_oc_init_struct.OCPolarity =TIM_OCPOLARITY_HIGH;
- HAL_TIM_OC_ConfigChannel(&tim_handle, &tim_oc_init_struct, TIM_CHANNEL_1);
- }
复制代码③:开始定时器输出比较 该函数用于开始定时器的输出比较,其函数原型如下所示: - HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
复制代码该函数的形参描述,如下表所示: 表22.2.1.5 函数HAL_TIM_OC_Start()形参描述 该函数的返回值描述,如下表所示: 表22.2.1.6 函数HAL_TIM_OC_Start()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- /* 开启定时器通道1输出比较 */
- HAL_TIM_OC_Start(&tim_handle, TIM_CHANNEL_1);
- }
复制代码22.2.2高级定时器驱动 本章实验的高级定时器驱动主要负责向应用层提供高级定时器的初始化函数。本章实验中,高级定时器的驱动代码包括atim.c和atim.h两个文件。 高级定时器驱动中,对TIM、GPIO的相关宏定义,如下所示: - #define ATIM_TIMX_COMP TIM8
- #define ATIM_TIMX_COMP_CLK_ENABLE() \
- do { \
- __HAL_RCC_TIM8_CLK_ENABLE(); \
- }while (0)
- #define ATIM_TIMX_COMP_CH1_GPIO_PORT GPIOC
- #define ATIM_TIMX_COMP_CH1_GPIO_PIN GPIO_PIN_6
- #define ATIM_TIMX_COMP_CH1_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOC_CLK_ENABLE(); \
- }while (0)
- #define ATIM_TIMX_COMP_CH2_GPIO_PORT GPIOC
- #define ATIM_TIMX_COMP_CH2_GPIO_PIN GPIO_PIN_7
- #define ATIM_TIMX_COMP_CH2_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOC_CLK_ENABLE(); \
- }while (0)
复制代码高级定时器驱动中TIM8的初始化函数,如下所示: - /**
- *@brief 初始化高级定时器输出比较
- *@param arr: 自动重装载值
- *@param psc: 预分频系数
- *@retval 无
- */
- voidatim_timx_comp_init(uint16_t arr, uint16_t psc)
- {
- GPIO_InitTypeDef gpio_init_struct;
- TIM_OC_InitTypeDef timx_oc_init_struct = {0};
-
- /* 使能相关时钟 */
- ATIM_TIMX_COMP_CH1_GPIO_CLK_ENABLE();
- ATIM_TIMX_COMP_CH2_GPIO_CLK_ENABLE();
- ATIM_TIMX_COMP_CLK_ENABLE();
-
- /* 配置输出比较通道1输出引脚 */
- gpio_init_struct.Pin = ATIM_TIMX_COMP_CH1_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_AF_PP;
- gpio_init_struct.Pull = GPIO_PULLUP;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(ATIM_TIMX_COMP_CH1_GPIO_PORT, &gpio_init_struct);
-
- /* 配置输出比较通道2输出引脚 */
- gpio_init_struct.Pin = ATIM_TIMX_COMP_CH2_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_AF_PP;
- gpio_init_struct.Pull = GPIO_PULLUP;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(ATIM_TIMX_COMP_CH2_GPIO_PORT, &gpio_init_struct);
- /* 初始化定时器输出比较 */
- g_timx_comp_handle.Instance = ATIM_TIMX_COMP;
- g_timx_comp_handle.Init.Prescaler = psc;
- g_timx_comp_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
- g_timx_comp_handle.Init.Period = arr;
- g_timx_comp_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
- g_timx_comp_handle.Init.RepetitionCounter = 0;
- HAL_TIM_OC_Init(&g_timx_comp_handle);
- /* 配置定时器通道1输出比较 */
- timx_oc_init_struct.OCMode = TIM_OCMODE_TOGGLE;
- timx_oc_init_struct.Pulse = ((arr + 1) >> 2) * 1;
- timx_oc_init_struct.OCPolarity = TIM_OCPOLARITY_HIGH;
- HAL_TIM_OC_ConfigChannel( &g_timx_comp_handle,
- &timx_oc_init_struct,
- TIM_CHANNEL_1);
- /* 配置定时器通道2输出比较 */
- timx_oc_init_struct.OCMode = TIM_OCMODE_TOGGLE;
- timx_oc_init_struct.Pulse = ((arr + 1) >> 2) * 2;
- timx_oc_init_struct.OCPolarity = TIM_OCPOLARITY_HIGH;
- HAL_TIM_OC_ConfigChannel( &g_timx_comp_handle,
- &timx_oc_init_struct,
- TIM_CHANNEL_2);
- /* 开始定时器输出比较 */
- HAL_TIM_OC_Start(&g_timx_comp_handle, TIM_CHANNEL_1);
- HAL_TIM_OC_Start(&g_timx_comp_handle, TIM_CHANNEL_2);
- }
复制代码在TIM8的初始化函数中,初始化了TIM8的输出比较同时配置了TIM8的输出比较通道1和通道2,最后开始了TIM8的输出比较通道1和通道2。
22.2.3 实验应用代码 本章实验的应用代码,如下所示: - int main(void)
- {
- uint8_t t = 0;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 配置时钟,72MHz */
- delay_init(72); /* 初始化延时 */
- usart_init(115200); /* 初始化串口 */
- led_init(); /* 初始化LED */
- atim_timx_comp_init(1000 - 1, 72 - 1); /* 初始化高级定时器输出比较 */
-
- while (1)
- {
- if (++t == 20)
- {
- t = 0;
- LED0_TOGGLE();
- }
- delay_ms(10);
- }
- }
复制代码从上面的代码中可以看到,TIM8的自动重装载值配置为(1000-1),TIM8的预分频器数值配置为(72-1),并且TIM8的时钟频率为72MHz,因此TIM8的计数频率为1MHz,且TIM8每计数1000次溢出一次,因此溢出频率为1KHz,但TIM8的两个通道配置为了匹配时输出翻转模式,因此两个通道输出的PWM频率应为500Hz。
22.3 下载验证 在完成编译和烧录操作后,可以通过示波器观察PC6引脚和PC7引脚输出的两路PWM,可以发现这两路PWM的频率都为500Hz、占空比都为50%,但相位两两相差了25%。 |