【电机控制】小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)

小白从零开始: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;

双闭环正转位置环+速度环

		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;

总结

本文仅仅简单介绍了软件驱动方面的配置,评论区欢迎讨论。

  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kisorge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值