📄 function.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 + -