编码器;pid;电机位置闭环控制
程序员文章站
2022-03-03 19:05:26
本文分为几个部分:1.编码器2.定时器输入捕获(把定时器初始化为编码器模式)3.pid闭环控速度编码器1.概述2.原理四倍频技术...
本文分为几个部分:
1.编码器
2.定时器输入捕获(把定时器初始化为编码器模式)
3.pid闭环控速度
编码器配置
编码器
1.概述
传感器-> 角速度或角位移------转化为------->电数字脉冲
2.原理
四倍频技术
转速计算方法:用捕获值(一秒内输出的脉冲数)/编码器线数(转速一圈输出脉冲数)/电机减数比(内部电机转动圈数与电机输出轴转动圈数比,即减速齿轮比)
2.定时器输入捕获(把定时器初始化为编码器模式)
编码器定时器配置
void Encoder_Init_TIM2(void)
{
RCC->APB1ENR|=1<<0; //TIM2时钟使能
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0XFFFFFF00;//PA0 PA1 为编码器的ab相
GPIOA->CRL|=0X00000044;//浮空输入
/* 把定时器初始化为编码器模式 */
TIM2->PSC = 0x0;//预分频器
TIM2->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值 65535
TIM2->CCMR1 |= 1<<0; //输入模式,IC1FP1映射到TI1上
TIM2->CCMR1 |= 1<<8; //输入模式,IC2FP2映射到TI2上
TIM2->CCER |= 0<<1; //IC1不反向
TIM2->CCER |= 0<<5; //IC2不反向
TIM2->SMCR |= 3<<0; //SMS='011' 所有的输入均在上升沿和下降沿有效
TIM2->CR1 |= 0x01; //CEN=1,使能定时器
}
void Encoder_Init_TIM4(void)
{
RCC->APB1ENR|=1<<2; //TIM4时钟使能
RCC->APB2ENR|=1<<3; //使能PORTb时钟
GPIOB->CRL&=0X00FFFFFF;//PB6 PB7
GPIOB->CRL|=0X44000000;//浮空输入
/* 把定时器初始化为编码器模式 */
TIM4->PSC = 0x0;//预分频器
TIM4->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值
TIM4->CCMR1 |= 1<<0; //输入模式,IC1FP1映射到TI1上
TIM4->CCMR1 |= 1<<8; //输入模式,IC2FP2映射到TI2上
TIM4->CCER |= 0<<1; //IC1不反向
TIM4->CCER |= 0<<5; //IC2不反向
TIM4->SMCR |= 3<<0; //SMS='011' 所有的输入均在上升沿和下降沿有效
TIM4->CR1 |= 0x01; //CEN=1,使能定时器
}
3.pid闭环控速度
在main函数中调用
Timer3_Init(99,7199);//=====10MS进一次中断服务函数,中断服务函数在control.c
定时器3配置函数
void Timer3_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1; //时钟使能
TIM3->ARR=arr; //设定计数器自动重装值
TIM3->PSC=psc; //预分频器7200,得到10Khz的计数时钟
TIM3->DIER|=1<<0; //允许更新中断
TIM3->DIER|=1<<6; //允许触发中断
TIM3->CR1|=0x01; //使能定时器
MY_NVIC_Init(1,3,TIM3_IRQn,2);
}
定时器3中断服务函数,其中用到的函数在下文实现
int Target_velocity=50; //设定速度控制的目标速度为50个脉冲每10ms
int TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//10ms定时中断
{
TIM3->SR&=~(1<<0); //===清除定时器1中断标志位
Encoder=Read_Encoder(2);//===读取编码器的值,M法测速,输出为每10ms的脉冲数
Led_Flash(100); //===LED闪烁;指示单片机正常运行
Moto1=Incremental_PI(Encoder,Target_velocity); //===速度PI控制器
Xianfu_Pwm(); //===PWM限幅
Set_Pwm(Moto1); //===赋值给PWM寄存器
}
return 0;
}
读定时器cnt计数函数
int Read_Encoder(u8 TIMX)
{
int Encoder_TIM;
switch(TIMX)
{
case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=0;break;
case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break;
case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break;
default: Encoder_TIM=0;
}
return Encoder_TIM;
}
增量式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_PI (int Encoder,int Target)
{
float Kp=20,Ki=30;
static int Bias,Pwm,Last_bias;
Bias=Encoder-Target; //计算偏差
Pwm+=Kp*(Bias-Last_bias)+Ki*Bias; //增量式PI控制器
Last_bias=Bias; //保存上一次偏差
return Pwm; //增量输出
}
位置式PID控制
/**************************************************************************
函数功能:位置式PID控制器
入口参数:编码器测量位置信息,目标位置
返回 值:电机PWM
根据位置式离散PID公式
pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]
e(k)代表本次偏差
e(k-1)代表上一次的偏差
∑e(k)代表e(k)以及之前的偏差的累积和;其中k为1,2,,k;
pwm代表输出
**************************************************************************/
int Position_PID (int Encoder,int Target)
{
float Position_KP=80,Position_KI=0.1,Position_KD=500;
static float Bias,Pwm,Integral_bias,Last_Bias;
Bias=Encoder-Target; //计算偏差
Integral_bias+=Bias; //求出偏差的积分
Pwm=Position_KP*Bias+Position_KI*Integral_bias+Position_KD*(Bias-Last_Bias); //位置式PID控制器
Last_Bias=Bias; //保存上一次偏差
return Pwm; //增量输出
}
/**************************************************************************
函数功能:赋值给PWM寄存器
入口参数:PWM
返回 值:无
**************************************************************************/
void Set_Pwm(int moto1)
{
if(moto1>0) AIN2=1, AIN1=0;
else AIN2=0, AIN1=1;
PWMA=myabs(moto1);
}
/**************************************************************************
函数功能:限制PWM赋值
入口参数:无
返回 值:无
**************************************************************************/
void Xianfu_Pwm(void)
{
int Amplitude=7100; //===PWM满幅是7200 限制在7100
if(Moto1<-Amplitude) Moto1=-Amplitude;
if(Moto1>Amplitude) Moto1=Amplitude;
}
源码:
本文地址:https://blog.csdn.net/yunddun/article/details/107773301
下一篇: C语言实现定时器