本帖最后由 正点原子运营 于 2024-4-11 15:31 编辑
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板
2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版
6)正点原子STM32技术交流QQ群:725095144
本章将介绍使用STM32F103输出带死区和刹车控制的两路互补PWM。通过本章的学习,读者将学习到高级定时器的互补输出、死区插入和刹车的功能的使用。 本章分为如下几个小节: 23.1 硬件设计 23.2 程序设计 23.3下载验证
23.1 硬件设计 23.1.1 例程功能 1. 若PA6引脚输入低电平,则PA8和PA7引脚输出频率为1KHz,占空比为30%的互补PWM 2. 若PA6引脚输入高电平,则PA8和PA7停止输出PWM 3. LED0闪烁,提示程序正在运行
23.1.2 硬件资源 1. LED LED0 - PB5 2. TIM1 CH1 - PA8 CH1N - PA7 BKIN - PA6
23.1.3 原理图 本章实验使用的TIM1为STM32F103的片上资源,因此没有对应的连接原理图。
23.2 程序设计 23.2.1 HAL库的TIM驱动 本章实验将使用TIM1的通道1和通道1的互补通道输出两路带死区的互补PWM,同时还使用到了刹车功能,其具体的配置步骤如下: ①:初始化定时器PWM ②:配置定时器PWM输出通道 ③:开始定时器PWM输出 ④:开始定时器互补通道PWM输出 在HAL库中对应的驱动函数如下: ①:初始化定时器PWM输出 请见第18.2.1小节中初始化定时器PWM的相关内容。 ②:配置定时器PWM输出通道 请见第18.2.1小节中配置定时器PWM输出通道的相关内容。 ③:配置定时器刹车死区时间 该函数用于配置定时器的刹车死区时间,其函数原型如下所示: - HAL_StatusTypeDef HAL_TIMEx_ConfigBreakDeadTime(
- TIM_HandleTypeDef*htim,
- TIM_BreakDeadTimeConfigTypeDef*sBreakDeadTimeConfig);
复制代码该函数的形参描述,如下表所示: 表23.2.1.1 函数HAL_TIMEx_ConfigBreakDeadTime()形参描述 该函数的返回值描述,如下表所示: 表23.2.1.2 函数HAL_TIMEx_ConfigBreakDeadTime()返回值描述 该函数使用TIM_BreakDeadTimeConfigTypeDef类型结构体指针传入了定时器刹车死区时间的配置参数,该结构体的定义如下所示: - typedef struct
- {
- uint32_t OffStateRunMode;/* 运行模式 */
- uint32_t OffStateIDLEMode;/* 空闲模式 */
- uint32_t LockLevel;/* Lock等级 */
- uint32_t DeadTime;/* 死区时间 */
- uint32_t BreakState;/* 刹车状态 */
- uint32_t BreakPolarity;/* 刹车极性 */
- uint32_t BreakFilter;/* 刹车滤波 */
- uint32_t AutomaticOutput;/* 刹车自动恢复 */
- } TIM_BreakDeadTimeConfigTypeDef;
复制代码该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- TIM_BreakDeadTimeConfigTypeDeftim_break_dead_time_config_struct = {0};
-
- /* 配置定时器刹车死区时间 */
- tim_break_dead_time_config_struct.OffStateRunMode = TIM_OSSR_DISABLE;
- tim_break_dead_time_config_struct.OffStateIDLEMode = TIM_OSSI_DISABLE;
- tim_break_dead_time_config_struct.LockLevel = TIM_LOCKLEVEL_OFF;
- tim_break_dead_time_config_struct.DeadTime = 100;
- tim_break_dead_time_config_struct.BreakState = TIM_BREAK_ENABLE;
- tim_break_dead_time_config_struct.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
- tim_break_dead_time_config_struct.BreakFilter = 0;
- tim_break_dead_time_config_struct.AutomaticOutput =
- TIM_AUTOMATICOUTPUT_ENABLE;
- HAL_TIMEx_ConfigBreakDeadTime( &tim_handle,
- &tim_break_dead_time_config_struct);
- }
复制代码④:开始定时器PWM输出 请见第18.2.1小节中开始定时器PWM输出的相关内容。 ⑤:开始定时器互补通道PWM输出 该函数用于开始定时器的互补通道PWM输出,其函数原型如下所示: - HAL_StatusTypeDef HAL_TIMEx_PWMN_Start( TIM_HandleTypeDef *htim,
- uint32_t Channel);
复制代码该函数的形参描述,如下表所示: 形参 | | | | | 定时器通道 例如:TIM_CHANNEL_1、TIM_CHANNEL_2等(在stm32f1xx_hal_tim.h文件中有定义) |
表23.2.1.3 函数HAL_TIMEx_PWMN_Start()形参描述 该函数的返回值描述,如下表所示: 表23.2.1.4 函数HAL_TIMEx_PWMN_Start()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- /* 开启定时器通道1互补通道PWM输出 */
- HAL_TIMEx_PWMN_Start(&tim_handle, TIM_CHANNEL_1);
- }
复制代码
23.2.2高级定时器驱动 本章实验的高级定时器驱动主要负责向应用层提供高级定时器的初始化函数和PWM占空比、死区时间的配置函数。本章实验中,高级定时器的驱动代码包括atim.c和atim.h两个文件。 高级定时器驱动中,对TIM、GPIO相关的宏定义,如下所示: - #define ATIM_TIMX_CPLM TIM1
- #define ATIM_TIMX_CPLM_CLK_ENABLE() \
- do { \
- __HAL_RCC_TIM1_CLK_ENABLE(); \
- } while(0)
- #define ATIM_TIMX_CPLM_CHY TIM_CHANNEL_1
- #define ATIM_TIMX_CPLM_CHY_GPIO_PORT GPIOA
- #define ATIM_TIMX_CPLM_CHY_GPIO_PIN GPIO_PIN_8
- #define ATIM_TIMX_CPLM_CHY_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOA_CLK_ENABLE(); \
- }while (0)
- #define ATIM_TIMX_CPLM_CHYN_GPIO_PORT GPIOA
- #define ATIM_TIMX_CPLM_CHYN_GPIO_PIN GPIO_PIN_7
- #define ATIM_TIMX_CPLM_CHYN_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOA_CLK_ENABLE(); \
- }while (0)
- #define ATIM_TIMX_CPLM_BKIN_GPIO_PORT GPIOA
- #define ATIM_TIMX_CPLM_BKIN_GPIO_PIN GPIO_PIN_6
- #define ATIM_TIMX_CPLM_BKIN_GPIO_CLK_ENABLE() \
- do { \
- __HAL_RCC_GPIOA_CLK_ENABLE(); \
- }while (0)
复制代码高级定时器驱动中TIM8的初始化函数,如下所示: - /**
- *@brief 初始化高级定时器互补输出带死区控制
- *@param arr: 自动重装载值
- *@param psc: 预分频系数
- *@retval 无
- */
- voidatim_timx_cplm_init(uint16_t arr, uint16_t psc)
- {
- GPIO_InitTypeDef gpio_init_struct;
- TIM_OC_InitTypeDef timx_oc_struct = {0};
-
- /* 使能相关时钟 */
- ATIM_TIMX_CPLM_CHY_GPIO_CLK_ENABLE();
- ATIM_TIMX_CPLM_CHYN_GPIO_CLK_ENABLE();
- ATIM_TIMX_CPLM_BKIN_GPIO_CLK_ENABLE();
- ATIM_TIMX_CPLM_CLK_ENABLE();
-
- /* 配置输出比较通道1输出引脚 */
- gpio_init_struct.Pin = ATIM_TIMX_CPLM_CHY_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_CPLM_CHY_GPIO_PORT, &gpio_init_struct);
-
- /* 配置输出比较通道1互补输出引脚 */
- gpio_init_struct.Pin = ATIM_TIMX_CPLM_CHYN_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_CPLM_CHYN_GPIO_PORT, &gpio_init_struct);
-
- /* 配置输出比较通道刹车输入引脚 */
- gpio_init_struct.Pin = ATIM_TIMX_CPLM_BKIN_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_CPLM_BKIN_GPIO_PORT, &gpio_init_struct);
-
- /* 初始化定时器PWM输出 */
- g_timx_cplm_handle.Instance = ATIM_TIMX_CPLM;
- g_timx_cplm_handle.Init.Prescaler = psc;
- g_timx_cplm_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
- g_timx_cplm_handle.Init.Period = arr;
- g_timx_cplm_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
- g_timx_cplm_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
- g_timx_cplm_handle.Init.RepetitionCounter = 0;
- HAL_TIM_PWM_Init(&g_timx_cplm_handle);
-
- /* 配置定时器PWM输出通道 */
- timx_oc_struct.OCMode =TIM_OCMODE_PWM1;
- timx_oc_struct.Pulse = (arr + 1) >> 1;
- timx_oc_struct.OCPolarity = TIM_OCPOLARITY_LOW;
- timx_oc_struct.OCNPolarity = TIM_OCNPOLARITY_LOW;
- timx_oc_struct.OCIdleState = TIM_OCIDLESTATE_SET;
- timx_oc_struct.OCNIdleState = TIM_OCNIDLESTATE_SET;
- HAL_TIM_PWM_ConfigChannel( &g_timx_cplm_handle,
- &timx_oc_struct,
- ATIM_TIMX_CPLM_CHY);
-
- /* 配置定时器刹车死区时间 */
- g_break_dead_time_config_struct.OffStateRunMode = TIM_OSSR_DISABLE;
- g_break_dead_time_config_struct.OffStateIDLEMode = TIM_OSSI_DISABLE;
- g_break_dead_time_config_struct.LockLevel = TIM_LOCKLEVEL_OFF;
- g_break_dead_time_config_struct.BreakState = TIM_BREAK_ENABLE;
- g_break_dead_time_config_struct.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
- g_break_dead_time_config_struct.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
- HAL_TIMEx_ConfigBreakDeadTime( &g_timx_cplm_handle,
- &g_break_dead_time_config_struct);
-
- /* 开始定时器PWM输出 */
- HAL_TIM_PWM_Start(&g_timx_cplm_handle, ATIM_TIMX_CPLM_CHY);
- HAL_TIMEx_PWMN_Start(&g_timx_cplm_handle, ATIM_TIMX_CPLM_CHY);
- }
复制代码从上面的代码中可以看出,初始化函数初始化了TIM1的PWM输出,同时配置了TIM1的PWM输出通道,并且也配置了TIM1的刹车和死区时间,最后开始了TIM1的PWM输出。 高级定时器驱动中配置PWM占空比和死区时间的函数,如下所示: - /**
- *@brief 设置高级定时器互补输出带死区控制
- *@param ccr: 输出比较值
- *@param dtg: 死区时间
- *@retval 无
- */
- voidatim_timx_cplm_set(uint16_t ccr, uint8_t dtg)
- {
- g_break_dead_time_config_struct.DeadTime = dtg; /* 死区时间 */
- HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_handle, /* 配置死区时间参数 */
- &g_break_dead_time_config_struct);
- __HAL_TIM_MOE_ENABLE(&g_timx_cplm_handle); /* 使能主输出 */
- ATIM_TIMX_CPLM->CCR1 = ccr; /* 设置比较寄存器 */
- }
复制代码从上面的代码中可以看出,该函数配置了TIM1的死区时间和输出比较值,因为配置PWM的占空比就是配置对应通道的输出比较值。
23.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_cplm_init(1000 - 1, 72 - 1); /* 初始化高级定时器互补输出带死区控制 */
- atim_timx_cplm_set(300 - 1, 100); /* 设置高级定时器互补输出带死区控制 */
-
- while (1)
- {
- if (++t == 20)
- {
- t = 0;
- LED0_TOGGLE();
- }
-
- delay_ms(10);
- }
- }
复制代码从上面的代码中可以看到,TIM1的自动重装载值配置为(1000-1),TIM1的预分频器数值配置为(72-1),并且TIM1的时钟频率为72MHz,因此TIM1的计数频率为1MHz,且TIM1每计数1000次溢出一次,因此溢出频率为1KHz,因此TIM1通道1及其互补通道输出两路互补PWM的频率也应该为1KHz。 随后配置了TIM1通道1的比较值为(300-1),与自动重装载值的比值为30%,因此输出PWM的占空比也应该为30%,同时配置了死区时间为100,因为TIM1的时钟频率为72MHz,因此死区时间在配置为100的情况下,对应的具体时间为(100*1/72MHz)ns≈595ns。
23.3 下载验证 在完成编译和烧录操作后,可以通过示波器观察PA8引脚和PA7引脚输出的两路PWM,可以发现,这两路PWM为互补PWM,且频率为1KHz、占空比为30%、死区时间大约为595ns。应为是能了刹车和自动输出功能,因此将PA6引脚接入有效的高电平后,可以看到两路PWM都被禁止输出了,撤销PA6引脚接入的高电平后,可以看到两路PWM有自动恢复输出了。 |