在伺服电机的控制过程中,使电机能够按照自己的想法转起来,一定要用到PWM输出控制,但是PWM该如何产生,频率如何控制,占空比如何调节?这就是我们今天要准备学习的部分:定时器产生PWM。
1.PWM的介绍
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。PWM原理示意图如下:
图中就是一个简单的PWM 原理示意图。图中,我们假定定时器工作在向上计数PWM模式,且当CNT<CCRx 时,输出0,当CNT>=CCRx 时输出1。那么就可以得到如上的PWM示意图:当CNT 值小于CCRx 的时候,IO 输出低电平(0),当CNT 值大于等于CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变CCRx 的值,就可以改变PWM 输出的占空比,改变ARR 的值,就可以改变PWM 输出的频率,这就是PWM 输出的原理。
如果是产生简单的PWM波形,我们使用STM32F7的定时器(除了TIM6 和7)均可以产生。但是我们在电机的控制中,不能使驱动电机的MOS管上下导通,必须产生互补的PWM波形才能满足要求,所以我们选用高级定时器来实现,在本开发板中使用定时器1来产生我们需要的波形。
2.定时器的简单介绍
高级定时器包含了通用定时器的基本功能外,还还会用到 4 个寄存器,来控制 PWM 。这四个寄存器分别是:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获 /比较使能寄存器(TIMx_CCER)、捕获 /比较寄存器(TIMx_CCR1~4)和刹车和死区寄存器(TIMx_BDTR)。我们要特别关注这四个寄存器,按照数据手册和自己的功能来进行配置。关于定时器的内容非常多,网上的资料也很多,在这里不在详细赘述。分享两个资料给大家参考:(1)电机控制基础——定时器基础知识与PWM输出原理(2)正点原子的资料:
STM32F7开发指南-HAL库版本_V1.1.part1.rar
(29.5 MB, 下载次数: 9)
STM32F7开发指南-HAL库版本_V1.1.part2.rar
(28.92 MB, 下载次数: 9)
3.定时器配置
(1)初始化TIM1,设置TIM1 的ARR 和PSC 等参数
定时器分频系数为2,计数模式为中心计数方式,PWM的频率为16KHz,不使用自动重装值。
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;//定时器1
htim1.Init.Prescaler = ((TIM_CLOCK_DIVIDER) - 1);//分频系数2-1
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;//计数模式为中心计数
htim1.Init.Period = ((PWM_PERIOD_CYCLES) / 2);//自动重装值108Mhz/16KHz
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;//定时器时钟2分频
htim1.Init.RepetitionCounter = (REP_COUNTER);//更新事件延后了6个PWM周期
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;//自动重装关闭
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)//初始化定时器
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)//初始化PWM
{
Error_Handler();
}
在这里要特别注意一个定时器配置参数: htim1.Init.RepetitionCounter = (REP_COUNTER);
TIM_RepetitionCounter 的作用是在本次定时结束后,再重装载定时 1次,进入中断。因为是6路PWM,所以这里设置的参数是6次,也就是6次PWM产生完成了,才进行定时器中断。
(2)触发模式
设置主从的触发模式:从模式使用选择ITR1作为输入源。
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;//选择从触发模式
sSlaveConfig.InputTrigger = TIM_TS_ITR1;//输入触发:选择ITR1作为输入源
if (HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) != HAL_OK)//初始化从模式
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;//失能定时器主模式输出触发配置
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;//从模式,设置是否使用定时器的被动触发
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
(3)设置PWM 模式,输出比较极性,比较值等参数
设置PWM为输出比较模式,互补输出极性,快速模式关闭。
sConfigOC.OCMode = TIM_OCMODE_PWM1;//PWM1输出比较模式
sConfigOC.Pulse = ((PWM_PERIOD_CYCLES) / 4);//设置电平跳变值108Mhz/16KHz
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;//输出比较极性
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;//互补输出比较极性
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;//输出比较快速失能
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;//选择空闲状态下非工作状态
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;//设置空闲状态下非工作状态
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)//PWM1通道1初始化
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)//PWM2通道1初始化
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)//PWM3通道1初始化
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM2;//PWM2输出比较模式
sConfigOC.Pulse = (((PWM_PERIOD_CYCLES) / 2) - (HTMIN));//设置电平跳变值108Mhz/16KHz/2-1
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)//PWM4通道1初始化
{
Error_Handler();
}
(4)刹车和死区时间配置
此时设置的死区时间为0,使能了刹车输入。
//刹车和死区时间配置
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;//设置运行模式下非工作状态选项
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;//设置在空载下非工作状态选项
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1; //锁电平参数
sBreakDeadTimeConfig.DeadTime = 0;//死区时间
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;//使能或失能TIMx刹车输入
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;//TIMx刹车输入管脚极性
sBreakDeadTimeConfig.BreakFilter = 0;//指定中断输入过滤器
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;//定时器BREAK2失能
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_LOW;//定时器Break2 输入极性
sBreakDeadTimeConfig.Break2Filter = 0;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;//失能自动输出功能
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)//初始化刹车死区时间参数
{
Error_Handler();
}
4.软件代码
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_SlaveConfigTypeDef sSlaveConfig = {0};//定时器从模式配置
TIM_MasterConfigTypeDef sMasterConfig = {0};//定时器主模式配置
TIM_OC_InitTypeDef sConfigOC = {0};//定时器比较模式配置
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};//定时器刹车和死区时间配置
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;//定时器1
htim1.Init.Prescaler = ((TIM_CLOCK_DIVIDER) - 1);//分频系数2-1
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;//计数模式为中心计数
htim1.Init.Period = ((PWM_PERIOD_CYCLES) / 2);//自动重装值108Mhz/16KHz
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;//定时器时钟2分频
htim1.Init.RepetitionCounter = (REP_COUNTER);//更新事件延后了6个PWM周期
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;//自动重装关闭
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)//初始化定时器
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)//初始化PWM
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;//选择从触发模式
sSlaveConfig.InputTrigger = TIM_TS_ITR1;//输入触发:选择ITR1作为输入源
if (HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) != HAL_OK)//初始化从模式
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;//失能定时器主模式输出触发配置
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;//从模式,设置是否使用定时器的被动触发
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;//PWM1输出比较模式
sConfigOC.Pulse = ((PWM_PERIOD_CYCLES) / 4);//设置电平跳变值108Mhz/16KHz
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;//输出比较极性
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;//互补输出比较极性
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;//输出比较快速失能
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;//选择空闲状态下非工作状态
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;//设置空闲状态下非工作状态
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)//PWM1通道1初始化
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)//PWM2通道1初始化
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)//PWM3通道1初始化
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM2;//PWM2输出比较模式
sConfigOC.Pulse = (((PWM_PERIOD_CYCLES) / 2) - (HTMIN));//设置电平跳变值108Mhz/16KHz/2-1
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)//PWM4通道1初始化
{
Error_Handler();
}
//刹车和死区时间配置
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;//设置运行模式下非工作状态选项
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;//设置在空载下非工作状态选项
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1; //锁电平参数
sBreakDeadTimeConfig.DeadTime = 0;//死区时间
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;//使能或失能TIMx刹车输入
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;//TIMx刹车输入管脚极性
sBreakDeadTimeConfig.BreakFilter = 0;//指定中断输入过滤器
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;//定时器BREAK2失能
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_LOW;//定时器Break2 输入极性
sBreakDeadTimeConfig.Break2Filter = 0;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;//失能自动输出功能
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)//初始化刹车死区时间参数
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}