具体如下:
1、如果加入D抖动的特别厉害,试试只用PI控制。
2、还有PID参数都是一步一步调出来的,我建议你做个上位机,就是个简单的VB串口程序,用来设置PID参数
3、然后在单片机这边弄个串口接收程序,这里就是个简单的串口程序,人人都会,把接收到的PID存储在缓冲区里。
4、然后单片机程序直接调用。单片机带EEPROM的话,当接收到改变的PID参数时,存储这些参数。去STC官网下你的单片机资料,上面有EEPROM测试程序,直接套用。
我这有51的#include#include"global_varible.h"/*****************************************************************************模块名:PID*描述:PID调节子程序*采用PID-PD算法。在偏差绝对值大于△e时,用PD算法,以改善动态品质。*当偏差绝对值小于△e时,用PID算法,提高稳定精度。*PIDout=kp*e(t)+ki*[e(t)+e(t-1)++e(1)]+kd*[e(t)-e(t-1)]*============================================================================*入口:无*出口:无*改变:PID_T_Run=加热时间控制*****************************************************************************/voidPID_Math(void){signedlongee1//偏差一阶//signedlongee2//偏差二阶signedlongd_out//积分输出if(!Flag_PID_T_OK)returnFlag_PID_T_OK=0Temp_Set=3700//温度控制设定值37.00度PID_e0=Temp_Set-Temp_Now//本次偏差ee1=PID_e0-PID_e1//计算一阶偏差//ee2=PID_e0-2*PID_e1+PID_e2//计算二阶偏差if(ee1>500)//一阶偏差的限制范围ee1=500if(ee1200)//积分最多累计的温差PID_e_SUM=200if(PID_e_SUM100)//如果温度相差大于1度时积分累计限制{if(PID_e_SUM>100)PID_e_SUM=100if(PID_e_SUM150)PID_e_SUM=150if(PID_e_SUM>0)//当前温度高于设定温度0.5度时削弱积分正输出d_out>>=1}PID_Out+=d_out//PID比例,积分和微分输出}elsePID_e_SUM=0PID_Out/=100//恢复被PID_Out系数放大的倍数if(PID_Out>200)PID_Out=200if(PID_Out300)//当前温度比设定温度低3度则全速加热PID_Out=200if(PID_e0<-20)//当前温度高于设定温度0.2度则关闭加热PID_Out=0Hot_T_Run=PID_Out//加热时间控制输出PID_e2=PID_e1//保存上次偏差PID_e1=PID_e0//保存当前偏差}////////////////////////////////////////////////////////////voidPID_Math()end.//P1.1(T0):Count They Distance//P0.4:Tx
//P0.5:Rx
#include <C8051F310.h>//SFR declarations
#include <stdio.h>//Standard I/O definition file
#include <math.h>//Math library file
#include <Intrins.h>
#include <absacc.h>
unsigned int j,i
char a=0
unsigned int t=0
//sbit led=P0^2
sbit vls=P0^4//P0.4(GPIO):给定左轮方向.
sbit vlf=P0^6//P0.6(T0) :反馈左轮速度.
sbit dlf=P1^0//P1.0(GPIO):反馈左轮方向.
//P0.2(PWM0):给定右轮速度.
sbit vrs=P0^5//P0.5(GPIO):给定右轮方向.
sbit vrf=P0^7//P0.7(T0) :反馈右轮速度.
sbit drf=P1^1//P1.1(GPIO):反馈右轮方向.
int ol//左轮给定值
int len
int len_1,len_2
int lyn_1,lyn_2
int vl1,vl2//反馈左轮速度值(取样周期内的方波数)
int lfz//运算后赋给PWM的值
int lyn,lynn
int lun=0,lun_1=0//偏差校正值 即校正PWM输出
int lunp,luni,lund//PID 校正值
int or//右轮给定值
int ren
int ren_1,ren_2
int ryn_1,ryn_2
int vr1,vr2//反馈右轮速度值(取样周期内的方波数)
int rfz//运算后赋给PWM的值
int ryn,rynn
int run=0,run_1=0//偏差校正值 即校正PWM输出
int runp,runi,rund//PID 校正值
float kp=2.0//比例系数1.8
float kd=0.2//微分系数0.4
float lki//积分系数
void pio_init(void)
void sys_init(void)
void t01_init(void)
void TIME3_INT(void)
void PID(void)
void interrupt_init(void)
void delay(unsigned int x)
void pwm1_1(void)
void main(void)
{
PCA0MD &= ~0x40//关闭
pio_init()//P11为测距输入端
sys_init()
t01_init()
pwm1_1()
TIME3_INT()
interrupt_init()
vls=1vrs=0
while(1)
{
ol=50
or=50
delay(1000)
ol=100
or=100
delay(1000)
ol=-50
or=50
delay(1000)
}
}
void PID(void)
{
/****************左轮PID调节******************/
if(dlf==1)
{
lyn=(vl2*256+vl1)//dlf是左轮反馈方向,0表示向前 vl=TL0
}
else
{
lyn=-(vl2*256+vl1)//dlf=1表示是向后退,速度应该为负值
}
len=ol-lyn//误差=给定速度-反馈速度(取样周期内的方波数)
if(abs(len)<8)//30
{
lki=1.4//ki值的确定1.4
}
else
{
lki=0.05//积分系数:如果 | 给定值-反馈值 | 太大
} //则就可以不引入积分,或者引入的很小0.05
lunp=kp*(len-len_1)//比例校正
luni=lki*len//积分校正
lund=kd*(len-2*len_1+len_2)//微分校正
lun=lunp+luni+lund+lun_1//总校正
/*************新旧数据更新*************************/
len_2=len_1
len_1=len//len:当前取样周期内出现的速度偏差len_1:上次取样周期内出现的速度偏差
lun_1=lun//lun:当前取样周期内得出的PWM校正值lun_1:上次取样周期内得出的PWM校正值
/*************新旧数据更新*************************/
if(lun>255)
{
lun=255//正速度
}
if(lun<-255)
{
lun=-255//负速度
}
if(lun<0)
{
vls=1
PCA0CPH0=-lun
}
if(lun>=0)
{
vls=0
PCA0CPH0=lun
}
/****************右轮PID调节******************/
if(drf==0)
{
ryn=(vr2*256+vr1)//drf是右轮反馈方向,0表示向前 vl=TL0
}
else
{
ryn=-(vr2*256+vr1)//dlf=1表示是向后退,速度应该为负值
}
ren=or-ryn//误差=给定速度-反馈速度(取样周期内的方波数)
if(abs(ren)<8)//30
{
lki=1.4//ki值的确定1.4
}
else
{
lki=0.05//积分系数:如果 | 给定值-反馈值 | 太大
} //则就可以不引入积分,或者引入的很小0.05
runp=kp*(ren-ren_1)//比例校正
runi=lki*ren//积分校正
rund=kd*(ren-2*ren_1+ren_2)//微分校正
run=runp+runi+rund+run_1//总校正
/*************新旧数据更新*************************/
ren_2=ren_1
ren_1=ren//len:当前取样周期内出现的速度偏差len_1:上次取样周期内出现的速度偏差
run_1=run//lun:当前取样周期内得出的PWM校正值lun_1:上次取样周期内得出的PWM校正值
/*************新旧数据更新*************************/
if(run>255)
{
run=255//正速度
}
if(run<-255)
{
run=-255//负速度
}
if(run<0)
{
vrs=1
PCA0CPH1=-run
}
if(run>=0)
{
vrs=0
PCA0CPH1=run
}
//因为这里的PCA0CPH0越大,对应的电机速度越小,所以要255来减一下
}
void pio_init(void)
{
XBR0=0x00//0000 0001
XBR1=0x72//0111 0010 时能弱上拉 T0T1连接到脚口P06、P07 CEX0、CEX1连接到脚口P00、P01
P0MDIN=0xff//模拟(0)数字(1) 1111 0011
P0MDOUT=0xc3//开漏(0)推挽(1) 1111 1111
P0SKIP=0x3c//0011 1100
P1MDIN=0xff//1111 1111
P1MDOUT=0xfc//
P1SKIP=0x00//1111 1111
}
void sys_init(void) //12MHz
{
OSCICL=0x43
OSCICN=0xc2
CLKSEL=0x00
}
void pwm1_1(void) //PWM的初始化
{
PCA0MD=0x08//PCA时钟为12分频
PCA0CPL0=200//左轮
PCA0CPM0=0x42//设置左轮为8位PWM输出
PCA0CPH0=200
PCA0CPL1=200//平衡校正
PCA0CPM1=0x42//设置为8位PWM输出
PCA0CPH1=200
PCA0CN=0x40//允许PCA工作
}
void t01_init(void)
{
TCON=0x50//计数器1、2允许
TMOD=0x55//定时器1、2采用16位计数功能
CKCON=0x00
TH1=0x00//用于采集左轮的速度
TL1=0x00
TH0=0x00//用于采集右轮的速度
TL0=0x00
}
void TIME3_INT(void)
{
TMR3CN = 0x00//定时器3为16位自动重载
CKCON &= ~0x40
TMR3RLL = 0xff
TMR3RLH = 0xd7
TMR3L = 0xff
TMR3H = 0xd7
TMR3CN |= 0x04
}
void T3_ISR() interrupt 14 //定时器3中断服务程序
{
//led=~led
EA=0
TCON &=~0x50//关闭计数器0、1
vl1=TL0//取左轮速度值
vl2=TH0
vr1=TL1//取右轮速度值
vr2=TH1
TH1=0x00
TL1=0x00
TH0=0x00
TL0=0x00
PID()//PID处理
TMR3CN &=~0x80//清中断标志位
TCON |=0x50//重新开计数器0、1
EA=1
}
void interrupt_init(void)
{ IE=0x80
IP=0x00
EIE1|=0x80
EIP1|=0x80
}
void delay(unsigned int m) //延时程序
{
for(i=0i<2000i++)
{
for(j=0j<mj++){_nop_()_nop_()}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)