STM32电机控制
stm32控制电机使用
设计目的:控制电机转速、转动距离
所涉及内容:步进电机、驱动芯片、定时器编码器功能、PWM输出功能
1.电机
1.1分类
直流电机:
步进电机
电机可根据需求选择直流电机或步进电机等其他类型;微型直流电机如不需要精确位置与方向切换可以直接输出PWM控制不使用驱动芯片。
1.2步进电机的特点
-
精确控制:每个步进都会转动一个固定的角度,一般从1.8度(200步/转)到0.9度(400步/转)不等。例如,雷赛电机42CME02, 步距角1.8°、保持转矩0.2~0.8 N.M、内置1000线增量式光电编码器、大转矩、低发热、高平稳性、高一致性。
-
定点控制:适合需要精确移位的应用。
-
高扭矩:在低速时具有较高的扭矩。
-
构造简单:相对简单的机械结构和控制。
-
常见类型:
-
永久磁铁步进电机:具有较高的扭矩,适合低速应用。
-
恒流步进电机:适合高扭矩应用,具备良好的响应特性。
-
混合式步进电机:结合了前两者的优点,兼具高扭矩和精度。
-
控制方式:
步进电机的控制通常通过微步控制器实现,微步技术可以提高电机的平滑性和精度。
2.驱动芯片
常见电机驱动芯片
- 步进电机驱动芯片:
- A4988:常用于控制两相步进电机,能够实现微步控制。
- DRV8825:具有更高的电压和电流容许范围,可以驱动更大功率的步进电机。
- bd63521:能够实现微步控制。
- 直流电机驱动芯片:
- L298N:一个双向直流电机驱动芯片,常用于机器人和电动轮车。
- TB6612FNG:比L298N更小巧、效率更高,适合低功耗项目。
- 伺服电机驱动芯片:
- MC33932:专为控制大型直流电机和伺服电机设计,提供高效能和保护功能。
3.timer配置
3.1 定时器PWM输出功能
/**********************************************************
** 函数名:PWM_Init_TIM1
** 功能描述: 定时器初始化函数
** 入口参数:预分频值,自动重装载值
** 输入参数: Psc(预分频值),Arr(自动重装载值)
** 输出参数: 无
***********************************************************/
void PWM_Init_TIM1(u16 Psc,u16 Arr)
{
GPIO_InitTypeDef GPIO_InitStruct; //GPIO初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; //定时器初始化
TIM_OCInitTypeDef TIM_OCInitStruct; //定时器通道初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_TIM2 | RCC_APB2Periph_AFIO,ENABLE);//开启时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; // 初始化GPIO--PB10为复用推挽输出 TIM2_CH3
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct); //GPIO初始化
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct); //用其默认值填充每个TIM_TimeBaseInitStruct成员
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //分频因子
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStruct.TIM_Period=Arr; //自动重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler=Psc; //预分频值
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct); //完成定时器初始化
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1; // 初始化输出比较
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=0;
TIM_OC1Init(TIM2,&TIM_OCInitStruct);//定时器通道1初始化
TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);// OC1预装载寄存器使能//CH1 TIM1
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_ARRPreloadConfig(TIM2,ENABLE); //允许或禁止在定时器工作时向ARR(自动重装载值)的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值,此处为允许
//TIM_CtrlPWMOutputs(TIM1,ENABLE);
//TIM_Cmd(TIM1,ENABLE); //定时器使能 可以先不使能输出,等需要动作时在开启
}
3.2定时器编码器功能
void TIM3_Int_Init()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//定时器设置-------------------------------------------------------------
TIM_TimeBaseInitStructure.TIM_Period = 1000-1; //重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1; //预分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分割
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
//编码器模式设置--------------------------------------------------------------
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//计数模式3
TIM_ICStructInit(&TIM_ICInitStructure); //将结构体中的内容缺省输入
TIM_ICInitStructure.TIM_ICFilter = 0;//滤波器值
TIM_ICInit(TIM3, &TIM_ICInitStructure); //将TIM_ICInitStructure中的指定参数初始化TIM3
//溢出中断设置--------------------------------------------------------------
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许TIM3溢出中断
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_SetCounter(TIM3,0); //TIM3->CNT=0
TIM_Cmd(TIM3, ENABLE);
}
//重装载值: (编码器线数-1 ) *4 因为我们是两相计数,一个脉冲信号4次计数,所以乘4,保证转完1整圈才触发中断
if(dir > 0) //向下计数 else //向上计数
4.应用代码
4.1步进电机修改转速:
void motor_start(unsigned short speed)
{
TIM1->ARR = speed;//重新设置重装载值
TIM1->CCR1 = speed/2;//重新设置占空比
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_Cmd(TIM1,ENABLE);
}
例如:设置速度1000,计算出周期是(1000-1)*(72-1)/72000000 = 1ms 频率为1k,表示1ms输出一个脉冲
4.2PWM输出中断
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
//可以记录输出脉冲数
}
}
4.3编码器计数中断
int circle_count=0;//圈数
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
if((TIM3->CR1>>4 & 0x01)==0) //DIR==0
circle_count++;
else if((TIM3->CR1>>4 & 0x01)==1)//DIR==1
circle_count--;
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
作者:tuui.