/******************************************************************
本程序只供學習使用,未經作者許可,不得用于其它任何用途
程序結構參考 安徽師范大學 Lyzhangxiang的EasyHW OS結構設計
Main.C file
作者:bg8wj
建立日期: 2011.12.23
版本:V1.0
Copyright(C) bg8wj
/*******************************************************************/
#include "ioconfig.h"
#include "includes.h"
#include "datacomm.h"
/************************************************
PID函數
*************************************************/
void PIDInit (struct PID *pp)
{
memset ( pp,0,sizeof(struct PID));
}
/************************************************
增量控制PID函數體
51單片機最不擅長浮點數計算,轉換成int型計算
*************************************************/
unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
{
unsigned int dError,Error,pError;
//增量法計算公式:
//Pdt=Kp*[E(t)-E(t-1)]+Ki*E(t)+Kd*[E(t)-2*E(t-1)+E(t-2)]
Error = set_temper - NextPoint; // 偏差E(t)
pError=Error-pp->LastError; //E(t)-E(t-1)
dError=Error-2*pp->LastError+pp->PrevError; //E(t)-2*E(t-1)+E(t-2)
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (
pp->Proportion * pError //比例
+ pp->Integral *Error //積分項
+ pp->Derivative * dError // 微分項
);
}
/************************************************
PID函數初始化
*************************************************/
void PIDBEGIN()
{
PIDInit(&spid); // Initialize Structure
spid.Proportion = 10; // Set PID Coefficients
spid.Integral = 5;
spid.Derivative =4;
}
/************************************************
實時溫度讀取函數
從DS18b20中讀取實時溫度
返回值放大10倍便于PID計算
*************************************************/
int ReadTemperature(void)
{
unsigned char TPL=0;
unsigned char TPH=0;
unsigned int temperture=0;
//EA = 0;
Init_DS18B20();
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
TPL=ReadOneChar(); //讀溫度低字節
TPH=ReadOneChar(); //讀溫度高字節
//啟動下一次溫度轉換
Init_DS18B20();
WriteOneChar(0xCC); // 跳過讀序號列號的操作
WriteOneChar(0x44); // 啟動溫度轉換
//temperture=(TPH*256+TPL)*0.0625 //真實溫度值 范圍(+125,-55)
if(TPH&0xfc)
{
tp_flag=1; //負溫度標記
temperture=((TPH<<8)|TPL);
temperture=((~temperture)+1);
temperture*=0.625+0.5;
}
else
{
tp_flag=0;
//temperture=((TPH<<8)|TPL)*0.0625 //溫度輸出值范圍(125.00,-55.00)
temperture=((TPH<<8)|TPL)*0.625+0.5;//溫度值放大10倍 范圍(+1250.00,-550.00)
} // +0.5四舍五入 精度只到小數后一位
return(temperture);
}
/************************************************
lcd1602顯示函數
*************************************************/
void xianshi(void)
{
LCD_Write_String(0,0,"NOW TMP:");
LCD_Write_String(0,1,"SET TMP:");
}
/************************************************
lcd1602顯示實時溫度
*************************************************/
void view(unsigned int tmp)
{
LCD_Write_Char(15,0,'C');
LCD_Write_Char(14,0,0xdf);//攝氏溫度符號
LCD_Write_Char(13,0,zhi[tmp%10]);//小數點后第1位
LCD_Write_Char(12,0,'.');
LCD_Write_Char(11,0,zhi[tmp%100/10]);// 個位
LCD_Write_Char(10,0,zhi[tmp/100]); //十位
if(0==tmp/1000)LCD_Write_Char(9,0,' ');//百位 如果為零顯示空格
else
LCD_Write_Char(9,0,zhi[tmp/1000]);
if(1==tp_flag)LCD_Write_Char(8,0,'-');//正負溫度符號顯示 負溫度顯示- 0上顯示空格
else
LCD_Write_Char(8,0,' ');
}
/***********************************************************
PID溫度控制做動函數
***********************************************************/
void compare_temper() //PID溫度控制輸出函數
{
unsigned char i;
if(set_temper>temper)
{
if(set_temper-temper>50)//如果控制目標溫度溫與實時溫度差大于5度,(放大10倍)是50
{
PWM0_set(10); //PWM 輸出高電平占空比最大。即全速加溫
PWM1_set(10);
}
else
{
for(i=0;i<10;i++) //5度范圍內PID增量控制,10次周期 即PID積分式中T=10
{
rin=ReadTemperature();//PID輸入實時溫度采樣值
rout = PIDCalc ( &spid,rin ); // PID增量輸出
}//PID增量輸出范圍(0-255)配合pwm取值范圍
send_string_com("pid out:"); //串口輸出監視數據
send_char_com(rin); //實時溫度值
send_char_com(rout);//PID增量輸出值
send_char_com(0x0d);//輸出回車,換行間隔控制字符
send_char_com(0x0a);//
if(rout>=240)rout=240; //保障PWM輸入值10-240 防止pwm出現失調。stc單片機特性。
if(rout<=20)rout=20;
PWM0_set(255-rout);
PWM1_set(255-rout);
}
}
else if(set_temper<=temper) //目標溫度小于實時溫度pwm輸出低電平最高占空比,關閉加熱。
{
PWM0_set(250);
PWM1_set(250);
}
}
/************************************************
系統初始化函數
*************************************************/
void Sys_Init()
{
PWM_init();
PIDBEGIN();
LCD_Init();
Init_DS18B20();
LCD_Clear();
InitUart1();
}
/*************************************************
主函數
**************************************************/
void main(void)
{
Sys_Init(); //系統初始化
xianshi(); //顯示字符
PWM0_set(250); //初始化PWM兩路輸出最高低電平占空比,不要加熱
PWM1_set(250);
delay500ms(); //延時稍等芯片初始化
while(1)
{
EA=0;
k=KeyPro(); //鍵盤掃描
if(k!=0xff)
{
if(k==15){i=0;shu[0]=0;shu[1]=0;shu[2]=0;shu[3]=0;}
else{shu[i]=k;i++;if(i>3)i=0;}//鍵值15對應清除設定溫度顯示及數組為0
}
if(k==14)//鍵值14鍵 置入設定溫度并確定 輸入格式xxx+確定鍵 第一位是百度 為0需要輸入0
{
EA=1;
set_temper=1000*(shu[0])+100*shu[1]+10*shu[2];
compare_temper(); //啟動PID溫度控制作動函數
}
LCD_Write_Char(15,1,'C'); //顯示設定溫度值百位為0時 顯示空格 但是輸入必須輸入0
LCD_Write_Char(14,1,0xdf); //溫標符號
LCD_Write_Char(13,1,zhi[0]);
LCD_Write_Char(12,1,'.');
LCD_Write_Char(11,1,zhi[shu[2]]);
LCD_Write_Char(10,1,zhi[shu[1]]);
if(shu[0]==0)LCD_Write_Char(9,1,' ');
else LCD_Write_Char(9,1,zhi[shu[0]]);
if(counter-- == 0) //溫度聯系讀5次
{
temper=ReadTemperature();
counter =5;
}
view(temper); //溫度顯示;
if(!set_temper==0)compare_temper();//只有設置目標溫度后才啟動PID溫控作動函數
}
}
|