控制输出电压电流,所以需要速度快点的算法,怎么防止振荡?
简单来说就是用8位单片机实现工控PID的算法,因为工控PID算法是带浮点运算的,单片机算不过来,需要简单版的PID算法
PIDæ§å¶å¨8ä½åçæºä¸ä»ç¶æ广æ³çåºç¨ï¼æ¯å¦æ¸©åº¦æ§å¶ï¼å©ç¨æ¯ä¾ã积åãå¾®åè¡¥å¿æ¥åæ温补å¿æ§å¶ï¼å½ç¶ç±äºæè¿äºæ°å¦å¤çï¼ç¨Cè¯è¨ç¸å¯¹æ¹ä¾¿ä¸äºï¼ä»¥ä¸æ¯ä¸ä¸ªå ·ä½çå®ä¾ã
#include<reg51.h>
#include<intrins.h>
#include<math.h>
#include<string.h>
struct PID {
unsigned int SetPoint; // 设å®ç®æ Desired Value
unsigned int Proportion; // æ¯ä¾å¸¸æ° Proportional Const
unsigned int Integral; // 积åå¸¸æ° Integral Const
unsigned int Derivative; // å¾®åå¸¸æ° Derivative Const
unsigned int LastError; // Error[-1]
unsigned int PrevError; // Error[-2]
unsigned int SumError; // Sums of Errors
};
struct PID spid; // PID Control Structure
unsigned int rout; // PID Response (Output)
unsigned int rin; // PID Feedback (Input)
sbit data1=P1^0;
sbit clk=P1^1;
sbit plus=P2^0;
sbit subs=P2^1;
sbit stop=P2^2;
sbit output=P3^4;
sbit DQ=P3^3;
unsigned char flag,flag_1=0;
unsigned char high_time,low_time,count=0;//å 空æ¯è°èåæ°
unsigned char set_temper=35;
unsigned char temper;
unsigned char i;
unsigned char j=0;
unsigned int s;
/***********************************************************
延æ¶åç¨åº,延æ¶æ¶é´ä»¥12Mæ¶æ¯ä¸ºå,延æ¶æ¶é´ä¸º30usÃtime
***********************************************************/
void delay(unsigned char time)
{
unsigned char m,n;
for(n=0;n<time;n++)
for(m=0;m<2;m++){}
}
/***********************************************************
åä¸ä½æ°æ®åç¨åº
***********************************************************/
void write_bit(unsigned char bitval)
{
EA=0;
DQ=0; /*æä½DQ以å¼å§ä¸ä¸ªåæ¶åº*/
if(bitval==1)
{
_nop_();
DQ=1; /*å¦è¦å1ï¼åå°æ»çº¿ç½®é«*/
}
delay(5); /*延æ¶90usä¾DA18B20éæ ·*/
DQ=1; /*éæ¾DQæ»çº¿*/
_nop_();
_nop_();
EA=1;
}
/***********************************************************
åä¸åèæ°æ®åç¨åº
***********************************************************/
void write_byte(unsigned char val)
{
unsigned char i;
unsigned char temp;
EA=0;
TR0=0;
for(i=0;i<8;i++) /*åä¸åèæ°æ®ï¼ä¸æ¬¡åä¸ä½*/
{
temp=val>>i; /*移ä½æä½ï¼å°æ¬æ¬¡è¦åçä½ç§»å°æä½ä½*/
temp=temp&1;
write_bit(temp); /*åæ»çº¿å该ä½*/
}
delay(7); /*延æ¶120uså*/
// TR0=1;
EA=1;
}
/***********************************************************
读ä¸ä½æ°æ®åç¨åº
***********************************************************/
unsigned char read_bit()
{
unsigned char i,value_bit;
EA=0;
DQ=0; /*æä½DQï¼å¼å§è¯»æ¶åº*/
_nop_();
_nop_();
DQ=1; /*éæ¾æ»çº¿*/
for(i=0;i<2;i++){}
value_bit=DQ;
EA=1;
return(value_bit);
}
/***********************************************************
读ä¸åèæ°æ®åç¨åº
***********************************************************/
unsigned char read_byte()
{
unsigned char i,value=0;
EA=0;
for(i=0;i<8;i++)
{
if(read_bit()) /*读ä¸åèæ°æ®ï¼ä¸ä¸ªæ¶åºä¸è¯»ä¸æ¬¡ï¼å¹¶ä½ç§»ä½å¤ç*/
value|=0x01<<i;
delay(4); /*延æ¶80us以å®ææ¤æ¬¡é½æ¶åºï¼ä¹åå读ä¸ä¸æ°æ®*/
}
EA=1;
return(value);
}
/***********************************************************
å¤ä½åç¨åº
***********************************************************/
unsigned char reset()
{
unsigned char presence;
EA=0;
DQ=0; /*æä½DQæ»çº¿å¼å§å¤ä½*/
delay(30); /*ä¿æä½çµå¹³480us*/
DQ=1; /*éæ¾æ»çº¿*/
delay(3);
presence=DQ; /*è·ååºçä¿¡å·*/
delay(28); /*延æ¶ä»¥å®ææ´ä¸ªæ¶åº*/
EA=1;
return(presence); /*è¿ååºçä¿¡å·ï¼æè¯çåºçè¿å0,æ è¯çåè¿å1*/
}
/***********************************************************
è·å温度åç¨åº
***********************************************************/
void get_temper()
{
unsigned char i,j;
do
{
i=reset(); /*å¤ä½*/
} while(i!=0); /*1为æ åé¦ä¿¡å·*/
i=0xcc; /*åé设å¤å®ä½å½ä»¤*/
write_byte(i);
i=0x44; /*åéå¼å§è½¬æ¢å½ä»¤*/
write_byte(i);
delay(180); /*延æ¶*/
do
{
i=reset(); /*å¤ä½*/
} while(i!=0);
i=0xcc; /*设å¤å®ä½*/
write_byte(i);
i=0xbe; /*读åºç¼å²åºå 容*/
write_byte(i);
j=read_byte();
i=read_byte();
i=(i<<4)&0x7f;
s=(unsigned int)(j&0x0f); //å¾å°å°æ°é¨å
s=(s*100)/16;
j=j>>4;
temper=i|j; /*è·åç温度æ¾å¨temperä¸*/
}
/*====================================================================================================
Initialize PID Structure
=====================================================================================================*/
void PIDInit (struct PID *pp)
{
memset ( pp,0,sizeof(struct PID)); //å ¨é¨åå§å为0
}
/*====================================================================================================
PID计ç®é¨å
=====================================================================================================*/
unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
{
unsigned int dError,Error;
Error = pp->SetPoint - NextPoint; // åå·®
pp->SumError += Error; // 积å
dError = pp->LastError - pp->PrevError; // å½åå¾®å
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error // æ¯ä¾é¡¹
+ pp->Integral * pp->SumError // 积å项
+ pp->Derivative * dError); // å¾®å项
}
/***********************************************************
温度æ¯è¾å¤çåç¨åº
***********************************************************/
void compare_temper()
{
unsigned char i;
if(set_temper>temper) //æ¯å¦è®¾ç½®ç温度大äºå®é 温度
{
if(set_temper-temper>1) //设置ç温度æ¯å®é ç温度æ¯å¦æ¯å¤§äº1度
{
high_time=100; //å¦ææ¯ï¼åå ¨éå ç
low_time=0;
}
else //å¦ææ¯å¨1度èå´å ï¼åè¿è¡PID计ç®
{
for(i=0;i<10;i++)
{
get_temper(); //è·å温度
rin = s; // Read Input
rout = PIDCalc ( &spid,rin ); // Perform PID Interation
}
if (high_time<=100)
high_time=(unsigned char)(rout/800);
else
high_time=100;
low_time= (100-high_time);
}
}
else if(set_temper<=temper)
{
if(temper-set_temper>0)
{
high_time=0;
low_time=100;
}
else
{
for(i=0;i<10;i++)
{
get_temper();
rin = s; // Read Input
rout = PIDCalc ( &spid,rin ); // Perform PID Interation
}
if (high_time<100)
high_time=(unsigned char)(rout/10000);
else
high_time=0;
low_time= (100-high_time);
}
}
// else
// {}
}
/*****************************************************
T0ä¸ææå¡åç¨åºï¼ç¨äºæ§å¶çµå¹³ç翻转 ,40us*100=4mså¨æ
******************************************************/
void serve_T0() interrupt 1 using 1
{
if(++count<=(high_time))
output=1;
else if(count<=100)
{
output=0;
}
else
count=0;
TH0=0x2f;
TL0=0xe0;
}
/*****************************************************
串è¡å£ä¸ææå¡ç¨åºï¼ç¨äºä¸ä½æºé讯
******************************************************/
void serve_sio() interrupt 4 using 2
{
/* EA=0;
RI=0;
i=SBUF;
if(i==2)
{
while(RI==0){}
RI=0;
set_temper=SBUF;
SBUF=0x02;
while(TI==0){}
TI=0;
}
else if(i==3)
{
TI=0;
SBUF=temper;
while(TI==0){}
TI=0;
}
EA=1; */
}
void disp_1(unsigned char disp_num1[6])
{
unsigned char n,a,m;
for(n=0;n<6;n++)
{
// k=disp_num1[n];
for(a=0;a<8;a++)
{
clk=0;
m=(disp_num1[n]&1);
disp_num1[n]=disp_num1[n]>>1;
if(m==1)
data1=1;
else
data1=0;
_nop_();
clk=1;
_nop_();
}
}
}
/*****************************************************
æ¾ç¤ºåç¨åº
åè½ï¼å°å 空æ¯æ¸©åº¦è½¬å为å个å符ï¼æ¾ç¤ºå 空æ¯åæµå¾å°ç温度
******************************************************/
void display()
{
unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};
unsigned char disp_num[6];
unsigned int k,k1;
k=high_time;
k=k%1000;
k1=k/100;
if(k1==0)
disp_num[0]=0;
else
disp_num[0]=0x60;
k=k%100;
disp_num[1]=number[k/10];
disp_num[2]=number[k%10];
k=temper;
k=k%100;
disp_num[3]=number[k/10];
disp_num[4]=number[k%10]+1;
disp_num[5]=number[s/10];
disp_1(disp_num);
}
/***********************************************************
主ç¨åº
***********************************************************/
void main()
{
unsigned char z;
unsigned char a,b,flag_2=1,count1=0;
unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};
TMOD=0x21;
TH0=0x2f;
TL0=0x40;
SCON=0x50;
PCON=0x00;
TH1=0xfd;
TL1=0xfd;
PS=1;
EA=1;
EX1=0;
ET0=1;
ES=1;
TR0=1;
TR1=1;
high_time=50;
low_time=50;
PIDInit ( &spid ); // Initialize Structure
spid.Proportion = 10; // Set PID Coefficients æ¯ä¾å¸¸æ° Proportional Const
spid.Integral = 8; //积åå¸¸æ° Integral Const
spid.Derivative =6; //å¾®åå¸¸æ° Derivative Const
spid.SetPoint = 100; // Set PID Setpoint 设å®ç®æ Desired Value
while(1)
{
if(plus==0)
{
EA=0;
for(a=0;a<5;a++)
for(b=0;b<102;b++){}
if(plus==0)
{
set_temper++;
flag=0;
}
}
else if(subs==0)
{
for(a=0;a<5;a++)
for(b=0;a<102;b++){}
if(subs==0)
{
set_temper--;
flag=0;
}
}
else if(stop==0)
{
for(a=0;a<5;a++)
for(b=0;b<102;b++){}
if(stop==0)
{
flag=0;
break;
}
EA=1;
}
get_temper();
b=temper;
if(flag_2==1)
a=b;
if((abs(a-b))>5)
temper=a;
else
temper=b;
a=temper;
flag_2=0;
if(++count1>30)
{
display();
count1=0;
}
compare_temper();
}
TR0=0;
z=1;
while(1)
{
EA=0;
if(stop==0)
{
for(a=0;a<5;a++)
for(b=0;b<102;b++){}
if(stop==0)
disp_1(phil);
// break;
}
EA=1;
}
}
PWM是直接配置,在PWM周期确定的情况下,PWM 的占空比怎么确定,因为站空比直接影响到输出值和精度
追答时钟周期可以改,比如说分频或者倍频,配置占空比说白了就是配置一个周期里面高低电平所占用周期时间的比值,通过寄存器是可以配置的,不过要配置成PWM输出而不是捕获
追问大侠呀,我说的问题你都没有搞明白,我不是说PWM不能输出,而的怎么得到这个站空比的值?算法,不是配置问题
追答这个具体电压精度的问题我没自己搞过,不过给你俩网站吧,一个是用积分电路来算出来的,不过有误差,另外一个使用CPU自身带的ADC来检测并控制PWM的占空比的,参考一下,希望对你有帮助。
http://zhidao.baidu.com/question/292010575.html?an=0&si=7
http://zhidao.baidu.com/question/214807119.html?an=0&si=1