标题:
请教一个PID程序问题分析
[打印本页]
作者:
小龙在此
时间:
2023-7-24 10:41
标题:
请教一个PID程序问题分析
pidout1=90 + PIDcontrol(setjiaodu,jiaodu); //pid算式这个90是哪里来的?具体指什么?
#include <reg52.h>
#include <intrins.H>
#include <math.H>
#include <stdio.h>
#define u8 unsigned char
#define uchar unsigned char
#define uint unsigned int
#define u16 unsigned int
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char Uint8; /* defined for unsigned 8-bits integer variable 无符号8位整型变量 */
typedef unsigned int Uint16; /* defined for unsigned 16-bits integer variable 无符号16位整型变量 */
typedef unsigned long Uint32; /* defined for unsigned 32-bits integer variable 无符号32位整型变量 */
sbit LCD_RS = P1^0; //液晶1602 RS端口
sbit LCD_RW = P1^1; //液晶1602 RS端口
sbit LCD_EP = P1^2; //液晶1602 EN端口
sbit PWM_PIN0 = P2^0 ;
sbit PWM_PIN1 = P2^1 ;
int setjiaodu = 40;//占空比最大100 6 16
u16 pwm;//占空比最大100 6 16
sbit Key_Set = P1^3 ;
sbit Key_Up = P1^4 ;
sbit Key_Dowm = P1^5 ;
uchar code table[] = {": "}; //设定速度初始化
uchar code table1[] = {" "}; // 动态显示初始化
uchar n , i,x,table2[5],table3[5],ge,shi,bai,flag1,key1n,temp;
///***********延时1MS程序***/
void delay(uint z)
{ uint x,y;
for(x=z;x>0;x--)
for(y=80;y>0;y--);
}
float kp = 0.70;
float ki = 0.0005;
float kd = 0.001;
float ee,eeh,p; //PID误差和误差累计
float pidout1,pidout2,pidout3;
float PIDcontrol( int uset , int feedback) //pid算式
{
float duk,D;
eeh=ee;
ee=uset*1.0-feedback*1.0;
p += ee;
D = ee -eeh;
duk=kp*ee+ki*p-kd*D;
return duk;
}
/******液晶写命令************/
void write_com(uchar com)
{ LCD_RS=0;
P0=com ;
// delay(1);
LCD_EP=1;
delay(1);
LCD_EP=0;
}
/*****************/
/********液晶写数据***********/
void write_data(uchar date)
{ LCD_RS=1;
P0=date ;
//delay(1);
LCD_EP=1;
delay(1);
LCD_EP=0;
}
/*****************************/
/********显示动态速度数据*********/
void display_val(unsigned int zhuan)
{
table2[0]=zhuan/10000+0x30; //取万位
table2[1]=(zhuan%10000)/1000+0x30; //取千位
table2[2]=(zhuan%1000)/100+0x30; //取百位
table2[3]=(zhuan%100)/10+0x30; //取十位
table2[4]=zhuan%10+0x30; //取个位
// write_com(0x80+0x40+7);
// write_data(table2[0]);
// write_com(0x80+0x40+8);
// write_data(table2[1]);
write_com(0x80+0x40+4);
//write_data(table2[2]);
//write_com(0x80+0x40+10);
write_data(table2[3]);
//write_com(0x80+0x40+11);
write_data(table2[4]);
}
void dis(int z,unsigned int zhua,int x,int y)
{
table2[0]=zhua/10000+0x30; //取万位
table2[1]=(zhua%10000)/1000+0x30; //取千位
table2[2]=(zhua%1000)/100+0x30; //取百位
table2[3]=(zhua%100)/10+0x30; //取十位
table2[4]=zhua%10+0x30; //取个位
if(z==1)
write_com(0x80+x);
if(z==2)
write_com(0x80+0x40+x);
// write_data(table2[0]);
// write_data(table2[1]);
write_data(table2[2]);
if(y==1)
write_data('.');
write_data(table2[3]);
// if(y==2)
// write_data('.');
write_data(table2[4]);
write_com(0x80+16);
}
void dis0(int z,int zhua,int x,int y)
{
if(zhua>0)
{
table2[0]=zhua/10000+0x30; //取万位
table2[1]=' '; //取千位
table2[2]=(zhua%1000)/100+0x30; //取百位
table2[3]=(zhua%100)/10+0x30; //取十位
table2[4]=zhua%10+0x30; //取个位
if(z==1)
write_com(0x80+x);
if(z==2)
write_com(0x80+0x40+x-1);
write_data(table2[1]);
write_data(table2[2]);
write_data(table2[3]);
write_data(table2[4]);
write_com(0x80+16);
}
else
{
zhua=abs(zhua);
table2[0]=zhua/10000+0x30; //取万位
table2[1]='-'; //取千位
table2[2]=(zhua%1000)/100+0x30;
table2[3]=(zhua%100)/10+0x30; //取十位
table2[4]=zhua%10+0x30; //取个位
if(z==1)
write_com(0x80+x);
if(z==2)
write_com(0x80+0x40+x-1);
write_data(table2[1]);
write_data(table2[2]);
write_data(table2[3]);
write_data(table2[4]);
write_com(0x80+16);
}
}
/*--------------------------液晶初始化-----------------------------*/
void init_lcd()
{
LCD_EP=0;
write_com(0x38);
write_com(0x08);
write_com(0x06);
write_com(0x0c);
write_com(0x01);
//初始化显示
write_com(0x80+2);
for(i=0;i<13;i++)
{
write_data(table[i]);
delay(3);
}
write_com(0x80+0x40);
for(i=0;i<14;i++)
{
write_data(table1[i]);
delay(3);
}
}
void PWMInit()
{
TMOD|=0x01; //模式设置,00000001,可见采用的是定时器0,工作与模式1(M1=0,M0=1)。
TR0=1; //打开定时器
TH0=0Xff; //定时器设置,每隔100微秒发起一次中断。
TL0=0Xc1;
ET0=1; //开定时器0中断
EA=1; //开总中断
}
sbit ADCS = P2^4; //ADC0832 片选
sbit ADCLK = P2^5; //ADC0832 时钟
sbit ADDI = P2^6; //ADC0832 数据输入 /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
sbit ADDO = P2^6; //ADC0832 数据输出 /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上
static unsigned char Adc0832(unsigned char channel)
{
Uint8 i=0;
Uint8 j;
Uint16 dat=0;
Uint8 ndat=0;
Uint8 Vot=0;
if(channel==0)channel=2;
if(channel==1)channel=3;
ADDI=1;
_nop_();
_nop_();
ADCS=0;//拉低CS端
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿1
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
ADDI=channel&0x1;
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿2
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
ADDI=(channel>>1)&0x1;
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿3
ADDI=1;//控制命令结束
_nop_();
_nop_();
dat=0;
for(i=0;i<8;i++)
{
dat|=ADDO;//收数据
ADCLK=1;
_nop_();
_nop_();
ADCLK=0;//形成一次时钟脉冲
_nop_();
_nop_();
dat<<=1;
if(i==7)dat|=ADDO;
}
for(i=0;i<8;i++)
{
j=0;
j=j|ADDO;//收数据
ADCLK=1;
_nop_();
_nop_();
ADCLK=0;//形成一次时钟脉冲
_nop_();
_nop_();
j=j<<7;
ndat=ndat|j;
if(i<7)ndat>>=1;
}
ADCS=1;//拉低CS端
ADCLK=0;//拉低CLK端
ADDO=1;//拉高数据端,回到初始状态
dat<<=8;
dat|=ndat;
return(dat); //return ad data
}
Uint16 ReadAdc(unsigned char channel,unsigned int Number)//channel为通道 Number为输出值最大值
{
Uint8 Read_AD;
Uint16 AdResult;
Read_AD = Adc0832(channel);
AdResult = (Uint32)4*Read_AD*Number/255;//255
return AdResult;
}
#define KEYDELAY 20
void KeyScanDeal(Uint8 sMenu,Uint16 *Setnumb1,float *Setnumb2,float *Setnumb3,float *Setnumb4)
{
static Uint8 Menu = 0;
if(Key_Set == 0)
{
Menu ++;
if(Menu > sMenu)
Menu = 0;
while(Key_Set == 0);
}
switch (Menu)
{
case 1:
{
if(Key_Up == 0)
{
delay(KEYDELAY);
if(Key_Up == 0 && (*Setnumb1) < 100)
{
(*Setnumb1) =*Setnumb1 + 1;
}
}
else if(Key_Dowm == 0 && (*Setnumb1) > 0)
{
delay(KEYDELAY);
if(Key_Dowm == 0)
{
(*Setnumb1) =*Setnumb1 - 1;
}
}
break;
}
case 2:
{
if(Key_Up == 0 && (*Setnumb2) < 100)
{
delay(KEYDELAY);
if(Key_Up == 0)
{
(*Setnumb2) =*Setnumb2 + 0.01;
}
}
else if(Key_Dowm == 0 && (*Setnumb2) > 0)
{
delay(KEYDELAY);
if(Key_Dowm == 0)
{
(*Setnumb2) =*Setnumb2 -0.01;
}
}
break;
}
case 3:
{
if(Key_Up == 0 && (*Setnumb3) < 50)
{
delay(KEYDELAY);
if(Key_Up == 0)
{
(*Setnumb3) =*Setnumb3 + 0.0001;
}
}
else if(Key_Dowm == 0)
{
delay(KEYDELAY);
if(Key_Dowm == 0 && (*Setnumb3) > 0)
{
(*Setnumb3) =*Setnumb3 -0.0001;
}
}
break;
}
case 4:
{
if(Key_Up == 0 && (*Setnumb4) < 59)
{
delay(KEYDELAY);
if(Key_Up == 0)
{
(*Setnumb4) =*Setnumb4 + 0.001;
}
}
else if(Key_Dowm == 0 && (*Setnumb4) > 0)
{
delay(KEYDELAY);
if(Key_Dowm == 0)
{
(*Setnumb4) =*Setnumb4 -0.001;
}
}
break;
}
}
}
void main()
{
Uint8 i = 0;
int jiaodu = 0;
PWMInit();
LCD_RW=0;
init_lcd(); // 初始化液晶显示
PWMInit();
PWM_PIN1 = 1;
while(1)
{
i ++;
if(i%5 ==0)
{
KeyScanDeal(4,&setjiaodu,&kp,&ki,&kd);
dis(1,setjiaodu,0,2);
dis(1,jiaodu,6,2);
dis(2,kp*100,0,2);
dis(2,ki*10000,5,2);
dis(2,kd*1000,9,2);
}
jiaodu = ReadAdc(0,80) - 156;
pidout1=90 + PIDcontrol(setjiaodu,jiaodu); //pid算式
if(pidout1 > 100)
{
pwm = 99;
}
else if(pidout1 <1)
{
pwm = 1;
}
else
{
pwm = pidout1;
}
}
}
void time0() interrupt 1
{
static int cnt = 0;
if(cnt <= pwm)
{
PWM_PIN0 = 1;
}
else
{
PWM_PIN0 = 0;
}
cnt++;
if(cnt > 100)
{
cnt = 0;
}
TH0=0Xff;
TL0=0Xc1;
}
复制代码
作者:
Hephaestus
时间:
2023-7-24 15:33
明显是PWM需要加上这个常数,为什么要加只能去查你的单片机手册PWM寄存器部分。
作者:
xuyaqi
时间:
2023-7-24 15:33
PID系统和实际现场联系非常紧密,离开实际现场,有些程序不好理解很正常。这里的90是编程者根据调试觉得,有这个90系统会比较快达到平衡。这里的90是输出从90开始控制调整,而不是0或其他.
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1