//摘要:温度控制器系统(温度显示精确到0.1度)
//调温调节范围设定在35-65度
//共计5种模式:
//模式0:温度实时值显示(前1位数码管显示模式,后2位显示实时温度值,精确到0.1C
//模式1:目标温度设定(35-65 度)
//模式2: PID 参数中的P参数调节模式(0.0-50.0)
//模式3: PID参数中的I参数调节模式(0.0-50.0)
//模式4: PID参数中的D参数调节模式(0.0-50.0)
//数码管第一位显示模式值,后三位显示参数值
//按MODE键显示对应模式,按UP,DOWN修改参数,按ENT键返回模式0即显示实时温度值
#include "STC12C5A60S2.h"
#include "table.h"
#define AD CHANNEL 0
#define uchar unsigned char
#define uint unsigned int
#define THCO 0xf8 //11.0592MHZ 晶振
#define TLCO 0xcb //定时 2ms时间常数值
unsigned char Data_Buffer[4]= {1,2,3,4};
uchar code
Duan[ 17]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71 ,0x76};
sbit P24=P2^4; //四 个数码管的位码口定义
sbit P25=P2^5;
sbit P26=P2^6;
sbit P27=P2^7;
sbit warm=P3^4;
sbit Mode_key=P2^0;
sbit UP_key=P2^1;
sbit DOWN_key=P2^2;
sbit ENT_key=P3^2;
void AD_init();
unsigned int AD_Sample(unsigned char channel);
void Buffer_fresh();
bit kuaisu=0; //按 键快速处理
unsigned char V_mode=0; //0-4
unsigned int canshu[5]= {0,450,110,50,10;//均放大10倍
//模式0:温度实时值显示(前1位数码管显示模式,后2位显示实时温度值,精确到0.1C
//模式1:目标温度设定(35-65 度)
//模式2: PID参数中的P参数调节模式(0.0-50.0)
//模式3: PID参数中的I参数调节模式(0.0-50.0)
//模式4: PID参数中的D参数调节模式(0.0-50.0)
unsigned int maxcanshu[5]= {0,700,500,500,500};
unsigned int mincanshu[5]= {0,300,1,1,1};
bit ADflag=0;
bit PIDflag=0;
bit Disp_flag=0;
/*---------------------------------------------
温度计算,放大10倍
---------------------------------------------*/
unsigned int ADtempreture(void)
{
unsigned int da=0,max,min,mid;
unsigned int V;
float t,t1j;
v=AD_ Sample(AD_ CHANNEL);
t=v;
t=v*4.83///4.883=5000/1024 ;
t1=t/1000; //t1为电压值
t1=(5000-t)/t1;
v=(unsigned int)t1*10; // 计算得电阻值
da=v;
max=97; min=0;
while(1)//查表求出温度值
{
mid=(max +min)/2;
if(Table[mid]<da) max-mid;
else min=mid;
if(max-min)<=1) break;
}
if(max-min)da-min* 10; //温度值放大10倍
else
{
j=(Table[min]-Table[max])/10;
j=(Table[min]-da)j;
da=j;
da= 10*min+da;
}
return da;
}
unsigned char pid_val_mid=0;
void PIDcompute()
{
/*-------------------------------------------------
根据设定及采集值进行计算PID调节,计算出PID——VAL——MID 的值
--------------------------------------------------*/
static int SumError-0,PrevError-0,L astError-=0;
int dError-0,Error=0;
double j=0.0,i;
Error =canshu[1]-cansbu[0];
if(Error> 10){pid val mid-25s;returm;}
else if(Errort 10<0){pid _val mid-0;return;}
SumError +=Error;
dError- Error-LastError;
PrevError-LastError;
LastError-Error;
// j=canshu[2]*Error + canshu[3]*SumError + canshu[4]*dError; //放大100倍
i=canshu[2];
j=Error*i;
i=canshu[3];
j=j+SumError*i;
i=canshu[4];
j=j+dError*i;
if(j>0) j=j/10; //PID参数放大了10倍,所以要減小10倍
if(j> 255)pid _val mid= 255; //全幵
else ifj<0)pid val mid-0; //全关
else pid _val _mid=j; //计算值
}
/******************** ******/
void main(void) //主程序
{
bit x: -0,y=0;;
TMOD =0x11; //没置定肘器0工作模式,16位汁数模式
TH0=THCO;
TL0=TLCO;
TR0=1; //启动计时器
ET0=1; //使能定时器中断
EA=l; //幵总中断
CCON=0; //清标志
CL=0; //清计数器
CH=0;
CMOD=0x08; //PCA时钟为SYSCLK
PCAPWM1=0X0;
CCAP1H=CCAP1L=0xff; //pwm0 output 50% duty cycle脉宽值越低输出越大DA
CCAPM1=0X42; //PCA module-0 work in 8-bit PWM mode
CR= 1; //PCA timer start run
AD_init();
while(1)
{
if(Disp_ flag==1)
{ Disp_ flag=0;Bufer_ fresh0;}
if(ADflag==1)
{canshu[0]=ADtempreture0;ADflag =0;
if(V_ mode= -0)Disp_ flag=1;}
if(PIDflag==1)
{PIDflag=0;PIDcompute0;CCAP1H=CCAP1L= 255-pid_ val mid;}
if(Mode_ key== =1)x=0;
else if(x= =0)
{x=1;
V_mode++;Disp_ flag= l;
if(V_ mode>4)V_ mode=0;
}
if(ENT_ key==1)y=0; //按ENT键观察实时温度
else if(y==0)
{y=1;
Disp_ flag=l;
V_ mode=0;
}
if(canshu[0] > 500)||canshu[0]<350)
{
P3 = 0x00;
}
else
{
P3 = 0XFF;
}
}
}
void AD_ init();
{
P1M0=P1M0&(~(1<<AD_ CHANNEL)); //P10 设为AD转换功以能
PIM1=P1M1|(1<<AD_ CHANNEL);
P1ASF=1<<AD_ CHANNEL; //通道选择
AUXRI|=0x04;
ADC_ _CONTR=0x80; //打开A/D转换器电源
}
unsigned int AD_ Sample(unsigned char channel)
{
unsigned int temp;
ADC_ CONTR=0x88|channel; //选择AD当前通道,并启动转换
while((ADC_ CONTR&0x10)==0); //等待AD转换结束
ADC_ _CONTR =0x80; //清除转 换结束标志
temp (ADC_ RES&0x03)*256+ADC_ RESL;
return temp;
}
void timer0) interrupt 1 //定时 器中断服务子程序
{
static unsigned int count=0,count1 =0,keytime =0; //软计时变量定义
static unsigned char Bit=0; //静态变量,退出程序后,值保留
TH0=THCO;
TL0=TLCO;
Bit++;
if(Bit>=4)Bit=0;
P2|=0xf0; //先关位码
P0=Duan[Data_ _Buffer[Bit];
if(Bit== 2|Bit==0)P0|=0X80;
switch(Bit) //送位码
{
case 0: P24=0;break;
case 1: P25=0;break;
case 2: P26=0;break;
case 3: P27=0;break;
}
count++;
if(count>=100) //200ms更新采集一次温度,并做一次 PID
{
count=0;
ADflag=l;
}
count1++;
if(count1>=400) //800ms做一次PID
{
count1=0;
PIDflag=1;
}
if(UP_ key-=0|DOWN_ key==0)&&V_ mode!=0)
{
if(+ +keytime >30)
{
keytime=0;
if(UP_ key==0)
{canshu[V_ mode]++;if(canshu[V_ mode]>maxcanshu[V_ mode])canshu[V_ mode]- mincanshu[V_ mode];Disp_ flag=1;}
else if(DOWN_ key--0)
{if(canshu[V_ mode] =mincanshu[V_ mode])canshu[V_ mode]=maxcanshu[V mode],canshu[V_ mode]--;Disp_ flag=1;}
}
}
else (keytime=0;)}
}
void Buffer_ fresh()
{ Data_ Buffer[0]=V_ mode;
Data_ Buffer[ l]=canshu[V_ mode]/100%10;
Data Buffer[2]=canshu[V_ mode]/10%10;
Data_ Buffer[3]= canshu[V_ mode]%10;
}
|