#include "STC15Fxxxx.h"
#include "button.h"
#include "LCD1602.h"
#include<absacc.h>
#define uchar unsigned char
//#define OSC 18432000L
//#define BAUD 9600
//#define URMD 0
#define ADC_POWER 0x80
#define ADC_FLAG 0x10
#define ADC_START 0x08
#define ADC_SPEEDLL 0x00
#define ADC_SPEEDL 0x20
#define ADC_SPEEDH 0x40
#define ADC_SPEEDHH 0x60
#define TIMS 65236
#define uchar unsigned char
#define uint unsigned int
#define ADC_7 XBYTE[0x0600] //定義模數轉換IO地址
#define DAC_1 XBYTE[0x0640]
//最小拍參數
sbit str = P1^7; //定義A/D啟動信號
sbit DIN0 = P1^0; //聲明同步信號
uint data time; //聲明變量,用于定時
uchar data t0_h,t0_l; //用于存儲定時器0的初值
int TK=100; //聲明采樣周期變量,//采樣周期=TK*10ms
int TC; //TK的變量
float KK0=0.5435; //系數kk0
float KK1=-0.2000; //系數kk1
float KK2=0; //系數kk2
float KK3=0; //系數kk3
float PP1=0.7170; //系數pp1
float PP2=0; //系數pp2
float PP3=0; //系數pp3
char UK; //當前時刻的D/A輸出
char EK; //當前時刻的偏差
char UK_1,UK_2,UK_3,EK_1,EK_2,EK_3;//前3次采樣時刻的控制量和偏差
//標志位
bit flag=0;
unsigned int intr2;
unsigned char intr;
bit adc_flag;
uchar state=1; //初始最小拍控制狀態
#define da_cs P15
#define led P17
bit key_flag;
float Err=0,D_Err=0;
float Last_Err=0,Prev_Err=0;
int limit=0;
float vol_set,vol_sample=0,temp_sample,dac=0;
int temp_set=60;
uchar key_table[]={0,0,0};
float uk0=0;
uint ad_data=0;
//bit adc_rd=0;
void timer_0() interrupt 1
{
if(++intr == 10) //1ms?′DDò?′?
{
intr = 0;
key_flag = 1; //10ms判鍵
}
if(++intr2 == 600) //1ms?′DDò?′?
{
//P47=!P47;
intr2 = 0;
adc_flag=1; //1s adc2é?ù??ê±ê±????
}
//display(temp_set,temp_sample);
}
void Timer0() interrupt 1 using 1
{
str = !str; //產生A/D啟動信號
TH0 = t0_h; //重新裝入初值
TL0 = t0_l;
}
void adc_int() interrupt 5
{
ADC_CONTR &=!ADC_FLAG;
//if (adc_rd==1){
ad_data=ADC_RES*4+ADC_RESL;
// } if (adc_rd==0) {adc_rd=1;}
}
float zuixiaopai( )
{
TMOD = 0x01;
time = 10; //定時10ms
t0_h = (65536-500*time)/256; //計算定時器0初值
t0_l = (65536-500*time)%256;
t0_l = t0_l+20; //修正因初值重裝而引起的定時誤差
TH0 = t0_h;
TL0 = t0_l;
IT1 = 1; //邊沿觸發中斷
EX1 = 1; //開外部中斷1
ET0 = 1; //開定時中斷0
TR0 = 1; //啟動定時器
TC = 1;
DAC_1= 0x80; //D/A清零
UK=UK_1=UK_2=UK_3=0;
EK=EK_1=EK_2=EK_3=0;
EA = 1;
return(UK); //開總中斷
while(1);
}
void int1() interrupt 2 using 2
{ float i,j;
DIN0 = 1; //讀取輸入前,先輸出高電平
if(DIN0) //判同步信號到否
{
UK=UK_1=UK_2=UK_3=0;
EK=EK_1=EK_2=EK_3=0;
DAC_1 =0x80; //D/A輸出零
TC=1;
}
else
{
TC--; //判采樣周期到否
if(TC==0)
{
EK = ADC_7-128; //采樣當前的偏差值,并計算偏差的變化量
i=EK*KK0; //計算i=EK*KK0+EK_1*KK1+EK_2*KK2+EK_3*KK3)
i=i+EK_1*KK1;
i=i+EK_2*KK2;
i=i+EK_3*KK3;
j=UK_1*PP1; //計算j=UK_1*PP1+UK_2*PP2+UK_3*PP3
j=j+UK_2*PP2;
j=j+UK_3*PP3;
i=i-j; //i-j
if(i>0) //判控制量是否溢出,溢出賦極值
{
if(i>=127)
UK=127;
else
UK=(char)i;
}
else
{
if(i<-128)
UK=-128;
else
UK=(char)i;
}
DAC_1=UK+128; //D/A輸出控制量
UK_3=UK_2; //控制量遞推
UK_2=UK_1;
UK_1=UK;
EK_3=EK_2; //偏差遞退
EK_2=EK_1;
EK_1=EK;
TC=TK; //采樣周期變量恢復
}
}
}
void main()
{
unsigned char key_temp;
unsigned char ch=0; //AD2é?ùí¨μà
uchar i=0;
P3=0;
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x01;
P1M1 = 0x01;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
CLK_DIV=0x03;
lcd_init();
display_init();
led=1;
TL0=TIMS;
TH0=TIMS>>8;
AUXR&=0x3F;
AUXR1=0X08;
TMOD=0x00;
TR0 = 1;
ET0 = 1;
EA = 1;
EADC=1;
P1ASF=0xFF;
ADC_RES=0;
temp_sample=vol_sample*16+20; //設置換算溫度初始值,對應0-5V,采樣溫度范圍20-100°C
ADC_CONTR =ADC_POWER |ADC_SPEEDLL | ADC_START | ch;
//for(i=0;i<10000;i++);
//ADC_CONTR &=!ADC_FLAG;
da_cs=0; //D/A初始值
while(1)
{
if(key_flag) //10ms掃描鍵盤1次
{
key_flag = 0;
key_temp = read_key();
}
switch (state) //狀態切換
{
case 1: //PID控制
if (adc_flag==1)
{
ADC_CONTR=ADC_POWER |ADC_SPEEDLL | ADC_START | ch;
// ad_data=0
adc_flag=0;
vol_set=(temp_set-20)/16.0; //溫控設定范圍20-100度,AD 0-5V
vol_sample=(float)(ad_data)*5/1024; //采樣數字量0-1023換算成電壓值0-5V
temp_sample=vol_sample*16+20; //換算成溫度
Err = vol_set - vol_sample;
uk0 = zuixiaopai( ); //調用最小拍
dac+=(uk0/5*256*5/12);
limit=round(dac);
if(limit<0) limit=0;
if(limit>255) limit=255;
P3=limit;
}
display(temp_set,temp_sample);
if (key_temp==10) //設置鍵按下
{
state=2;
led=0; //設置指示燈亮
}
break;
case 2: //設置給定溫度
if (key_temp>=0&&key_temp<=9) //數字鍵按下
{key_table[i++]=key_temp; //按位記錄按鍵設定值
if (i==3) i=0;}
else if (key_temp==11)
{
led=1;
Err=0;
D_Err=0;
state=1;
break;
}
//led=0;
temp_set=key_table[0]*100+key_table[1]*10+key_table[2]; //組合成溫度設定值
display(temp_set,temp_sample);
break;
}
}
}
|