⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 function.c

📁 STC12C5412AD做的温度检测控制的源程序.有AD检测,可控硅过零触发,PID算法.
💻 C
字号:

#include".\Globle.h"
#include".\Modbus_RTU.h"
extern WordType wtmp;
int SetTemp;				//设定温度
UBYTE SetFlow;					//设定风量
float PDef;					// P
float IDef;					//I
float DDef;					//D
UWORD AdjTime;				//调节时间
UBYTE ZSet=0;					//0v校准
UBYTE FSet;					//100mv校准
UBYTE SlaveAdd;				//从机地址


int ZeroValue=0;				//0v偏差
UWORD FullValue;				//100mv值


code int KTable[6][10]={
	{	60	,	78	,	94	,	110	,	126	,	143	,	159	,	176	,	193	,	210	}	,
	{	225	,	242	,	254	,	269	,	290	,	307	,	321	,	339	,	355	,	371	}	,
	{	387	,	404	,	420	,	436	,	451	,	468	,	483	,	501	,	517	,	533	}	,
	{	549	,	568	,	585	,	602	,	620	,	637	,	653	,	671	,	688	,	703	}	,
	{	720	,	738	,	756	,	774	,	783	,	801	,	819	,	837	,	854	,	872	}	,
	{	889	,	907	,	924	,	941	,	959	,	976	,	994	,	1011	,	1023	,	1024	}	

};
void ParaFresh(UBYTE num)
{
	wtmp.bytes.bh=gvc_data_buf[num*2];
	wtmp.bytes.bl=gvc_data_buf[num*2+1];
	switch(num)
		{
			case 0:
				SetTemp=wtmp.wd;

				
			break;


			case 1:
				SetFlow=wtmp.bytes.bl;

			break;


			case 2:
				PDef=wtmp.wd;
				PDef=PDef/100;

			break;

			case 3:
				IDef=wtmp.wd;
				IDef=IDef/100;

			break;


			case 4:
				DDef=wtmp.wd;
				DDef=DDef/100;

			break;


			case 5:
				AdjTime=wtmp.wd;
		
			break;


			case 6:
				ZSet=wtmp.bytes.bl;
				uart_send(ZSet);
			break;


			case 7:
				FSet=wtmp.bytes.bl;
		

			case 8:
				SlaveAdd=wtmp.bytes.bl;
			
			break;

			//case 9:
			//	SetTemp=gvc_data_buf[num];
			//break;

			default:
			break;
		}

}
UWORD FifoBuff[10];
UWORD FifoAdc(UWORD input)
{
	UBYTE	lvc_counter;
	long lvl_tmp=0;
	for(lvc_counter=0;lvc_counter<9;lvc_counter++)
		{
			FifoBuff[lvc_counter]=FifoBuff[lvc_counter+1];
			lvl_tmp+=FifoBuff[lvc_counter];
		}
	FifoBuff[9]=input;
	lvl_tmp+=input;

	return(lvl_tmp/10);

}

UWORD TempCheck(UWORD Votage)				//温度检测
{
	float unit;
	float lvf_tmp;
	UWORD tmp;
	UBYTE	x1,x2,y;
	UBYTE	lvc_tmp;
	for(y=0;y<6;y++)
		{
			if(Votage<KTable[y][0])
				{
					y=y-1;
					break;
				}
		
		}
	for(x2=0;x2<10;x2++)
		{
			if(Votage<KTable[y][x2])
				{
					x1=x2-1;
					break;
				}

		}

	unit=KTable[y][x2]-KTable[y][x1];
	unit=unit/10;
	lvf_tmp=KTable[y][x1];
	for(lvc_tmp=0;lvc_tmp<10;lvc_tmp++)
		{
			if(Votage<(lvf_tmp+unit))
				break;
			else
				lvf_tmp+=unit;


		}
	tmp=y*100+x1*10+lvc_tmp;
	if(tmp<490)
		return(y*100+x1*10+lvc_tmp);
	else
		return(0);

}

//float Kp,ki,kd;
float e=0,e1=0,e2=0;
float delta;
int TSample;
float Tout;
float Tout_buff;

void PIDCal()
{
	e=SetTemp-TSample;
	//uart_send(0x55);
	//uart_send(SetTemp/256);
	//uart_send(SetTemp%256);
	//uart_send(TSample/256);
	//uart_send(TSample%256);
	//if(e>10||e<-10){
			e=e*0.2;
			//delta=PDef*(e-e1)+IDef*e+DDef*(e-2*e1+e2);
			delta=PDef*e+IDef*(e1+e2+e)+DDef*(e-e1);
			e2=e1;
			e1=e;
			
			Tout=Tout_buff+delta;
			if(Tout>50)
				Tout=50;
			if(Tout<0)
				Tout=0;
			Tout_buff=Tout;
	//	}

}
#if 0

/*******************************
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);  
	 }
 }


#define KP 3.0 //比例系数 
#define KI 0.3 //积分系数
#define KD 200.0 //微分系数
#define KC 0.1 //维持功率系数
#define T_c 16 //采样周期(单位:秒)
sbit pid_port=P3^5; //控制输出端口
float T_target=0; //目标温度
float T_real=0; //当前温度
float PWM=0; //输出控制量

bit read_AD_enable=0; //PID运算允许标志位

//T0定时器初始化
void Timer0_Init()
{
TMOD|=0x01; 
TF0 =0;
TR0 =1;
IE |=0x02; 
}
//读取AD 转换值并刻度
void read_AD(void)
{
int delta_ad; 
unsigned char ad[3];
ad[0]=ADRESH;
ad[1]=ADRESM;
ad[2]=ADRESL;
delta_ad=ad[0]*0x100+ad[1]-0x23cb;
if(delta_ad<=0)delta_ad=0;
T_real=(float)delta_ad/70;
}

//*--------PID运算函数
void pid(void)
{
static float diff[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static float sum_diff=0; //Σ(diff)
static int curr_=0;
float p_out,i_out,d_out,temp;
float pwm_0;
temp=diff[curr_];
if(curr_+1>=20)curr_=0;
else curr_+=1;
sum_diff-=diff[curr_];
diff[curr_]=T_target-T_real;
sum_diff+=diff[curr_];
p_out=KP*diff[curr_]; //比例项输出
i_out=KI*sum_diff; //积分项输出
d_out=KD*(diff[curr_]-temp); //微分项输出
pwm_0=KC*T_target; //维持功率项
if(i_out>100)i_out=100; //积分分离
if(i_out<-100)i_out=-100;
PWM=p_out+i_out+d_out+pwm_0; //总输出量
if(PWM<0)PWM=0;
else if(PWM>=100)PWM=100;
}
// 输出函数
void PWM_OUT(float PWM)
{
static unsigned char t=1; //t=(1--100)周期为4秒
unsigned char limit; //pid_value输出百分比
limit=(unsigned char)PWM;
if(t<=limit)pid_port=0; //加热
else pid_port=1; //停止加热
t++;
if(t>100)t=1;
}
/**************************************************/
//T0中断服务程序
void Timer0_ISR() interrupt 1 using 1
{
static unsigned int x=0;
TH0=(28672)>>8; // 11.0592MHz,interval 40mS
TL0=(28672+20)&0xff; // +20 compensate 
TF0=0;
if((x++)>(T_c*25))
{
x=0;
read_AD_enable=1;
}
PWM_OUT(PWM); //可控硅输出
}

/****************************************************
主程序
----------------------------------------------------*/
void main (void)
{
//-------程序初始化(略)
while (1)
{
if(read_AD_enable==1)
{
read_AD_enable=0;
read_AD();
pid();
}
}
}
#endif



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -