控制输出电压电流,所以需要速度快点的算法,怎么防止振荡?
简单来说就是用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
8位单片机PID控制PWM的算法如何实现,C语言计算?
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(...
PIC单片机输出PWM波的C语言源程序
void pwm_ccp2(unsigned char a,unsigned char b) \/\/右边PWM \/\/CCP2 模块的 PWM 工作方式,周期为(b+1)*4*Tosc*(TMR2前分频值),\/\/pwm高电平=a:CCP2CON(第四五位)Tosc*(TMR2前分频值){ CCPR2L=a; \/\/* 设置工作循环的高 8bit 为 a CCP2CON=0X0C; \/\/* 设置 CCP2 为 ...
求用单片机设计的PWM波形发生器(C语言写的)
TR0=1;CYCLE = 10;\/\/ 时间可以调整 这个是10调整 8位PWM就是256步 while(!Flag){ delay(20000); \/\/延时时间,从一个亮度到下一个亮度的间隔时间,速度快就能看到连续效果 PWM_ON++; \/\/这个使用较长延时,以便能看清楚变化过程 if(PWM_ON == CYCLE){ \/\/这个里可以添加其他程序 如...
单片机C语言PWM的典型程序谢谢
sbit K1 =P1^4 ; \/\/PWM值增加键 sbit K2 =P1^5 ; \/\/PWM值减少键 sbit BEEP =P3^7 ; \/\/蜂鸣器 unsigned char PWM=0x7f ; \/\/赋初值 void Beep();void delayms(unsigned char ms);void delay(unsigned char t);\/***\/ void main(){ P1=0xff;TMOD=0x21 ;TH0=0x...
PIC单片机中PWM怎么实现DA转换
PWM称之为脉宽调制,PIC单片机中的PWM是8位。输出频率大约为10K,如果转换为连续变化直流最简单的方法是阻容滤波即在输出引脚连接一1到4.7K电阻,电阻末端连接一10UF滤波电容输出极为稳定连续变化直流当然此种方法一般应用场合足矣。如果需要精度更高的就要采用运算放大器有源滤波了,一般采用LM324....
单片机pid算法控制步进电机的电路图和程序
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_...
基于单片机AT89c51的数字PID控制直流电机PWM调速系统C语言程序
首先弄清楚PID是一种控制算法!!!1,“如果用单片机恒温可以使温度到达预定值就停止加热,低了就加热,用一个温度传感器反馈,这样算是一个自动控制吗”你这是控制系统,但是效果会非常差,尤其是对于温度控制这种大惯性系统,达到预定值就停止加热,但是由于惯性,温度肯定会继续上升,电炉烧水的时候,水...
单片机控制PWM,用到双向可控硅。怎样设计相关电路图和程序(C语言...
输出复位,开始延时。如果定时器有外部管脚复位启动功能,可以不要这段。\\x0d\\x0a延时中断做一件事,触发输出。如果定时器有触发输出功能,可以没有这段中断程序。\\x0d\\x0a具体的延时时间,由主程序控制,一般是根据PID的计算结果进行设置。注意,延时时间越长,输出电压越小。
用51单片机c语言让八个led亮度自左向右逐渐变亮(pwm)
。 P0 |= (1 << LEDx); PWM正占空 else if(x > Count) PORTA &= ~(1 << LEDx); \/\/51怎么改?。 P0 &= ~(1 << LEDx); PWM负占空 }void main( void ){ unsigned char delay = 0; unsigned char LEDx = 0; Init_IO(); while (1) { delay ++; ...
stc8h单片机如何设置pwm频率
PWMA_CCMR1 寄存器的 IC1PS=00)。5. 设置 PWMA_CCER1 寄存器的 CC1E=1,允许捕获计数器的值到捕获寄存器中。6. 如果需要,通过设置 PWMA_IER 寄存器中的 CC1IE 位允许相关中断请求。7.使能计数器设置 PWMA_CR1 寄存器的 CEN 位来启动计数器。