硬件设备
42步进电机,步进电机驱动器,正点原子F429开发板
开发软件
keil5,Cube
综述
一般要精准的控制电机,就要控制单片机的引脚输出指定个数的PWM波,有多种可实现的方法,其中最好用的方法是用定时器级联输出固定个数PWM脉冲,虽然多用了一个定时器,但大大减少了CPU的处理资源。STM32的每个定时器可以通过另外一个定时器的某一个条件被触发而启动.这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件.这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式。
Cube配置定时器,主定时器为PWM输出,从定时器为门控模式
1.主定时器为TIM3,其中通道1配置为PWM输出,主模式的更新事件选为触发输入

Cube的配置为参考,一切以代码为准
void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim3.Instance = TIM3; //设置主定时器为TIM3
htim3.Init.Prescaler = 4-1; //设置PWM频率
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //设置计数模式为向上计数
htim3.Init.Period = 100-1; //设置占空比
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //设置为无分频
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; //更新事件被选为触发输入
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; //开启主从模式
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1; //设置PWM模式为PWM1
sConfigOC.Pulse = 50; //设置PWM占空比为50%(50/100)
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; //设置PWM空闲状态引脚拉低
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim3); //设置PA6复用为PWM输出引脚
HAL_TIM_Base_Stop(&htim3);
}
2.从定时器为TIM4,选为门控模式——触发输入
从为TIM4,主为TIM3,根据下图,所以从模式的触发时钟为ITR2
void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
htim4.Instance = TIM4; //设置从定时器为TIM4
htim4.Init.Prescaler =0; //设置从定时器频率为0
htim4.Init.CounterMode = TIM_COUNTERMODE_UP; //设置计数模式为向上计数
htim4.Init.Period =0xffff; //这个大于0就行
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //设置为无分频
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; //设置为内部时钟触发,即为TIM3
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED; //设置为门触发
sSlaveConfig.InputTrigger = TIM_TS_ITR2; //设置ITR2(tim3)为输入源
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; //设置触发模式为上升沿
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; //设置无预分频
sSlaveConfig.TriggerFilter = 0x0; //设置无滤波
if (HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_Base_Stop_IT(&htim4);
}
从定时器的频率一定要设为0,不然输出的PWM会加倍
中断处理函数
HAL里的中断处理函数要选HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim),当TIM4->CNT的值达到TIM4->ARR的值时触发中断,关闭主从定时器,清零中断标志位SR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
FLAG1_OK = 0;
if(htim==(&htim4))
{
//****************************************************//
if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_CC1) != RESET) //判断是否触发中断
{
__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1); //清除中断标志位
HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_1); //关闭主定时器的PWM输出
HAL_TIM_Base_Stop_IT(&htim4); //关闭从定时器的计数
//****************************************************//
}
delay_ms(1);
FLAG1_OK = 1;
}
}
脉冲输出主函数
中断函数关闭的,于此要重新开启,有始有终
while(1)
{
if(FLAG1_OK == 1 ) //标志判断
{ she10
__HAL_TIM_SET_AUTORELOAD(&htim4,10-1); //ARR装载要输出的PWM脉冲数
HAL_TIM_Base_Start_IT(&htim4); //从定时器计数开启
HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1); //主定时器PWM脉冲输出 }
}
分析仪实测波形
很漂亮整洁的10个PWM波,在1MHz以下挺准的,但上去了就多了一两个波,还需要细调。
这个是单定时器的单通道的程序,已经写好单定时器多通道的了,有时间再发。
有不足之处还请各位不吝赐教。
硬件设备
42步进电机,步进电机驱动器,正点原子F429开发板
开发软件
keil5,Cube
综述
一般要精准的控制电机,就要控制单片机的引脚输出指定个数的PWM波,有多种可实现的方法,其中最好用的方法是用定时器级联输出固定个数PWM脉冲,虽然多用了一个定时器,但大大减少了CPU的处理资源。STM32的每个定时器可以通过另外一个定时器的某一个条件被触发而启动.这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件.这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式。
Cube配置定时器,主定时器为PWM输出,从定时器为门控模式
1.主定时器为TIM3,其中通道1配置为PWM输出,主模式的更新事件选为触发输入

Cube的配置为参考,一切以代码为准
void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim3.Instance = TIM3; //设置主定时器为TIM3
htim3.Init.Prescaler = 4-1; //设置PWM频率
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //设置计数模式为向上计数
htim3.Init.Period = 100-1; //设置占空比
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //设置为无分频
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; //更新事件被选为触发输入
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; //开启主从模式
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1; //设置PWM模式为PWM1
sConfigOC.Pulse = 50; //设置PWM占空比为50%(50/100)
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; //设置PWM空闲状态引脚拉低
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim3); //设置PA6复用为PWM输出引脚
HAL_TIM_Base_Stop(&htim3);
}
2.从定时器为TIM4,选为门控模式——触发输入
从为TIM4,主为TIM3,根据下图,所以从模式的触发时钟为ITR2
void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
htim4.Instance = TIM4; //设置从定时器为TIM4
htim4.Init.Prescaler =0; //设置从定时器频率为0
htim4.Init.CounterMode = TIM_COUNTERMODE_UP; //设置计数模式为向上计数
htim4.Init.Period =0xffff; //这个大于0就行
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //设置为无分频
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; //设置为内部时钟触发,即为TIM3
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED; //设置为门触发
sSlaveConfig.InputTrigger = TIM_TS_ITR2; //设置ITR2(tim3)为输入源
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; //设置触发模式为上升沿
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; //设置无预分频
sSlaveConfig.TriggerFilter = 0x0; //设置无滤波
if (HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_Base_Stop_IT(&htim4);
}
从定时器的频率一定要设为0,不然输出的PWM会加倍
中断处理函数
HAL里的中断处理函数要选HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim),当TIM4->CNT的值达到TIM4->ARR的值时触发中断,关闭主从定时器,清零中断标志位SR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
FLAG1_OK = 0;
if(htim==(&htim4))
{
//****************************************************//
if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_CC1) != RESET) //判断是否触发中断
{
__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1); //清除中断标志位
HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_1); //关闭主定时器的PWM输出
HAL_TIM_Base_Stop_IT(&htim4); //关闭从定时器的计数
//****************************************************//
}
delay_ms(1);
FLAG1_OK = 1;
}
}
脉冲输出主函数
中断函数关闭的,于此要重新开启,有始有终
while(1)
{
if(FLAG1_OK == 1 ) //标志判断
{ she10
__HAL_TIM_SET_AUTORELOAD(&htim4,10-1); //ARR装载要输出的PWM脉冲数
HAL_TIM_Base_Start_IT(&htim4); //从定时器计数开启
HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1); //主定时器PWM脉冲输出 }
}
分析仪实测波形
很漂亮整洁的10个PWM波,在1MHz以下挺准的,但上去了就多了一两个波,还需要细调。
这个是单定时器的单通道的程序,已经写好单定时器多通道的了,有时间再发。
有不足之处还请各位不吝赐教。
举报