?? 溫控最終程序.c
字號:
#include<absacc.h>
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
#include<math.h>
#include<string.h>
#define AD0809 XBYTE[0xf605]
sbit p_clock=P2^1; //P2.1口為AD0809的時鐘輸入
sbit ad_busy=P3^2; //AD轉換結束標志
sbit Start=P2^3; //開始轉換啟動信號
sbit LE=P2^0; //鎖存標志
sbit P1_3=P1^3;
sbit P1_4=P1^4;
uchar Date_AD; //Date_AD來接受AD轉換后得到的數據
uchar led[8]; //緩沖區
const uchar DATA_7SEG[ ] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; //數碼管段碼
uchar sed0=0,sed1=0,min0=0,min1=0; //秒表程序所要用到的四個全局變量
int count=0; //用count來控制產生1秒所要循環的次數
uchar Judge; //用于PID比較的全局變量,經AD轉換的采樣溫度
uchar value[31]; //存儲采樣值,用于濾波
uint sum=0;
uint temp=0;
uchar tt;
struct PID //PID結構體
{
uint q1;
uint q2;
uint q3;
uint LastError; // 上次誤差E(k-1)
uint PrevError; // 上上次誤差E(k-2)
};
struct PID spid;
int rout;
uchar high_time,low_time; //占空比調節參數
uchar set_temper; //設定溫度值
void pdelay(unsigned char time) //溫控延時延時時間為30*time微秒
{
unsigned char m,n;
for(n=0;n<time;n++)
for(m=0;m<2;m++){}
}
void PIDInit (struct PID *pp) //PID結構體初始化
{
memset ( pp,0,sizeof(struct PID));
spid.q1 = 11;
spid.q2 = 15;
spid.q3 =10;
spid.LastError = 0;
spid.PrevError = 0;
high_time=50; //占空比初始化
low_time=50;
}
uint PIDCalc( struct PID *pp, unsigned int NextPoint ) //增量式偏差運算,NextPoint為采樣值
{
int Pk,Error;
Error =set_temper- NextPoint; // 偏差Pk就是△U(k)
Pk=pp->q1 * Error-pp->q2 * pp-> LastError+pp->q3*pp->PrevError;
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (Pk);
}
void compare_temper() //溫度控制
{
if(set_temper>Judge)
{
if(set_temper-Judge>4)
{
high_time=100;
low_time=0;
}
else if((set_temper-Judge>=1)&&(set_temper-Judge<=4))
{
rout = PIDCalc ( &spid,Judge );
if(rout<0)
{
high_time=2;
low_time=98;
}
else
{
high_time=(unsigned char)(rout*2+4);
low_time= (100-high_time);
}
}
else
{
high_time=5;
low_time=95;
}
}
else {
high_time=0;
low_time=100;
}
}
void con_temper(void) //與設定溫度比較
{ int i;
compare_temper();
for(i=0;i<low_time;i++)
{P1_3=1; P1_4=1; pdelay(2);}
for(i=0;i<high_time;i++)
{ P1_3=0; P1_4=0; pdelay(2);}
}
void delay(uint x) //延時程序
{
uchar j;
while(x--)
{
for(j=0;j<125;j++)
{;}
}
}
void display(void) //顯示子程序
{
uchar i;
uchar sp=0x1f&P1;
for (i=0;i<8;i++)
{
P1=sp; //位選移位
if(i==6)
P0=DATA_7SEG[led[i]]+0x80; //加點
else
P0=DATA_7SEG[led[i]]; //送段碼
LE=1;
sp+=0x20;
delay(1);
}
}
void adc0809() //AD轉換程序
{
int i;
Start=0;
WR=1;
P0=0x05;
WR=0;
WR=1;
P0=0xff;
i=i;
i=i;
i=i;
i=i;
do
{
p_clock=~p_clock; //給時鐘信號
i=i;
i=i;
}
while(ad_busy==1); //等待AD轉換結束
Start=0;
RD=0;
Date_AD=P0; //把轉換結果保存
RD=1; //數據保存后立即使AD的輸出鎖存,防止干擾顯示
}
void watch() //秒表程序
{
if(count==20) //循環20次才是1秒
{
sed0++;
count=0;
if(sed0==10)
{sed1++;sed0=0;}
if(sed1==6)
{min0++;sed1=0;}
if(min0==10)
{min1++;min0=0;}
if(min1==6)
{min1=min0=sed1=sed0=0;}
}
led[7]=min1; //填寫緩沖區
led[6]=min0;
led[5]=sed1;
led[4]=sed0;
TF0=0; //定時器T0溢出標志
}
time0() interrupt 1 using 2 //中斷服務程序
{
count++;
TH0=(65536-46080)/256; //定時器裝入初值 為50微秒
TL0=(65536-46080)%256;
}
void sub_one()
{
TH0=(65536-46080)/256; //定時器裝入初值 為50微秒
TL0=(65536-46080)%256;
EA=1; //cpu開中斷
ET0=1; //定時器0開中斷
TR0=1; //啟動T/C開始定時(T0運行控制位)
}
void sub_two()
{
int i=0;
for(i=30;i>0;i--) //一下為數字濾波部分
value[i]=value[i-1];
value[0]=Date_AD; //每次采樣后的值保存在數組的第零位
sum=sum+value[0]-value[30];
temp=sum/30; //求算術平均值
tt=temp/5;
led[3]=tt/100; //填緩沖區
led[2]=tt%100/10;
led[1]=tt%10;
led[0]=12; //顯示字符C,表示攝氏度
Judge=led[2]*10+led[1]; //用Judge保存轉換后的溫度(十進制式)
}
void communication() //通訊子函數
{
TH1=0xfd; //裝入初值
TL1=0xfd;
SCON=0xd8; //串行口工作在方式3
PCON=0x00; //波特率不加倍
TR1=1; //啟動定時
while(RI==0); //等待接受數據
RI=0;
set_temper=SBUF;
SBUF=Judge;
while(TI==0); //判斷是否發送完畢
TI=0; //發送完畢則清零
}
void main()
{
int k=0;
sub_one(); //定時器初始化子程序
TMOD=0x21; //兩個定時器的設置
while(1)
{
watch(); //秒表子程序
if(k==10)
{
k=0;
adc0809(); //AD轉換
sub_two(); //AD轉換后數據的處理子程序
} k++;
display(); //顯示子程序
communication(); //串口通訊子程序
con_temper(); //PID溫度控制子程序
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -