#include<reg52.h>
//***函数定义***
void long_delay(void); //长延时
void short_delay(void); //短延时
void delay10ms(unsigned char); //延时10ms
void write7279(unsigned char,unsigned char);
unsigned char read7279(unsigned char);
void send_byte(unsigned char);
unsigned char receive_byte(void);
ADCJ(unsigned char tongdao);
void sheding();
//***定义变量及I/O口***
unsigned char digit[5];
unsigned char key_number,j,k;
unsigned int tmr;
unsigned long wait_cnter;
unsigned char keyz;
bit test; //长按键标志
sbit cs=P2^0;
sbit clk=P2^1;
sbit dat=P2^2;
sbit key=P2^3;
sbit AD_CS=P0^4;
sbit clk1=P0^1;
sbit dat1=P0^2;
sbit key11=P0^3;
//////////////////////////加热////////////////
sbit jiare=P0^6;
sbit light=P0^7;
bit ad_ok;
bit ad_ok1;
bit ad_ok2;
////////定义结构体//////////
typedef struct DeltPID
{
int good;//目标温度
float P;
float I;
float D;
int ei;//偏差
unsigned int abs_ei;//偏差绝对值
int lasterror;//上次偏差
int delt_ei; //偏差变化
int delt_ei_pn;//偏差变化的趋势
unsigned int adc_data[3];//三次ad采样值
int limit_pidorkey;//分界线
int ui;//输出
int delt_ui;//输出变化
unsigned char i_sign;
}DeltPID;
DeltPID PID;
int m_count;//待输出的周波数
unsigned char ms_timing,second,minuter;
//20ms中断次数计数
//////////////////////yanshi.//////////////////
void delay(unsigned char i)
{
unsigned char j,k;
for(j=0;j<i;j++)
{
for(k=0;k<200;k++);
}
}
//***HD7279指令***
#define CMD_RESET 0xa4 //复位
#define CMD_TEST 0xbf //该指令使所有的LED全部点亮,并处于闪烁状态,主要用于测试 1011 1111
#define DECODE0 0x80 //设置译码器0方式译码,显示 0 -P
#define DECODE1 0xc8 //设置译码器1方式译码,显示 0 -F
#define CMD_READ 0x15 //读按键指令
#define UNDECODE 0x90 //下载不编译
#define BLINKCTL 0x88//控制闪烁
////////pid初始化///////
void PIDinit(void)
{
PID.P=50;
PID.I=50;
PID.D=50;
//PID.good=500;//(带1位小数)
PID.limit_pidorkey=30;//(带小数)
}
/////////////////pid控制///////////////
void PID_ctrl(void)
{
PID.ui=0;
PID.lasterror=PID.ei;//偏差->上次偏差
PID.ei=PID.good-PID.adc_data[0];//求本次偏差
//if(PID.ei<0) PID.abs_ei=-PID.ei;// 求偏差绝对值
//else PID.abs_ei=PID.ei; // 求偏差绝对值
PID.delt_ei=PID.ei-PID.lasterror;//求偏差变化
if(PID.delt_ei>0) PID.delt_ei_pn=1; //曲线下降(降温)
if(PID.delt_ei<0) PID.delt_ei_pn=-1;//曲线上升(升温)
if(PID.ei>PID.limit_pidorkey)//偏差太大超越PID控制范围全量输出
{
PID.ui=2*50; //2xout
return;
}
if(PID.ei<-5)//加热过渡
{
PID.ui=0; //stop out
return;
}
if(((PID.ei>0)&&(PID.delt_ei_pn<0))||((PID.ei<0)&&(PID.delt_ei_pn>0)))//低温下加热or高温下降温
{
PID.i_sign=0;//停积分
}
else PID.i_sign=1;
PID.delt_ui=PID.P/17*PID.delt_ei+PID.i_sign*PID.I/50*PID.ei-PID.D/100*(PID.adc_data[0]-2*PID.adc_data[1]+PID.adc_data[2]);
if(PID.delt_ui>15)
{
PID.delt_ui=15;
}
if(PID.delt_ui<-15)
{
PID.delt_ui=-15;
}
PID.ui+=PID.delt_ui;
}
//////////////////////////中断0/////////////
void jishi() interrupt 1
{
TH0=0xb1; //(655536-45549)/256
TL0=0xe4; //(655536-45549)%256
ms_timing++;
if(ad_ok==0)
ad_ok1=1;
if(m_count>0)
{
jiare=0;//P1.1加热
light=1;//灯亮
m_count--;
}
else
{
jiare=1;//不加热
light=0;//灯灭
}
if(ms_timing>49)
{
ms_timing=0;
if(++second>59)
{
second=0;
//minuter++;
}
//P1~=0x20;//P1.5取
}
}
void delay3(unsigned char h)
{
unsigned char i,j,k;
for(i=0;i<h;i++)
{
for(j=0;j<4;j++)
{
for(k=0;k<245;k++);
}
}
}
/**********************************************************
** 函数名称: key1
** 功能描述:读按键1
** 输入:无
** 输出:keyvalue0
** 全局变量: 无
** 调用模块: 无
***************************************************************/
key1()
{
unsigned char keyvalue0=1;
P2|=0xf0; //向P3高四位写1,准备读按键
keyvalue0=P2;
keyvalue0=~keyvalue0;
keyvalue0=keyvalue0&0xf0; //屏蔽无用位
return(keyvalue0);
}
/**********************************************************
** 函数名称: key2
** 功能描述:读按键2
** 输入:无
** 输出:keyvalue2
** 全局变量:test
** 调用模块: key1
***************************************************************/
key2()
{
unsigned char keyvalue1,keyvalue2,key_count=0; //key_count为长按键记数
keyvalue1=key1(); //第一次读按键
if(keyvalue1>0) //是否有键按下
{
delay3(7);
keyvalue2=key1(); //第一次读按键
if(keyvalue2==keyvalue1) //两次按键值是否相等
{
while(keyvalue1>0)
{
key_count++;
keyvalue1=key1();
delay3(7);
if(key_count>50)
{
key_count=0;test=1; //确定为长按键,置标志位
}
if(test==1)
{
return(keyvalue2);
}
}
//test=0;
return(keyvalue2);
}
test=0;return(0);
}
test=0;return(0);
}
main()
{
unsigned int ad,wen;//暂时不用ad1
int aaa;
//unsigned int ad,aa,ad1 ;
TH0=0xb1; //177
TL0=0xe4; //228 20ms
ET0=1;EA=1;
TR0=1;TMOD=0x01;
for(tmr=0;tmr<0x2000;tmr++);
send_byte(CMD_RESET);
PIDinit();
while(1)
{
keyz=key2(); //读按键
switch(keyz)
{
case 0x80: sheding();
break;
}
aaa++;
ad_ok=1;
if(aaa>10||ad_ok1==1)
{
ad_ok1=0;aaa=0;
ad_ok=0;
if(ad_ok1==0)
{
ad_ok=1;
ad=ADCJ(0);
wen=(ad-296)*1.7;
write7279(DECODE1+0,wen/1000);
write7279(DECODE1+1,wen%1000/100);
write7279(DECODE1+2,(wen%100/10)|0x80);
write7279(DECODE1+3,wen%10);
}
}
PID.adc_data[2]=PID.adc_data[1];
PID.adc_data[1]=PID.adc_data[0];
PID.adc_data[0]=wen;
if((second%1)==0)//1秒控制1次
{
PID_ctrl();
m_count=PID.ui;
}
}
}
void send_byte(unsigned char out_byte)
{
unsigned char i;
cs=0;
long_delay();
for(i=0;i<8;i++)
{
if(out_byte&0x80)
{
dat=1;
}
else
{
dat=0;
}
clk=1;
short_delay();
clk=0;
short_delay();
out_byte=out_byte*2;
}
dat=0;
}
void write7279(unsigned char cmd, unsigned char dta )
{
send_byte(cmd);
send_byte(dta);
}
unsigned char read7279(unsigned char command)
{
send_byte(command);
return(receive_byte());
}
unsigned char receive_byte(void)
{
unsigned char i,in_byte;
dat=1;
long_delay();
for(i=0;i<8;i++)
{
clk=1;
short_delay();
in_byte=in_byte*2;
if(dat)
{
in_byte=in_byte|0x01;
}
clk=0;
short_delay();
}
dat=0;
return(in_byte);
}
void long_delay(void)
{
unsigned char i;
for(i=0;i<0x30;i++);
}
void short_delay(void)
{
unsigned char i;
for(i=0;i<8;i++);
}
void delay10ms(unsigned char time)
{
unsigned char i;
unsigned int j;
for(i=0;i<time;i++)
{
for(j=0;j<0x390;j++)
{
if(!key)
{
key_int();