隨著電子技術(shù)的不斷發(fā)展,傳統(tǒng)的溫度控制方式已經(jīng)越來越不能滿足工業(yè)現(xiàn)場的需求,這時,PID控制憑借其算法簡單、適應(yīng)性強(qiáng)的特性,在工業(yè)過程控制中得到了廣泛的應(yīng)用。但PID控制無法應(yīng)用于滯后性大、控制對象復(fù)雜的系統(tǒng)中,尤其是控制精度要求高的溫度控制系統(tǒng)。而將智能控制中的模糊控制與PID控制相結(jié)合的方法,使系統(tǒng)不僅有PID控制的優(yōu)點(diǎn)也具有智能控制的優(yōu)點(diǎn),這樣極大消除了傳統(tǒng)PID控制的缺點(diǎn),這樣的控制方式有著廣闊的發(fā)展前景。 基于以上敘述,本設(shè)計(jì)基于PID控制原理,結(jié)合模糊控制理論,對模糊PID參數(shù)自整定算法在溫度控制系統(tǒng)中的應(yīng)用進(jìn)行了研究。本設(shè)計(jì)采用AT89C52單片機(jī)作為該裝置的核心處理器,DS18B20作為溫度傳感器,LCD1602作為顯示裝置。 本設(shè)計(jì)完成了基于單片機(jī)的模糊PID溫度控制裝置設(shè)計(jì)的硬件設(shè)計(jì)和軟件設(shè)計(jì),并利用MATLAB軟件中Simulink自帶的模糊工具箱完成了仿真測試實(shí)驗(yàn),實(shí)驗(yàn)結(jié)果表明,模糊PID控制算法相比于傳統(tǒng)PID控制算法具有響應(yīng)速度更快,超調(diào)量幾乎為零等優(yōu)點(diǎn),可應(yīng)用于復(fù)雜的溫度控制系統(tǒng)中。
單片機(jī)源程序如下:
- //-----------定義模糊系統(tǒng)參數(shù)-----------------------------------------------------------
- //------------------------------------------------------------------------------------
- // 定義差距輸入常量
- #define GAP_ZERO 0x00
- #define GAP_VSMALL 0x01
- #define GAP_SMALL 0x02
- #define GAP_MEDIUM 0x03
- #define GAP_BIG 0x04
- // 定義控制輸出常量
- #define TURN_ZERO 0x80
- #define TURN_VSMALL 0x81
- #define TURN_SMALL 0x82
- #define TURN_MEDIUM 0x83
- #define TURN_BIG 0x84
- #define uchar unsigned char
- #define uint unsigned int
- //-----------定義模糊系統(tǒng)參數(shù)-----------------------------------------------------------
- //------------------------------------------------------------------------------------
- unsigned char Temp_H,Temp_L;
- uint sum; //10次AD值的綜合變量
- uchar RH,RH_H=12,RH_L=8,state,ms,cs; //當(dāng)前水位, 水位上限,下限, 設(shè)置項(xiàng)變量,50ms變量 ,cs 為計(jì)次數(shù)變量 ,
- bit beep1,zt,s1; //報警標(biāo)志位, 工作模式標(biāo)志位, 閃爍標(biāo)志位
- int Temperature;
-
- //-----------定義模糊系統(tǒng)參數(shù)-----------------------------------------------------------
- //------------------------------------------------------------------------------------
- //-------------定義常量----------------------------------------------------------------
- #define MU_MAX 0XFF //模糊度的最大值為0XFF代表面1
- #define RULE_TOT 10 //規(guī)則數(shù)個數(shù)
- #define MF_TOT 5 //成員函數(shù)的個數(shù)
- #define IO_NUM 0x07
- #define LABEL_NUM 0x70
- #define DEFAULT_VALUE 0x00
- //----------------定義數(shù)據(jù)庫-----------------------------------------------------------
- unsigned char code output_memf[MF_TOT]={0, 15, 35, 60, 102};// OUTPUT TURNING NUMBER:
- // ZERO, VSMALL, SMALL, MEDIUM, BIG
- // 輸入功能函數(shù)以點(diǎn)斜式方式存儲. 第一維成員函數(shù)標(biāo)號第二維是點(diǎn)斜式數(shù)據(jù)
- unsigned char code input_memf[MF_TOT][4]={ //距離功能函數(shù)
- { 0x00, 0x00, 0x00, 0x0d }, // VSLOW
- { 0x00, 0x0d, 0x14, 0x0d }, // SLOW
- { 0x1e, 0x0d, 0x32, 0x0d }, // MEDIUM
- { 0x3C, 0x0d, 0x50, 0x0d }, // FAST
- { 0x50, 0x09, 0x6e, 0x00 } // VFAST
- };
- //-----------定義模糊系統(tǒng)參數(shù)-----------------------------------------------------------
- //------------------------------------------------------------------------------------
- //-----------定義模糊系統(tǒng)規(guī)則-----------------------------------------------------------
- unsigned char code rules[RULE_TOT]={
- // if... then... 規(guī)則
- GAP_ZERO,TURN_ZERO,
- GAP_VSMALL,TURN_VSMALL,
- GAP_SMALL,TURN_SMALL,
- GAP_MEDIUM,TURN_MEDIUM,
- GAP_BIG,TURN_BIG
- };
- //-----------定義模糊系統(tǒng)參數(shù)-----------------------------------------------------------
- //------------------------------------------------------------------------------------
- //-----------定義各變量-----------------------------------------------------------------
- unsigned char outputs[MF_TOT],fuzzy_out; //模糊輸出mu值
- //-----------子程序函數(shù)頭申明-----------------------------------------------------------
- void fuzzy_engine(uchar);
- uchar compute_memval(uchar,uchar);
- void defuzzify(void);
- /***************************************************************************************************************/
- uchar compute_memval(uchar input,uchar label)
- {
- int data temp;
- if (input < input_memf[label][0])
- { // 如果輸入不在曲線下u值為0
- return 0;
- }
- else
- {
- if (input < input_memf[label][2])
- {
- temp=input; // 用點(diǎn)斜式計(jì)算mu
- temp-=input_memf[label][0];
- if (!input_memf[label][1])
- {
- temp=MU_MAX;
- }
- else
- {
- temp*=input_memf[label][1];
- }
- if (temp < 0x100)
- { // 如果結(jié)果不超過1
- return temp; // 返回計(jì)算結(jié)果
- }
- else
- {
- return MU_MAX; // 確保mu值在范圍內(nèi)
- }
- }
- else
- { // 輸入落在第二條斜線上
- temp=input; // 用點(diǎn)斜式方法計(jì)算 mu
- temp-=input_memf[label][2];
- temp*=input_memf[label][3];
- temp=MU_MAX-temp;
- if (temp < 0)
- { // 確保結(jié)果不小于0
- return 0;
- }
- else
- {
- return temp; // mu為正 – 返回結(jié)果
- }
- }
- }
- return 0;
- }
- /*******************************************************************************
- Function: defuzzify 解模糊
- Description: 計(jì)算模糊輸出的重心并調(diào)用函數(shù)把它
- 轉(zhuǎn)換成可被系統(tǒng)使用的輸出量
- Parameters: 無.
- Returns: 無.
- Side Effects: outputs[][] 數(shù)組被清零.
- *******************************************************************************/
- void defuzzify(void)
- {
- unsigned long numerator, denominator;
- unsigned char j;
- numerator=0; // 恢復(fù)總數(shù)值
- denominator=0;
- for (j=0; j<MF_TOT; j++)
- { // 計(jì)算總和值
- numerator+=(outputs[j]*output_memf[j]);
- denominator+=outputs[j];
- outputs[j]=0; // 清零輸出作為參考使用
- if (denominator)
- { // 確保分母是0的情況不發(fā)生
- fuzzy_out=numerator/denominator; // 確定 COG
- }
- else
- {
- fuzzy_out=DEFAULT_VALUE; // 沒有規(guī)則被觸發(fā)
- }
- }
- }
- /*******************************************************************************
- Function: fuzzy_engine
- Description: 實(shí)施規(guī)則基中的規(guī)則
- Parameters: 無
- Returns: 無.
- Side Effects: 無
- ********************************************************************************/
- unsigned char bdata clause_val; // 保存當(dāng)前的分支進(jìn)行快速訪問
- sbit clause_type = clause_val^7; // 表示分支是否是條件分支或者是結(jié)果分支
- void fuzzy_engine(uchar input)
- {
- bit then; // 當(dāng)正在分析結(jié)果時置位
- unsigned char if_val, // 保存當(dāng)前規(guī)則中條件分支中的值
- clause, // 規(guī)則基中當(dāng)前的分支
- mu, // 保存當(dāng)前分支中的值
- label=0; // 被條件使用的成員函數(shù)
- then=0; // 設(shè)第一個分支是條件分支
- if_val=MU_MAX; // max out mu for the first rule
- for (clause=0; clause<RULE_TOT; clause++)
- { // 遍歷每條規(guī)則
- clause_val=rules[clause]; // 讀入當(dāng)前的分支
- if (!clause_type)
- { // 當(dāng)前的分支是不是條件分支
- if (then)
- { // 是否正在分析結(jié)果...
- then=0;
- if_val=MU_MAX; // 復(fù)位mu
- }
- mu=compute_memval(input, label); // 得到條件分支的值
- if_val=mu;
- label++;
- }
- else
- { // 當(dāng)前分支是結(jié)果
- then=1; // 置位標(biāo)志位,如果當(dāng)前規(guī)則的mu比參考的值要大,保存這個值作為新的模糊輸出
- if (outputs[clause_val&0x07] < if_val)
- {
- outputs[clause_val&0x07]=if_val;
- }
- }
- }
- defuzzify(); // 用COG方法計(jì)算模糊輸出和反模糊輸出
- }
復(fù)制代碼
- #include<reg52.h>
- #include<intrins.h>
- #include<math.h>
- #include<string.h>
- #include"fuzzy.h"
- struct PID
- {
- unsigned int SetPoint; // 設(shè)定目標(biāo) Desired Value
- unsigned int Proportion; // 比例常數(shù) Proportional Const
- unsigned int Integral; // 積分常數(shù) Integral Const
- unsigned int Derivative; // 微分常數(shù) Derivative Const
- unsigned int LastError; // Error[-1] 當(dāng)前偏差
- unsigned int PrevError; // Error[-2] 上一次偏差
- unsigned int SumError; // Sums of Errors 累計(jì)偏差
- };
- struct PID spid; // PID Control Structure
- unsigned int rout; // PID Response (Output) 響應(yīng)輸出
- unsigned int rin; // PID Feedback (Input)//反饋輸入
- unsigned char high_time,low_time,count=0;//占空比調(diào)節(jié)參數(shù)
- #define uchar unsigned char
- #define uint unsigned int
- char Usart_Data[3];
- bit FinishFlag =0;
- char UsartCount=0;
- uchar buzzer_flag = 0;
- sbit buzzer = P1^2;
- sbit output=P1^0;
- sbit ds=P3^2;
- sbit DQ=P3^2;//ds18b20與單片機(jī)連接口
- sbit lcden=P2^7;//LCE使能引腳
- sbit lcdrs=P2^5;
- sbit lcdrw=P2^6;
- sbit ledred=P1^6; //加熱指示燈
- sbit ledgreen=P1^7; //加熱指示燈
- sbit key0=P2^0;//按鍵引腳
- sbit key1=P2^1;
- bit busy;
- uchar set[2]={0};
- uchar code str1[]="now temp: C";
- uchar code str2[]="set temp: C";
- uchar code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
- uchar n,num;
- int set_temper=30,temper,temp; //溫度變量定義
- unsigned int s;
- float f_temp;//轉(zhuǎn)換后的溫度
- uint tvalue;
- uchar tflag;//溫度正負(fù)標(biāo)志
- void SendData(unsigned char dat);
- void SetSendData(unsigned char SetNum);
- void delay(i)//延時函數(shù)
- {
- uint j;
- for(i;i>0;i--)
- for(j=110;j>0;j--);
- }
- void Delay_Ms(i){
- delay(i);
- }
- void Timer2_init()
- {
- RCAP2H = (0XFFFF - 50000)/256;
- RCAP2L = (0XFFFF - 50000)%256;
- T2CON =0;
- //T2MOD = 0;
- IE |=0xA0;
- TR2 = 1;
- }
- void wr_com(uchar ml)//寫命令
- {
- lcdrs=0;
- P0=ml;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void wr_data(uchar shuju)//寫數(shù)據(jù)
- {
- lcdrs=1;
- //lcden=1;
- P0=shuju;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void init() //按照時序操作的初始化
- {
- lcdrw=0;
- wr_com(0x38);//顯示模式設(shè)置,設(shè)置為16*2顯示,5*7點(diǎn)陣,八位數(shù)據(jù)口
- wr_com(0x0c);//開顯示,但不開光標(biāo),光標(biāo)不閃
- wr_com(0x06);//顯示光標(biāo)移動設(shè)置
- wr_com(0x01);// 清屏
- wr_com(0x80); // 數(shù)據(jù)指針初始化
- for(num=0;num<16;num++)
- {
- wr_data(str1[num]);//now temp
- }
- wr_com(0x80+0x40); //地址初始化
- for(num=0;num<16;num++)
- {
- wr_data(str2[num]);//set temp
- }
-
- }
- /*************************DS1820程序****************************/
- void delay_18B20(unsigned int i)//延時1微秒
- {
- while(i--);
- }
- void ds1820rst(void)/*ds1820復(fù)位*/
- {
- unsigned char x=0;
- DQ = 1; //DQ復(fù)位
- delay_18B20(4); //延時
- DQ = 0; //DQ拉低
- TR0=0;
- delay_18B20(100); //精確延時大于
- TR0=1;
- DQ = 1; //拉高
- delay_18B20(40);
- }
- uchar ds1820rd(void)/*讀數(shù)據(jù)*/
- {
- unsigned char i=0;
- unsigned char dat = 0;
- TR0=0;
- for (i=8;i>0;i--)
- {
- DQ = 0; //給脈沖信號
- dat>>=1;
- DQ = 1; //給脈沖信號
- if(DQ)
- dat|=0x80;
- delay_18B20(10);
- }
- return(dat);
- }
- void ds1820wr(uchar wdata)/*寫數(shù)據(jù)*/
- {
- unsigned char i=0;
- TR0=0;
- for (i=8; i>0; i--)
- {
- DQ = 0;
- DQ = wdata&0x01;
- delay_18B20(10);
- DQ = 1;
- wdata>>=1;
- }
- }
- uint get_temper()//獲取溫度
- {
-
- uchar a,b;
- ds1820rst();
- ds1820wr(0xcc);//*跳過讀序列號*/
- ds1820wr(0x44);//*啟動溫度轉(zhuǎn)換*/
- ds1820rst();
- ds1820wr(0xcc);//*跳過讀序列號*/
- ds1820wr(0xbe);//*讀取溫度*/
- a=ds1820rd();
- b=ds1820rd();
-
- tvalue=b;
- tvalue<<=8;
- tvalue=tvalue|a;
- TR0=1;
- if(tvalue<0x0fff) tflag=0;
- else {tvalue=~tvalue+1;tflag=1;}
- tvalue=tvalue*(0.625);//溫度值擴(kuò)大10倍,精確到1位小數(shù)
- temp=tvalue;
- return temp;
- }
- void dis_temp(int t)//顯示溫度
- {
- uchar d0,d1,d2,d3;
- //t=26;
- if(tflag==0)
- {
- d0=t/1000+0x30;
- d1=t%1000/100+0x30;
- d2=t%100/10+0x30;
- d3=t%10+0x30;
- if(d0==0x30)
- {
- wr_com(0x80+9);
- wr_data(d1);
- wr_com(0x80+10);
- wr_data(d2);
- wr_com(0x80+11);
- wr_data(0x2e);
- wr_com(0x80+12);
- wr_data(d3);
-
- SendData('N');
- SendData(d1);
- SendData(d2);
- SendData('.');
- SendData(d3);
- SendData('E');
- SendData('\r');
- SendData('\n');
- }
- else
- {
- wr_com(0x80+9);
- wr_data(d0);
- wr_com(0x80+10);
- wr_data(d1);
- wr_com(0x80+11);
- wr_data(d2);
- wr_com(0x80+12);
- wr_data(' ');
-
- SendData('N');
- SendData(d0);
- SendData(d1);
- SendData(d2);
- SendData('E');
- SendData('\r');
- SendData('\n');
-
- }
-
- }
- else
- {
- wr_com(0x80+9);
- wr_data('-');
- wr_com(0x80+10);
- wr_data(d1);
- wr_com(0x80+11);
- wr_data(d2);
- wr_com(0x80+12);
- wr_data(' ');
- //wr_com(0x80+12);
- //wr_data(d3);
-
- // SendData('N');
- // SendData(d1);
- // SendData(d2);
- // SendData('E');
- // SendData('\r');
- // SendData('\n');
- }
- wr_com(0x80+14);
- wr_data(0xdf);
- temper=t/10;
- }
- void keyscan()//鍵盤掃描
- {
- if(key0==0)
- {
- delay(1);
- if(key0==0)
- {
- while(!key0);
- delay(1);
- while(!key0);
- set_temper++;
- }
- set[0]=set_temper/10; //獲得設(shè)置溫度顯示值
- set[1]=set_temper%10;
- wr_com(0x80+0x40+9);
- wr_data(table[set[0]]);
- delay(1);
- wr_com(0x80+0x40+10);
- wr_data(table[set[1]]);
- delay(1);
- //wr_com(0x80+0x40+11);
- //wr_data(0x2e);
- //wr_com(0x80+0x40+14);
- //wr_data(0xdf);
- delay(1);
- }
- if(key1==0)
- {
- delay(3);//延時去抖
- if(key1==0)
- {
- while(!key1);
- delay(3);
- while(!key1);
- set_temper--;//溫度減
- if(set_temper==0)
- {set_temper=0;}
- }
-
- set[0]=set_temper/10; //獲得設(shè)置溫度顯示值
- set[1]=set_temper%10;
- wr_com(0x80+0x40+9); //顯示設(shè)置溫度值
- wr_data(table[set[0]]);
- delay(1);
- wr_com(0x80+0x40+10);
- wr_data(table[set[1]]);
- delay(1);
- //wr_com(0x80+0x40+11);
- //wr_data(0x2e);
- wr_com(0x80+0x40+14);
- wr_data(0xdf);
- delay(1);
- }
- }
- void PIDInit (struct PID *pp)
- {
- memset ( pp,0,sizeof(struct PID)); //用參數(shù)0初始化pp
- }
- unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint ) //PID計(jì)算
- {
- unsigned int dError,Error;
- Error = pp->SetPoint - NextPoint; // 偏差
- pp->SumError += Error; // 積分
- dError = pp->LastError - pp->PrevError; // 當(dāng)前微分
- pp->PrevError = pp->LastError;
- pp->LastError = Error;
- return (pp->Proportion * Error//比例
- + pp->Integral * pp->SumError //積分項(xiàng)
- + pp->Derivative * dError); // 微分項(xiàng)
- }
- /***********************************************************
- 溫度比較處理子程序
- ***********************************************************/
- void compare_temper(void)
- {
- unsigned char i;
- if(set_temper>temper) //設(shè)置溫度大于當(dāng)前溫度
- {
- buzzer_flag = 0;
- ledred=0;
- ledgreen=1;
- if(set_temper-temper>1) //溫度相差1度以上
- {
- high_time=100;
- low_time=0;
- }
- else //設(shè)置溫度不大于當(dāng)前溫度
- {
- //模糊計(jì)算
- fuzzy_engine((set_temper-temper)*10);
- high_time=(unsigned char)(fuzzy_out*4);
- if(high_time>100)
- high_time = 100;
- low_time= (100-high_time);
- }
- }
- else if(set_temper<=temper) //設(shè)置溫度不大于當(dāng)前溫度
- {
- buzzer_flag = 1;
- ledred=1;
- ledgreen=0;
- if(temper-set_temper>0) //溫度相差0度以上
- {
- high_time=0;
- low_time=100;
- }
- else
- {
- high_time=0;
- low_time=100;
- }
- }
- }
- /*****************************************************
- T0中斷服務(wù)子程序,用于控制電平的翻轉(zhuǎn) ,40us*100=4ms周期
- ******************************************************/
- void serve_T0() interrupt 1 using 1
- {
- if(++count<=(high_time)) output=0;
- else if(count<=50)
- {
- output=1;
- }
- else count=0;
- TH0=0x2f;
- TL0=0x40;
- }
- void UsarrtInit(){
- SCON = 0x50; //8-bit variable UART
- TMOD |= 0x20; //Set Timer1 as 8-bit auto reload mode
- TH1 = TL1 = 0XFD; //Set auto-reload vaule
- TR1 = 1; //Timer1 start run
- ES = 1; //Enable UART interrupt
- EA = 1; //Open master interrupt switch
- }
- void SendData(unsigned char dat)
- {
- while (busy); //Wait for the completion of the previous data is sent
- ACC = dat; //Calculate the even parity bit P (PSW.0)
- busy = 1;
- SBUF = ACC; //Send data to UART buffer
- }
- /*----------------------------
- UART interrupt service routine
- ----------------------------*/
- void Uart_Isr() interrupt 4
- {
- unsigned char a;
-
- if (RI)
- {
- RI = 0; //Clear receive interrupt flag
- a=SBUF;
- if(!FinishFlag){
-
- Usart_Data[UsartCount]=a;
-
- if(++UsartCount>2){
- UsartCount=0;
- FinishFlag=1;
- }
-
- }else{
-
-
-
- }
-
- }
- if (TI)
- {
- TI = 0; //Clear transmit interrupt flag
- busy = 0; //Clear transmit busy flag
- }
- }
- void TemSendData(unsigned char SetNum){
- uchar d0,d1,d2,d3;
- if(tflag==0){
- d0=SetNum/1000+0x30;
- d1=SetNum%1000/100+0x30;
- d2=SetNum%100/10+0x30;
- d3=SetNum%10+0x30;
-
- if(d0==0x30){
-
- SendData('N');
- SendData(d1);
- SendData(d2);
- SendData('.');
- SendData(d3);
- SendData('E');
- SendData('\r');
- SendData('\n');
-
- }else{
- SendData('N');
- SendData(d0);
- SendData(d1);
- SendData(d2);
- SendData('E');
- SendData('\r');
- SendData('\n');
-
-
-
- }
- }else{
-
- SendData('N');
- SendData(d1);
- SendData(d2);
- SendData('E');
- SendData('\r');
- SendData('\n');
-
-
- }
- }
- void SetSendData(unsigned char SetNum){
- SendData('S');
- SendData(SetNum/10+48);
- SendData(SetNum%10+48);
- SendData('E');
- SendData('\r');
- SendData('\n');
- }
- void LedA_StateData(){
- SendData('L');
- SendData('A');
- if(ledred){
- SendData('1');
- }else{
- SendData('0');
- }
- SendData('E');
- SendData('\r');
- SendData('\n');
- }
- void LedB_StateData(){
- SendData('L');
- SendData('B');
- if(ledgreen){
- SendData('1');
- }else{
- SendData('0');
- }
- SendData('E');
- SendData('\r');
- SendData('\n');
- }
- void USart_Handle(){
- if(FinishFlag){
- if(Usart_Data[0]=='S'){;
- set_temper=((Usart_Data[1]-48)*10)+(Usart_Data[2]-48);
-
- }
- set[0]=set_temper/10; //獲得設(shè)置溫度顯示值
- set[1]=set_temper%10;
- wr_com(0x80+0x40+9); //顯示設(shè)置溫度值
- wr_data(table[set[0]]);
- delay(1);
- wr_com(0x80+0x40+10);
- wr_data(table[set[1]]);
- delay(1);
-
- FinishFlag=0;
- }
- }
- /***********主函數(shù)**********/
- void main(void)
- {
-
- unsigned char i;
- init();//LCD初始化
-
- TMOD=0x01;
- TH0=0x2f;
- TL0=0x40;
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼本人初學(xué),僅供參考,存在錯誤和不足之處,請大家回帖多多指教,不勝感激.切勿照搬
仿真:無
電路圖:無
Keil代碼下載:
程序.zip
(120.62 KB, 下載次數(shù): 80)
2023-5-15 16:34 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|