STM32G474之TIM1输出PWM信号,互补输出,支持死区时间和刹车。PWM第1通道输出引脚配置:TIM1_CH1映射到PA8,TIM1_CH1N映射到PA7,TIM1_BKIN映射到PA6,用作刹车输入信号。当刹车时,停止PWM波形输出。在使用“比较输出通道2”时,需要将PA11引脚复用为TIM1_BKIN2,用作刹车输入。
1、测试程序
void Timer1_Init(void)
{
TIM_HandleTypeDef htim1;
GPIO_InitTypeDef GPIO_InitStruct = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
__HAL_RCC_TIM1_CLK_ENABLE(); //使能“定时器1”的时钟,Enable TIM1 clock
__HAL_RCC_GPIOA_CLK_ENABLE(); //GPIOA时钟使能
GPIO_InitStruct.Pin = GPIO_PIN_8;
//选择引脚编号8
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用功能推挽模式
GPIO_InitStruct.Pull = GPIO_PULLUP; //设置上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
//将PA8引脚复用为TIM1_CH1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//根据GPIO_InitStruct结构变量指定的参数初始化GPIOA的外设寄存器
GPIO_InitStruct.Pin = GPIO_PIN_7;
//选择引脚编号7
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用功能推挽模式
GPIO_InitStruct.Pull = GPIO_PULLUP; //设置上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
//引脚的输出速度为120MHz
GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
//将PA7引脚复用为TIM1_CH1N
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//根据GPIO_InitStruct结构变量指定的参数初始化GPIOA的外设寄存器
GPIO_InitStruct.Pin = GPIO_PIN_6;
//选择引脚编号6
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用功能推挽模式
GPIO_InitStruct.Pull = GPIO_PULLUP; //设置上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
//引脚的输出速度为120MHz
GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
//将PA6引脚复用为TIM1_BKIN,用作刹车输入
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//根据GPIO_InitStruct结构变量指定的参数初始化GPIOA的外设寄存器
// GPIO_InitStruct.Pin = GPIO_PIN_11;
// //选择引脚编号7
// GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用功能推挽模式
// GPIO_InitStruct.Pull = GPIO_PULLUP; //设置上拉
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
// //引脚的输出速度为120MHz
// GPIO_InitStruct.Alternate = GPIO_AF12_TIM1_COMP2;
// //在使用“比较输出通道2”时,需要将PA11引脚复用为TIM1_BKIN2,用作刹车
// HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// //根据GPIO_InitStruct结构变量指定的参数初始化GPIOA的外设寄存器
htim1.Instance = TIM1;
htim1.Init.Period = PERIOD_VALUE; //周期值99
htim1.Init.Prescaler = (17-1); //16表示设置TIM1预分频器为17
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
//设置时钟分频系数,TIM1_CR1中的CKD[9:8]=00b,tDTS=Ttim_ker_ck;
//tim_ker_ck位定时器内核时钟,也就是定时器的计数器输入时钟
//溢出时间为(99+1)*1*17/170000000/1=10us
//最大误差为17/170000000=0.1us
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.RepetitionCounter = 0;//重复计数(1-0)次,产生1次中断,比较重要
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_PWM_Init(&htim1);//将TIM1初始化为PWM
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;//TIMx_EGR.UG位用作产生TIM1_TRGO触发信号
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;//TIMx_EGR.UG位用作产生TIM1_TRGO2触发信号
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;//Master/slave mode is selected
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
//Configures the TIM in master mode.
sConfigOC.OCMode = TIM_OCMODE_PWM1; //设置为PWM1模式
sConfigOC.Pulse = PULSE_WIDTH_VALUE1; //比较值1,用来设置输出脉宽
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; //“OC输出极性”非空闲状态时,为高电平有效
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; //“OCN输出极性”非空闲状态时,为高电平有效
sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
//定时器输出快速状态:“输出比较快速”使能,因为PWM输出频率高,还是用快速比较
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; //“OC的空闲状态”为低电平
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; //“OCN的空闲状态”为低电平
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
//初始化“比较输出1通道”
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;//TIM_OSSR_DISABLE;
//运行模式下的OFF状态:
//TIMx_BDTR寄存器bit11(OSSR),OSSR=0,当处于“不活动”状态时,OC/OCN输出不使能,被定时器释放,强制进入Hi-Z状态。
//TIMx_BDTR寄存器bit11(OSSR),OSSR=1,当不活动时,OC/OCN输出会启用其非活动电平。
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;//TIM_OSSI_DISABLE;
//空闲模式下的OFF状态:
//TIMx_BDTR寄存器bit10(OSSI),OSSI=0,当不活动时,OC/OCN输出不使能,被定时器释放,强制进入Hi-Z状态。
//TIMx_BDTR寄存器bit10(OSSI),OSSI=1,当不活动时,OC/OCN输出强制使用其空闲状态的电平
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
//TIMx_BDTR寄存器bit9:8(LOCK[1:0])
//LOCK[1:0]=00b,无写保护;
//LOCK[1:0]=01b,TIMx_BDTR寄存器中的“DTG[7:0],BKBID,BKE,BKP,AOE”,TIMx_CR2寄存器中的“OISx和OISxN”,写保护;
//锁定位在CPU复位后只能写入一次。TIMx_BDTR寄存器一旦被写入,则它们的内容会被冻结,直到下一次CPU复位时才能改写。
sBreakDeadTimeConfig.DeadTime = 85;
//死区时间:当时钟分频系数htim1.Init.ClockDivision=0时,死区时间DT=85*(1/170000000)=0.5us
//TIMx_BDTR寄存器bit7:0(DTG[7:0])
//只要锁定级别1、2或3已经被编程(TIMx_BDTR寄存器中的锁定位LOCK[1:0]),就不能修改死区时间
//DTG[7:5]=0xx,死区时间DT=DTG[7:0] * tdtg,tdtg=tDTS.
//DTG[7:5]=10x,死区时间DT=(64+DTG[5:0]) * tdtg,Tdtg=2*tDTS
//DTG[7:5]=110,死区时间DT=(32+DTG[4:0]) * tdtg,Tdtg=8*tDTS
//DTG[7:5]=111,死区时间DT=(32+DTG[4:0]) * tdtg,Tdtg=16*tDTS
//时钟分频系数htim1.Init.ClockDivision
//TIMx_CR1寄存器bit9:8(CKD[1:0]),通常CKD[1:0]=00b,tDTS=ttim_ker_ck;
//CKD[1:0]=01b,tDTS=2*ttim_ker_ck;CKD[1:0]=10b,tDTS=4*ttim_ker_ck;CKD[1:0]=11b,保留
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
//使能TIM1_BKIN引脚检测
//TIMx_BDTR寄存器bit12(BKE),BKE=1b,“刹车功能”使能
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
//TIM1_BKIN引脚低电平有效
//TIMx_BDTR寄存器bit13(BKP),BKP=0b,“tim_brk刹车输入信号”低电平停止PWM波形输出
sBreakDeadTimeConfig.BreakFilter = 0;
//指定TIM1_BKIN引脚的“输入过滤器”
//TIMx_BDTR寄存器bit19:16(BKF[3:0]),BKF[3:0]=0000b,tim_brk可以异步操作刹车
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; //指定TIM1_BKIN引脚的“复用功能”
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; //关闭TIM1_BKIN2引脚检测,因为这里用不到"TIM1_BKIN2"
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; //TIM1_BKIN2引脚高电平有效
sBreakDeadTimeConfig.Break2Filter = 0; //指定TIM1_BKIN2引脚的“输入过滤器”
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; //指定TIM1_BKIN2引脚的“复用功能”
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
//刹车撤销后能自动恢复输出波形
// sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
//刹车撤销后不会自动恢复输出波形
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
//配置BKIN刹车引脚和死区时间
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
//启动PWM信号发生器:启动OC通道1
//Start PWM signals generation:Start channel 1
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);//开启互补通道1输出到TIM1_CH1N
}
Timer1.h程序如下:
#ifndef __Timer1_H__
#define __Timer1_H__
#include "stm32g4xx_hal.h"
#include "main.h"
#define PERIOD_VALUE (uint32_t)(100 - 1) //周期值
#define PULSE_WIDTH_VALUE1 (uint32_t)(100*0.5) //比较值1,用来设置输出脉宽
extern void Timer1_Init(void);
extern void Print_TIM1_input_frequency(void);
#endif
2、输出波形