stm32用pid控制编码电机
stm32硬件PID控制编码电机
stm32的定时器具有读取正交编码器的功能(所谓正交,就是波形相位互余的一对信号),其具体配置在之前的博客中我已经封装过函数了,没看过的朋友可以点击这里,位置式PID的封装函数也写过了,在这里。本文将以这些代码为例子,来写一个控制编码电机的代码。
首先,给出控制电机的代码,原理很简单,就是输出比较而已。
GuiStar_Motor.h:
#ifndef __GUISTAR_MOTOR_H__
#define __GUISTAR_MOTOR_H__
#include "stm32f10x.h" // Device header
#include "GuiStar_TIM.h"
#include "IO.h"
//电机的PWM选择TIM2通道1(A0),电机的正负极如下:
#define INA PAout(1)
#define INA_Port GPIOA
#define INA_Pin GPIO_Pin_1
#define INB PAout(2)
#define INB_Port GPIOA
#define INB_Pin GPIO_Pin_2
void GuiStar_Motor_Init(void);
void GuiStar_Motor_SetSpeed(int Speed);
#endif
GuiStar_Motor.c:
#include "GuiStar_Motor.h"
/**
* @brief 电机初始化
* @param 无
* @retval 无
*/
void GuiStar_Motor_Init(void)
{
IO_Init(INA_Port,INA_Pin,GPIO_Mode_Out_PP);
IO_Init(INB_Port,INB_Pin,GPIO_Mode_Out_PP);
Encoder_Init(TIM3);
GuiStar_PWM_Init(TIM2,1,1,7200,0);
}
/**
* @brief 设置电机速度
* @param Speed 电机速度,范围-7200~7200,正数正转,负数反转
* @retval 无
*/
void GuiStar_Motor_SetSpeed(int Speed)
{
if(Speed>0)
{
INA=1;
INB=0;
TIM_SetCompare1(TIM2,Speed);
}
else if(Speed==0)
{
INA=0;
INB=0;
TIM_SetCompare1(TIM2,0);
}
else if(Speed<0)
{
INA=0;
INB=1;
TIM_SetCompare1(TIM2,-Speed);
}
}
接下来是重点,PID控制的.c和.h文件:
GuiStar_Control.h:
#ifndef __GUISTAR_CONTROL_H__
#define __GUISTAR_CONTROL_H__
#include "GuiStar_TIM.h"
#include "GuiStar_Motor.h"
#include "GuiStar_PID.h"
//PID调参宏
#define GuiStar_P 0
#define GuiStar_I 0
#define GuiStar_D 0
void GuiStar_StartControl(void);//启动PID控制
void GuiStar_SetEncoderSpeed(int Encoder_Speed_Value);//设置编码电机的预期值
#endif
GuiStar_Control.c:
#include "GuiStar_Control.h"
void GuiStar_PID_Control_IRQHandler(void);//PID中断函数声明
GuiStar_PIDTypedef GuiStar_PID;//PID调参结构体声明
int PWM_Speed=0;//电机的PWM数值(是GuiStar_Motor_SetSpeed的实参)
int Task_Encoder_Speed=0;//电机的编码器预期速度,范围-200~200
/**
* @brief (1)开启定时器中断,每隔10mspid控制一次电机
(2)设置TIM4中断函数为PID中断函数
(3)PID调参
* @param
* @retval
*/
void GuiStar_StartControl(void)
{
GuiStar_TIM(TIM4,7200,100,1,1);//设置TIM410ms中断
GuiStar_TIM_SetTIM4IRQHandler(GuiStar_PID_Control_IRQHandler);//设置TIM4中断函数为PID_Control_IRQHandler
GuiStar_Motor_Init();//电机初始化
//PID参数设置
GuiStar_PID.KP=GuiStar_P;
GuiStar_PID.KI=GuiStar_I;
GuiStar_PID.KD=GuiStar_D;
}
/**
* @brief 设置本文件中的Task_Encoder_Speed变量(它是编码器速度的目标值)
* @param Encoder_Speed_Value 取值范围-200~200
* @retval 无
*/
void GuiStar_SetEncoderSpeed(int Encoder_Speed_Value)
{
Task_Encoder_Speed=Encoder_Speed_Value;
}
/**
* @brief 读取CNT此时的值,并清零CNT,此函数将在10ms中断函数中调用,则
它的值表示10ms内编码器的总次数,是反应速度大小的量
* @param 无
* @retval 编码器此时的值
*/
static int16_t GuiStar_GetMotor_Encoder_Speed(void)
{
return Encoder_GetSpeed(TIM3);
}
/**
* @brief 限幅PWM_Speed的值在合理的范围(-7200~7200)
* @param 无
* @retval 无
*/
static void GuiStar_Limit_PWM_Speed()
{
if(PWM_Speed<-7200) PWM_Speed=-7200;
else if(PWM_Speed>7200) PWM_Speed=7200;
}
/**
* @brief PID10ms中断函数,计算出本次控制应该输出的Speed变量,将变量限幅之后,以此变量来控制电机
* @param 无
* @retval 无
*/
void GuiStar_PID_Control_IRQHandler(void)
{
PWM_Speed=GuiStar_P_PID1(GuiStar_GetMotor_Encoder_Speed(), Task_Encoder_Speed, &GuiStar_PID);//PID控制
GuiStar_Limit_PWM_Speed();//速度限幅
GuiStar_Motor_SetSpeed(PWM_Speed);//按本次的控制结果控制电机
}
PID控制总结:
需要做五件事:
第一,完成电机,相关定时器,引脚,编码器接口等的初始化工作
第二,在中断函数中输出本次控制的值
第三,对本次控制的值进行限幅
第四,将限幅之后的值交给执行函数去执行控制电机
第五,PID调参
其中,PID调参是重中之重,不难发现,我写的代码pid三个参数都还是0,我还没调,哈哈,摆烂一天,明天继续!