小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)
小白从零开始:STM32双闭环(速度环、位置环)电机控制(硬件篇)
前言
小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)
杭州研究生手把手教你搞不定STM32
使用工具:
1.语言:C语言
2.代码编译:KEIL5、
3.代码烧录:FLYMCU
提示:以下是本篇文章正文内容,下面案例可供参考
一、电机测速
#include "encoder.h"
void Encoder_TIM4_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//ʹÄܶ¨Ê±Æ÷4µÄʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//ʹÄܶ˿ÚB
/*- Õý½»±àÂëÆ÷ÊäÈëÒý½Å PB->6 PB->7 -*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;//¶Ë¿ÚÅäÖÃ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //³õʼ»¯GPIOB
/*- TIM4±àÂëÆ÷ģʽÅäÖà -*/
//TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Period = 65535;//¼Æ´ÎÊý;ÉèÖüÆÊýÆ÷×Ô¶¯ÖØ×°ÔØ
TIM_TimeBaseStructure.TIM_Prescaler = 0;//Ô¤·ÖƵÆ÷
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;//Ñ¡ÔñʱÖÓ·ÖƵģʽ£º²»·ÖƵ
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//Á¬ÐøÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge); //ÅäÖñàÂëÆ÷ģʽ´¥·¢Ô´ºÍ¼«ÐÔË«±ßÑؼì²â ²»ÖªµÀ¿ÉÒÔ¿´¼¼ÊõÊÖ²áÉÏÃæÓнéÉܱàÂëÆ÷ģʽ
//ʹÓñàÂëÆ÷ģʽ3
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 Ñ¡ÔñÊäÈë¶Ë IC1Ó³Éäµ½TI1ÉÏ
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //ÉÏÉýÑز¶»ñ
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Ó³Éäµ½TI1ÉÏ
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //ÅäÖÃÊäÈë·ÖƵ,²»·ÖƵ
TIM_ICInitStructure.TIM_ICFilter = 0x01;//IC1F=0000 ÅäÖÃÊäÈëÂ˲¨Æ÷ ²»ÂË
//
TIM_ICInit(TIM4, &TIM_ICInitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//ÇÀÕ¼ÓÅÏȼ¶2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //×ÓÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM4,0);
TIM_Cmd(TIM4, ENABLE); //Æô¶¯TIM4¶¨Ê±Æ÷
}
__IO int16_t EncoderOverflowCnt = 0;
//¶¨Ê±Æ÷4ÖжϷþÎñ³ÌÐò
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
if((TIM4->CR1 & TIM_CounterMode_Down) != TIM_CounterMode_Down)
{
EncoderOverflowCnt++;/*±àÂëÆ÷¼ÆÊýÖµ[ÏòÉÏ]Òç³ö*/
}
else
{
EncoderOverflowCnt--;/*±àÂëÆ÷¼ÆÊýÖµ[ÏòÏÂ]Òç³ö*/
}
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update); //Çå³ýÖжϱê־λ
}
int Read_Speed(void)
{
int Encoder_TIM;
Encoder_TIM= (short)TIM4 -> CNT;
TIM4 -> CNT=0;
return Encoder_TIM;
}
二、电机PID控制算法
记得PID参数自己调一下哦
/**************************************************************************
º¯Êý¹¦ÄÜ£ºÔöÁ¿PI¿ØÖÆÆ÷
Èë¿Ú²ÎÊý£º±àÂëÆ÷²âÁ¿Öµ£¬Ä¿±êËÙ¶È
·µ»Ø Öµ£ºµç»úPWM
¸ù¾ÝÔöÁ¿Ê½ÀëÉ¢PID¹«Ê½
pwm+=Kp[e£¨k£©-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k)´ú±í±¾´ÎÆ«²î
e(k-1)´ú±íÉÏÒ»´ÎµÄÆ«²î ÒÔ´ËÀàÍÆ
pwm´ú±íÔöÁ¿Êä³ö
ÔÚÎÒÃǵÄËٶȿØÖƱջ·ÏµÍ³ÀïÃ棬ֻʹÓÃPI¿ØÖÆ
pwm+=Kp[e£¨k£©-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_P(int Encoder,int Target)
{
static int pwmout=0,last_error=0,last_last_error=0;
int error =Target - Encoder;
int d_error=error-last_error;
int dd_error = -2*last_error+error+last_last_error;
// //ËÀÇøãÐÖµ
// if((error>-cu_error_zone)&&(error<cu_error_zone))
// {
// error=0;
// d_error=0;
// dd_error=0;
// }
pwmout+=P*d_error/10 +I*error/10+D*dd_error/10;
last_last_error=last_error;
last_error = error;
if(pwmout > 1000) pwmout = 1000;
if(pwmout <=0) pwmout = 0;
return pwmout;
}
/**************************************************************************
º¯Êý¹¦ÄÜ£ºÔöÁ¿PI¿ØÖÆÆ÷
Èë¿Ú²ÎÊý£º±àÂëÆ÷²âÁ¿Öµ£¬Ä¿±êËÙ¶È
·µ»Ø Öµ£ºµç»úPWM
¸ù¾ÝÔöÁ¿Ê½ÀëÉ¢PID¹«Ê½
pwm+=Kp[e£¨k£©-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k)´ú±í±¾´ÎÆ«²î
e(k-1)´ú±íÉÏÒ»´ÎµÄÆ«²î ÒÔ´ËÀàÍÆ
pwm´ú±íÔöÁ¿Êä³ö
ÔÚÎÒÃǵÄËٶȿØÖƱջ·ÏµÍ³ÀïÃ棬ֻʹÓÃPI¿ØÖÆ
pwm+=Kp[e£¨k£©-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_PI (int Encoder,int Target)
{
float KP = 0;
float KI = 0;
float KD = 0;
static int pwmout=0,last_error=0,last_last_error=0;
int error =Target - Encoder;
int d_error=error-last_error;
int dd_error = -2*last_error+error+last_last_error;
pwmout+=KP*d_error/10 +KI*error/10+KD*dd_error/10;
last_last_error=last_error;
last_error = error;
if(pwmout > 1000) pwmout = 1000;
if(pwmout <=0) pwmout = 0;
return pwmout;
}
/**************************************************************************
º¯Êý¹¦ÄÜ£ºÎ»ÖÃʽPID¿ØÖÆÆ÷
Èë¿Ú²ÎÊý£º±àÂëÆ÷²âÁ¿Öµ£¬Ä¿±êλÖÃ
·µ»Ø Öµ£ºµç»úPWM
¸ù¾ÝÔöÁ¿Ê½ÀëÉ¢PID¹«Ê½
pwm+=Kp[e£¨k£©+Ki*e(k)+Kd[e(k)-e(k-1)]
e(k)´ú±í±¾´ÎÆ«²î
e(k-1)´ú±íÉÏÒ»´ÎµÄÆ«²î ÒÔ´ËÀàÍÆ
pwm´ú±íÔöÁ¿Êä³ö
pwm+=Kp[e£¨k£©-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_PID (int Encoder,int Target)
{
static int pwmout=0,last_error=0,I_error=0;
int error=Target-Encoder;
int d_error=error-last_error;
//È¡¾ø¶ÔÖµ
// if(error>0)error=error;
// else error=-error;
//ËÀÇøãÐÖµ
if((error>-lo_error_zone)&&(error<lo_error_zone))
{
error=0;
I_error=0;
d_error=0;
}
//»ý·ÖÏî¡¢»ý·Ö·ÖÀë½Ï´óÆ«²îʱȥµô»ý·Ö×÷ÓÃ
if(error>lo_integral_start && error<lo_integral_max)
{
I_error+=error;
if(I_error>lo_integral_max)
{
I_error=lo_integral_max;
}
else if(I_error<-lo_integral_max)
{
I_error=-lo_integral_max;
}
}
//I_error+=error;
//λÖÃʽPIDËã·¨
pwmout+=KPP*error/10 +KII*I_error/10+KDD*d_error/10;
//Îó²î´«µÝ
last_error = error;
//PWMÏÞ·ù
if(pwmout > 1000) pwmout = 1000;
if(pwmout <=0) pwmout = 0;
//·µ»Øµ±Ç°Êµ¼ÊÖµ
return pwmout;
}
三、电机PWM输出
PWM占空比输出脉冲
#include "pwm.h"
#include "led.h"
//PWMÊä³ö³õʼ»¯
//arr£º×Ô¶¯ÖØ×°Öµ
//psc£ºÊ±ÖÓÔ¤·ÖƵÊý
void PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO,ENABLE);//¿ªÆôʱÖÓ
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//³õʼ»¯GPIO--PA8¡¢PA11Ϊ¸´ÓÃÍÆÍìÊä³ö
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseStructInit(&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);/*¡¾2¡¿*///TIM2
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(TIM1,&TIM_OCInitStruct);
TIM_OC4Init(TIM1,&TIM_OCInitStruct);
TIM_CtrlPWMOutputs(TIM1,ENABLE);//¸ß¼¶¶¨Ê±Æ÷רÊô--MOEÖ÷Êä³öʹÄÜ
TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);/*¡¾3¡¿*///ENABLE//OC1ԤװÔؼĴæÆ÷ʹÄÜ
TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable);//ENABLE//OC4ԤװÔؼĴæÆ÷ʹÄÜ
TIM_ARRPreloadConfig(TIM1,ENABLE);//TIM1ÔÚARRÉÏԤװÔؼĴæÆ÷ʹÄÜ
TIM_Cmd(TIM1,ENABLE);//¿ª¶¨Ê±Æ÷¡£
}
void Motor_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//¿ªÆôʱÖÓ
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//³õʼ»¯GPIO--PB12¡¢PB13¡¢PB14¡¢PB15ΪÍÆÍìÊä³ö
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//³õʼ»¯GPIO--PB12¡¢PB13¡¢PB14¡¢PB15ΪÍÆÍìÊä³ö
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
四、双闭环速度环在内、位置环在外
单闭环正转速度环
Motor_pwm=Incremental_PI(speed,set_speed); //»ñÈ¡PID¼ÆËãµÄPWMÖµ
TIM_SetCompare1(TIM1,Motor_pwm); //Êä³öPWMÖµ
LED0=0;
LED1=1;
单闭环正转位置环
Motor_pwm=Incremental_PID(position,set_potision); //»ñÈ¡PID¼ÆËãµÄPWMÖµ
TIM_SetCompare1(TIM1,Motor_pwm); //Êä³öPWMÖµ
LED0=0;
LED1=1;
双闭环正转位置环+速度环文章来源:https://www.toymoban.com/news/detail-658769.html
if((t++%2) == 0)
{
Motor_pwm=Incremental_PID(position,set_potision); //»ñÈ¡PID¼ÆËãµÄPWMÖµ
}
Motor_pwm=Incremental_PI(speed,Motor_pwm); //»ñÈ¡PID¼ÆËãµÄPWMÖµ
TIM_SetCompare1(TIM1,Motor_pwm); //Êä³öPWMÖµ
LED0=0;
LED1=1;
总结
本文仅仅简单介绍了软件驱动方面的配置,评论区欢迎讨论。文章来源地址https://www.toymoban.com/news/detail-658769.html
到了这里,关于【电机控制】小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!