📄 温控最终程序.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 + -