www.pudn.com > Pid-fuzzy-c-language-.zip > Pid fuzzy c language .txt, change:2014-12-12,size:7815b


/******************************* 
project        :A/D转换数码管显示 
chip type      : atmega8		 
clock frequency:内部RC(INT) 8MHz 
Author         :周远峰		 
********************************/ 
#include "iom8v.h" 
#include "macros.h" 
#define osccal 0x7d      		    
unsigned long adc_rel;              //处理后世界转换结果 
unsigned long adc_rl;               //A/D转换结 
unsigned int tmp;                   //设置的温度参数  			 
unsigned char adc_mux;              //A/D通道  
unsigned char led_buff[3]={0,0,0};  //显示缓存 
signed int error0;                  //当前偏差 
signed int error1;                  //上次偏差 
signed int error2;                  //上上次偏差 
signed char Kp;                     //比例常数 
signed char Ki;                     //积分常数 
signed char Kd;                     //微分常数 
signed int kk1;                     //当前控制输出 
signed int kk2;                     //上次控制输出 
#define NB -3 
#define NM -2 
#define NS -1 
#define ZO 0  
#define PS 1  
#define PM 2 
#define PB 3 
#pragma data:code      
 //设置数据区位程序储存器 
const unsigned char seg_table[16]={0x40,0x79,0x24,0x30,0x19,0x90,0x80,0x78,0x00,0x10,0x08,0x81,0x44,0x21,0x04,0x8c}; 
const unsigned char KP_table[49]={PB,PB,PM,PM,PS,ZO,ZO,PB,PB,PM,PS,PS,ZO,NS,PM,PM,PM,PS,ZO,NS,NS,PM,PM,PS,ZO,NS,NM,NM,PS,PS,ZO,NS,NS,NM,NM,PS,ZO,NS,NM,NM,NM,NB,ZO,ZO,NM,NM,NM,NB,NB}; 
const unsigned char KI_table[49]={NB,NB,NM,NM,NS,ZO,ZO,NB,NB,NM,NS,NS,ZO,ZO,NB,NM,NS,NS,ZO,PS,PS,NM,NM,NS,ZO,PS,PM,PM,NM,NS,ZO,PS,PS,PM,PB,ZO,ZO,PS,PS,PM,PB,PB,ZO,ZO,PS,PM,PM,PB,PB}; 
const unsigned char KD_table[49]={PS,NS,NB,NB,NB,NM,NS,PS,NS,NB,NM,NM,NS,ZO,ZO,NS,NM,NM,NS,NS,ZO,ZO,NS,NS,NS,NS,NS,ZO,ZO,ZO,ZO,ZO,ZO,ZO,ZO,PB,NS,PS,PS,PS,PS,PB,PB,PM,PM,PM,PS,PS,PB}; 
#pragma data:data     
//设置数据区回到数据储存器 
/********************************************************* 
 
延时函数 
 
*********************************************************/ 
void delay_us(int time) //微秒级延时 
 { 
 do 
 time--; 
 while (time>1); 
 } 
 void delay_ms(unsigned int time)  //毫秒级延时 
 { 
 while (time!=0) 
   { 
   delay_us(1000); 
   time--; 
   } 
 } 
 /************************************************************ 
中断显示初始化 
TIMER2 initialize - prescale:1024 
WGM: Normal 
desired value: 10mSec 
actual value:  9.984mSec (0.2%) 
*************************************************************/ 
void timer2_init(void)  
{ 
 TCCR2 = 0x00; //stop 
 ASSR  = 0x00; //set async mode 
 TCNT2 = 0xB2; //setup 
 OCR2  = 0x4E; 
 TCCR2 = 0x07; //start 
 DDRB=0xff;  //PC口为推挽1输出 
 PORTB=0xff; //PC口内部上拉 
 DDRD|=0xf1; 
 PORTD&=0x1f;  //关闭LED 
} 
/*********************************************** 
 
中断显示 
 
*************************************************/ 
#pragma interrupt_handler timer2_ovf_isr:5 
void timer2_ovf_isr(void) 
{ 
 unsigned char i; 
 static unsigned k; 
 SEI(); 
 TCNT2 = 0xB2; //reload counter value 
 for(i=0;i<3;i++) 
   { 
   PORTB=led_buff[i]; 
   PORTD|=(1<<(i+5));//待显示的位置1 
   delay_ms(1); 
   PORTD&=0x1f;     //关闭LED 
   } 
} 
/************************************************************ 
 
PWM初始化,OC1A口输出 
 
*************************************************************/ 
void timer1_init(void)  
{ 
 TCCR1B = 0x00; //stop 
 TCNT1H = 0x00; //setup 
 OCR1A  = 200; 
 TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);//输出低电平  
 TCCR1B = (1<<CS11)|(1<<CS10); // 
} 
/***************************************************** 
 
PID初始化 
 
******************************************************/ 
void pidcalc_init(void)   
{ 
Kp=3; 
Ki=3; 
Kd=3; 
kk1=0; //当前 
kk2=100; 
error0=0; 
error1=0; 
error2=0; 
tmp=300; 
} 
void pidcalc_zizheng(void) 
{ 
if (tmp>adc_rel) 
   {  
	if (kk2<500) kk2+=3; 
	else kk2=500; 
   } 
if ((tmp-1)>adc_rel) 
   {  
	if (kk2<500) kk2+=3; 
	else kk2=500; 
   } 
/*if ((tmp-2)>adc_rel) 
   {  
	if (kk2<600) kk2+=3; 
	else kk2=600; 
   }*/ 
if (tmp<adc_rel) 
   { 
   if (kk2>10) kk2-=3; 
   else kk2=10; 
   } 
if ((tmp+1)<adc_rel) 
   { 
   if (kk2>10) kk2-=3; 
   else kk2=10; 
   } 
/*if ((tmp+2)<adc_rel) 
   { 
   if (kk2>10) kk2-=3; 
   else kk2=10; 
   } 
/*if (tmp>adc_rel) 
   { 
   if (Ki<200) Ki+=4; 
   else Ki=400; 
   } 
if (tmp<adc_rel) 
   { 
   if (Ki>0) Ki-=4; 
   else Ki=0; 
   }  */  
} 
/******************************************************* 
 
PID函数 
 
********************************************************/ 
void pidcalc(void) 
{ 
signed long KPP; 
signed long KII; 
signed long KDD; 
signed int i; 
signed char j; 
error0=tmp-adc_rel; 
j=error0-error1; 
i=7*(3+error0)+(3+j); 
if(i<49) 
    { 
     if (i>0) 
	    { 
		Kp=KP_table[i]; 
		Ki=KI_table[i]; 
		Kd=KD_table[i]; 
		}  
     }                        //输出	               
if ((tmp-15)<adc_rel)                         //比设定低一定值时开始PID 
  { 
   if((tmp+5)>adc_rel)                        //比设定高时关PID 
       { 
       KPP=Kp*(error0-error1);                //比例 
       KII=error0*Ki;                         //积分 
       KDD=Kd*(error0-(2*error1)+error2);     //微分 
       kk1=(KPP+KII+KDD)*4+kk2;   
       if(kk1<0x3ef) 
	           { 
			   if (kk1>=10) OCR1A=kk1;    
			   else OCR1A=0;                 
               } 
	   else 
	           {    
	            OCR1A=0x3ff; 
               }       
			   /*if((tmp-2)>adc_rel) 
			        { 
			        if(OCR1A<500) OCR1A+=20; 
			        else OCR1A=500; 
					}*/ 
	   } 
    else  
	   { 
	   //if (tmp<adc_rel) 
	         // { 
	          ///  if (OCR1A>50) OCR1A-=20; 
	          //  else OCR1A=50; 
	   OCR1A=0;   
	         // } 
       } 
   } 
else 
   {  
    OCR1A=0x3ff; 
   } 
error2=error1; 
error1=error0;   
} 
/*********************************************** 
 
ADC初始化 
 
************************************************/ 
void adc_init(void)   
 { 
 DDRC=0x00; 
 PORTC=0X00; 
 ADCSRA=0X00; 
 ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V为基准AREF外加滤波电容 
 ACSR=(1<<ACD);                  //关闭模拟比较器 
 ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//128分频 
 } 
 /********************************************* 
  
 ADC中断处理函数 
  
 **********************************************/ 
 #pragma interrupt_handler adc_isr:15 
 void adc_isr(void) 
 { 
 static unsigned i; 
 adc_rl+=ADC&0x3ff; 
 ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V位基准 
 ADCSRA|=(1<<ADSC); //启动AD转换    
 if (i<2048) 
    i++; 
else   
     { 
	 adc_rel=adc_rl/2048; 
	 adc_rel=adc_rel*3/5; 
	 i=0; 
	 adc_rl=0; 
	 } 
 } 
 /****************************************************** 
  
 ADC数据转压缩BCD 
  
 ******************************************************/ 
 void ADCtoBCD(unsigned int temp)  
 { 
 unsigned char i;  
 for (i=0;i<3;i++) 
   { 
   led_buff[i]=seg_table[temp%10];/*temp%10求余数‘假设一个数是234那么234/10=23余4也就是查找4的段码*/ 
    
   temp=temp/10;// 234/10=23因为不处理小数实际就等于右移了 
   } 
    
 } 
/*************************************************************** 
 
主程序 
 
***************************************************************/ 
 void main(void) 
 { 
 unsigned char i; 
 unsigned int  k; 
 unsigned int adc_old; 
 unsigned long adc_ol; 
 unsigned int adc_o; 
 DDRD=0xff; 
 PORTD=0xf0; 
 OSCCAL=osccal; 
 TIMSK = 0x40; //timer interrupt sources 
 adc_mux=0; 
 adc_init(); 
 timer1_init(); 
 pidcalc_init(); 
 SEI(); 
 for(i=0;i<3;i++) 
   led_buff[i]=seg_table[8]; 
 for(i=0;i<200;i++) 
   timer2_init(); 
   adc_old=0; 
   adc_rel=0; 
  while(1) 
     { 
		if(adc_old!=adc_rel)//ADC更新完毕就执行数据处理 
	         { 
		      adc_old=adc_rel; 
			  pidcalc(); 
			  pidcalc_zizheng(); 
			    if(k<5)  
				    { 
					k++; 
					adc_ol+=adc_old; 
					} 
				else 
				    { 
					adc_o=adc_ol/5; 
					adc_ol=0; 
					k=0; 
					}	 
			  }   
	    ADCtoBCD(adc_o);   
	 } 
 }