總所周知贝奇,PID算法是個(gè)很經(jīng)典的東西。而做自平衡小車靠胜,飛行器PID是一個(gè)必須翻過的坎掉瞳。因此本節(jié)我們來好好講解一下PID,根據(jù)我在學(xué)習(xí)中的體會(huì)浪漠,力求通俗易懂陕习。并舉出PID的形象例子來幫助理解PID。一址愿、首先介紹一下PID名字的由來:P:Proportion(比例)该镣,就是輸入偏差乘以一個(gè)常數(shù)。I? :Integral(積分)响谓,就是對(duì)輸入偏差進(jìn)行積分運(yùn)算损合。D:Derivative(微分),對(duì)輸入偏差進(jìn)行微分運(yùn)算歌粥。注:輸入偏差=讀出的被控制對(duì)象的值-設(shè)定值塌忽。比如說我要把溫度控制在26度,但是現(xiàn)在我從溫度傳感器上讀出溫度為28度失驶。則這個(gè)26度就是”設(shè)定值“土居,28度就是“讀出的被控制對(duì)象的值”胞枕。然后來看一下狸捕,這三個(gè)元素對(duì)PID算法的作用憔购,了解一下即可姨蟋,不懂不用勉強(qiáng)镊辕。P吉拳,打個(gè)比方暮芭,如果現(xiàn)在的輸出是1想鹰,目標(biāo)輸出是100胎围,那么P的作用是以最快的速度達(dá)到100吁系,把P理解為一個(gè)系數(shù)即可德召;而I呢?大家學(xué)過高數(shù)的汽纤,0的積分才能是一個(gè)常數(shù)上岗,I就是使誤差為0而起調(diào)和作用;D呢蕴坪?大家都知道微分是求導(dǎo)數(shù)肴掷,導(dǎo)數(shù)代表切線是吧,切線的方向就是最快到至高點(diǎn)的方向背传。這樣理解呆瞻,最快獲得最優(yōu)解,那么微分就是加快調(diào)節(jié)過程的作用了径玖。二痴脾、然后要知道PID算法具體分兩種:一種是位置式的 ,一種是增量式的梳星。在小車?yán)镆话阌迷隽渴矫鞴瑸槭裁茨兀课恢檬絇ID的輸出與過去的所有狀態(tài)有關(guān)丰泊,計(jì)算時(shí)要對(duì)e(每一次的控制誤差)進(jìn)行累加,這個(gè)計(jì)算量非常大始绍,而明顯沒有必要瞳购。而且小車的PID控制器的輸出并不是絕對(duì)數(shù)值,而是一個(gè)亏推,代表增多少学赛,減多少。換句話說吞杭,通過增量PID算法盏浇,每次輸出是PWM要增加多少或者減小多少,而不是PWM的實(shí)際值芽狗。所以明白增量式PID就行了绢掰。三、接著講PID參數(shù)的整定童擎,也就是PID公式中滴劲,那幾個(gè)常數(shù)系數(shù)Kp,Ti顾复,Td等是怎么被確定下來然后帶入PID算法中的班挖。如果要運(yùn)用PID,則PID參數(shù)是必須由自己調(diào)出來適合自己的項(xiàng)目的芯砸。通常四旋翼萧芙,自平衡車的參數(shù)都是由自己一個(gè)調(diào)節(jié)出來的给梅,這是一個(gè)繁瑣的過程。本次我們可以不管双揪,關(guān)于PID參數(shù)怎么確定的动羽,網(wǎng)上有很多經(jīng)驗(yàn)可以借鑒。比如那個(gè)經(jīng)典的經(jīng)驗(yàn)試湊口訣:? ? ? ? ? ? ? ? ? ? ? ? 參數(shù)整定找最佳盟榴, 從小到大順序查曹质。? ? ? ? ? ? ? ? ? ? ? ? 先是比例后積分, 最后再把微分加擎场。? ? ? ? ? ? ? ? ? ? ? ? 曲線振蕩很頻繁羽德, 比例度盤要放大。? ? ? ? ? ? ? ? ? ? ? ? 曲線漂浮繞大彎迅办, 比例度盤往小扳宅静。? ? ? ? ? ? ? ? ? ? ? ? 曲線偏離回復(fù)慢, 積分時(shí)間往下降站欺。? ? ? ? ? ? ? ? ? ? ? ? 曲線波動(dòng)周期長(zhǎng)姨夹, 積分時(shí)間再加長(zhǎng)。? ? ? ? ? ? ? ? ? ? ? ? 曲線振蕩頻率快矾策, 先把微分降下來磷账。? ? ? ? ? ? ? ? ? ? ? ? 動(dòng)差大來波動(dòng)慢, 微分時(shí)間應(yīng)加長(zhǎng)贾虽。? ? ? ? ? ? ? ? ? ? ? ? 理想曲線兩個(gè)波逃糟, 前高后低四比一。? ? ? ? ? ? ? ? ? ? ? ? 一看二調(diào)多分析蓬豁, 調(diào)節(jié)質(zhì)量不會(huì)低绰咽。四、接下來我們用例子來輔助我們把常用的PID模型講解了地粪。(PID控制并不一定要三者都出現(xiàn)取募,也可以只是PI、PD控制蟆技,關(guān)鍵決定于控制的對(duì)象玩敏。)(下面的內(nèi)容只是介紹一下PID模型,可以不看付魔,對(duì)理解PID沒什么用)例子:我們要控制一個(gè)人聊品,讓他一PID的控制方式來行走110步后停下來。1)P比例控制几苍,就是讓他按照一定的比例走翻屈,然后停下。比如比例系數(shù)為108妻坝,則走一次就走了108步伸眶,然后就不走了惊窖。說明:P比例控制是一種最簡(jiǎn)單的控制方式,控制器的輸出與輸入誤差信號(hào)成比例關(guān)系厘贼。但是僅有比例控制時(shí)系統(tǒng)輸出存在穩(wěn)態(tài)誤差界酒。比如上面的只能走到108,無論怎樣都走不到110嘴秸。2)PI積分控制毁欣,就是按照一定的步伐走到112步然后回頭接著走,走到108步位置時(shí)岳掐,然后又回頭向110步位置走凭疮。在110位置處來回晃蕩幾次,最后停在110步的位置串述。說明:在積分I控制中执解,控制器的輸出與輸入誤差信號(hào)的積分成正比關(guān)系。對(duì)一個(gè)自動(dòng)控制系統(tǒng)來說纲酗,如果在進(jìn)入穩(wěn)態(tài)后存在穩(wěn)態(tài)誤差衰腌,則稱這個(gè)控制系統(tǒng)是有穩(wěn)態(tài)誤差的或簡(jiǎn)稱有差系統(tǒng)。為了消除穩(wěn)態(tài)誤差觅赊,在控制器中必須引入“積分項(xiàng)”右蕊。積分項(xiàng)對(duì)誤差的影響取決于時(shí)間的積分,隨著時(shí)間的增加吮螺,積分項(xiàng)會(huì)增大尤泽。這樣,即便誤差很小规脸,積分項(xiàng)也會(huì)隨著時(shí)間的增加而加大,它推動(dòng)控制器的輸出增大熊咽,從而使穩(wěn)態(tài)誤差進(jìn)一步減小莫鸭,直到等于0。因此横殴,比例+積分(PI)控制器可以使系統(tǒng)在進(jìn)入穩(wěn)態(tài)后無穩(wěn)態(tài)誤差被因。3)PD微分控制,就是按照一定的步伐走到一百零幾步后衫仑,再慢慢地走向110步的位置靠近梨与,如果最后能精確停在110步的位置,就是無靜差控制文狱;如果停在110步附近(如109步或111步位置)粥鞋,就是有靜差控制。說明:在微分控制D中瞄崇,控制器的輸出與輸入誤差信號(hào)的微分(即誤差的變化率)成正比關(guān)系呻粹。? ? ? 自動(dòng)控制系統(tǒng)在克服誤差的調(diào)節(jié)過程中可能會(huì)出現(xiàn)振蕩甚至失穩(wěn)壕曼,原因是存在較大慣性組件(環(huán)節(jié))或滯后組件,具有抑制誤差的作用等浊,其變化總是落后于誤差的變化腮郊。解決的辦法是使抑制誤差作用的變化“超前”,即在誤差接近于零時(shí)筹燕,抑制誤差的作用就應(yīng)該是零轧飞。這就是說,在控制器中僅引入“比例P”項(xiàng)往往是不夠的撒踪,比例項(xiàng)的作用僅是放大誤差的幅值过咬,而目前需要增加的是“微分項(xiàng)”,它能預(yù)測(cè)誤差變化的趨勢(shì)糠涛。這樣援奢,具有比例+微分的控制器就能夠提前使抑制誤差的控制作用等于零,甚至為負(fù)值忍捡,從而避免了被控量的嚴(yán)重超調(diào)集漾。所以對(duì)有較大慣性或滯后的被控對(duì)象,比例P+微分D(PD)控制器能改善系統(tǒng)在調(diào)節(jié)過程中的動(dòng)態(tài)特性砸脊。五具篇、用小明來說明PID:? ? ? 小明接到這樣一個(gè)任務(wù):有一個(gè)水缸有點(diǎn)漏水(而且漏水的速度還不一定固定不變),要求水面高度維持在某個(gè)位置凌埂,一旦發(fā)現(xiàn)水面高度低于要求位置驱显,就要往水缸里加水。 小明接到任務(wù)后就一直守在水缸旁邊瞳抓,時(shí)間長(zhǎng)就覺得無聊埃疫,就跑到房里看小說了,每30分鐘來檢查一次水面高度孩哑。水漏得太快栓霜,每次小明來檢查時(shí),水都快漏完了横蜒,離要求的高度相差很遠(yuǎn)胳蛮,小明改為每3分鐘來檢查一次,結(jié)果每次來水都沒怎么漏丛晌,不需要加水仅炊,來得太頻繁做的是無用功。幾次試驗(yàn)后澎蛛,確定每10分鐘來檢查一次抚垄。這個(gè)檢查時(shí)間就稱為采樣周期。 開始小明用瓢加水,水龍頭離水缸有十幾米的距離督勺,經(jīng)常要跑好幾趟才加夠水渠羞,于是小明又改為用桶加,一加就是一桶智哀,跑的次數(shù)少了次询,加水的速度也快了,但好幾次將缸給加溢出了瓷叫,不小心弄濕了幾次鞋屯吊,小明又動(dòng)腦筋,我不用瓢也不用桶摹菠,老子用盆盒卸,幾次下來,發(fā)現(xiàn)剛剛好次氨,不用跑太多次蔽介,也不會(huì)讓水溢出。這個(gè)加水工具的大小就稱為比例系數(shù)煮寡。? ? ? ? 小明又發(fā)現(xiàn)水雖然不會(huì)加過量溢出了虹蓄,有時(shí)會(huì)高過要求位置比較多,還是有打濕鞋的危險(xiǎn)幸撕。他又想了個(gè)辦法薇组,在水缸上裝一個(gè)漏斗,每次加水不直接倒進(jìn)水缸坐儿,而是倒進(jìn)漏斗讓它慢慢加律胀。這樣溢出的問題解決了,但加水的速度又慢了貌矿,有時(shí)還趕不上漏水的速度炭菌。于是他試著變換不同大小口徑的漏斗來控制加水的速度,最后終于找到了滿意的漏斗逛漫。漏斗的時(shí)間就稱為積分時(shí)間娃兽。? ? ? ? 小明終于喘了一口,但任務(wù)的要求突然嚴(yán)了尽楔,水位控制的及時(shí)性要求大大提高,一旦水位過低第练,必須立即將水加到要求位置阔馋,而且不能高出太多,否則不給工錢娇掏。小明又為難了呕寝!于是他又開努腦筋,終于讓它想到一個(gè)辦法婴梧,常放一盆備用水在旁邊下梢,一發(fā)現(xiàn)水位低了客蹋,不經(jīng)過漏斗就是一盆水下去,這樣及時(shí)性是保證了孽江,但水位有時(shí)會(huì)高多了讶坯。他又在要求水面位置上面一點(diǎn)將水缸要求的水平面處鑿一孔,再接一根管子到下面的備用桶里這樣多出的水會(huì)從上面的孔里漏出來岗屏。這個(gè)水漏出的快慢就稱為微分時(shí)間辆琅。六、在代碼中理解PID:(好好看注釋这刷,很好理解的婉烟。注意結(jié)合下面PID的公式)首先看PID的增量型公式:PID=Uk+KP*【E(k)-E(k-1)】+KI*E(k)+KD*【E(k)-2E(k-1)+E(k-2)】在單片機(jī)中運(yùn)用PID,出于速度和RAM的考慮暇屋,一般不用浮點(diǎn)數(shù)似袁,這里以整型變量為例來講述PID在單片機(jī)中的運(yùn)用。由于是用整型來做的咐刨,所以不是很精確昙衅。但是對(duì)于一般的場(chǎng)合來說,這個(gè)精度也夠了所宰,關(guān)于系數(shù)和溫度在程序中都放大了10倍绒尊,所以精度不是很高,但是大部分的場(chǎng)合都?jí)蛄俗兄啵舨粔蛴て祝梢栽俜糯?0倍或者100倍處理,不超出整個(gè)數(shù)據(jù)類型的范圍就可以了躯泰。一下程序包括PID計(jì)算和輸出兩部分谭羔。當(dāng)偏差>10度時(shí)全速加熱,偏差在10度以內(nèi)時(shí)為PID計(jì)算輸出麦向。程序說明:下面的程序瘟裸,先看main函數(shù)∷薪撸可知在對(duì)定時(shí)器0初始化后就一直在執(zhí)行PID_Output()函數(shù)话告。在PID_Output()函數(shù)中先用iTemp變量來得到PID運(yùn)算的結(jié)果,來決定是啟動(dòng)加熱絲加熱還是不啟動(dòng)加熱絲卵慰。下面的if語句結(jié)合定時(shí)器來決定PID算法多久執(zhí)行一次沙郭。PID_Operation()函數(shù)看似很復(fù)雜,其實(shí)就一直在做一件事:根據(jù)提供的數(shù)據(jù)裳朋,用PID公式把最終的PID值算出來病线。
#include <reg52.h>typedefunsigned char? ? uChar8;? ? typedefunsigned int? ? ? uInt16;typedefunsigned longint? uInt32; sbit ConOut = P1^1;? ? //加熱絲接到P1.1口 typedefstruct? PID_Value{? ? uInt32 liEkVal[3];? ? ? ? ? //差值保存,給定和反饋的差值? ? uChar8 uEkFlag[3];? ? ? ? ? //符號(hào),1則對(duì)應(yīng)的為負(fù)數(shù)送挑,0為對(duì)應(yīng)的為正數(shù)? ? ? uChar8 uKP_Coe;? ? ? ? ? ? //比例系數(shù)? ? uChar8 uKI_Coe;? ? ? ? ? ? //積分常數(shù)? ? uChar8 uKD_Coe;? ? ? ? ? ? //微分常數(shù)? ? uInt16 iPriVal;? ? ? ? ? ? //上一時(shí)刻值? ? uInt16 iSetVal;? ? ? ? ? ? //設(shè)定值? ? uInt16 iCurVal;? ? ? ? ? ? //實(shí)際值}PID_ValueStr; PID_ValueStr PID;? ? ? ? ? ? ? //定義一個(gè)結(jié)構(gòu)體绑莺,這個(gè)結(jié)構(gòu)體用來存算法中要用到的各種數(shù)據(jù)bit g_bPIDRunFlag = 0;? ? ? ? ? //PID運(yùn)行標(biāo)志位,PID算法不是一直在運(yùn)算惕耕。而是每隔一定時(shí)間纺裁,算一次。/* ********************************************************/* 函數(shù)名稱:PID_Operation()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 函數(shù)功能:PID運(yùn)算? ? ? ? ? ? ? ? ? /* 入口參數(shù):無(隱形輸入赡突,系數(shù)对扶、設(shè)定值等)? ? ? ? ? ? ? ? ? ? /* 出口參數(shù):無(隱形輸出,U(k))/* 函數(shù)說明:U(k)+KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ******************************************************** */voidPID_Operation(void){? ? uInt32 Temp[3] = {0};? //中間臨時(shí)變量? ? uInt32 PostSum = 0;? ? //正數(shù)和? ? uInt32 NegSum = 0;? ? ? //負(fù)數(shù)和? ? if(PID.iSetVal > PID.iCurVal)? ? ? ? ? ? ? ? //設(shè)定值大于實(shí)際值否惭缰?? ? {? ? ? ? if(PID.iSetVal - PID.iCurVal > 10)? ? ? //偏差大于10否浪南?? ? ? ? ? ? PID.iPriVal = 100;? ? ? ? ? ? ? ? ? //偏差大于10為上限幅值輸出(全速加熱)? ? ? ? else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //否則慢慢來? ? ? ? {? ? ? ? ? ? Temp[0] = PID.iSetVal - PID.iCurVal;? ? //偏差<=10,計(jì)算E(k)? ? ? ? ? ? PID.uEkFlag[1] = 0;? ? ? ? ? ? ? ? ? ? //E(k)為正數(shù),因?yàn)樵O(shè)定值大于實(shí)際值? ? ? ? ? ? /* 數(shù)值進(jìn)行移位,注意順序漱受,否則會(huì)覆蓋掉前面的數(shù)值 */? ? ? ? ? ? PID.liEkVal[2] = PID.liEkVal[1];? ? ? ? ? ? PID.liEkVal[1] = PID.liEkVal[0];? ? ? ? ? ? PID.liEkVal[0] = Temp[0];? ? ? ? ? ? /* =================================================================== */? ? ? ? ? ? if(PID.liEkVal[0] > PID.liEkVal[1])? ? ? ? ? ? ? //E(k)>E(k-1)否络凿?? ? ? ? ? ? {? ? ? ? ? ? ? ? Temp[0] = PID.liEkVal[0] - PID.liEkVal[1];? //E(k)>E(k-1)? ? ? ? ? ? ? ? PID.uEkFlag[0] = 0;? ? ? ? ? ? ? ? ? ? ? ? //E(k)-E(k-1)為正數(shù)? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else? ? ? ? ? ? {? ? ? ? ? ? ? ? Temp[0] = PID.liEkVal[1] - PID.liEkVal[0];? //E(k)<E(k-1)? ? ? ? ? ? ? ? PID.uEkFlag[0] = 1;? ? ? ? ? ? ? ? ? ? ? ? //E(k)-E(k-1)為負(fù)數(shù)? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* =================================================================== */? ? ? ? ? ? Temp[2] = PID.liEkVal[1] * 2;? ? ? ? ? ? ? ? ? //2E(k-1)? ? ? ? ? ? if((PID.liEkVal[0] + PID.liEkVal[2]) > Temp[2]) //E(k-2)+E(k)>2E(k-1)否?? ? ? ? ? ? {? ? ? ? ? ? ? ? Temp[2] = (PID.liEkVal[0] + PID.liEkVal[2]) - Temp[2];? ? ? ? ? ? ? ? PID.uEkFlag[2]=0;? ? ? ? ? ? ? ? ? ? ? ? ? //E(k-2)+E(k)-2E(k-1)為正數(shù)? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //E(k-2)+E(k)<2E(k-1)? ? ? ? ? ? {? ? ? ? ? ? ? ? Temp[2] = Temp[2] - (PID.liEkVal[0] + PID.liEkVal[2]);? ? ? ? ? ? ? ? PID.uEkFlag[2] = 1;? ? ? ? ? ? ? ? ? ? ? ? //E(k-2)+E(k)-2E(k-1)為負(fù)數(shù)? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* =================================================================== */? ? ? ? ? ? Temp[0] = (uInt32)PID.uKP_Coe * Temp[0];? ? ? ? //KP*[E(k)-E(k-1)]? ? ? ? ? ? Temp[1] = (uInt32)PID.uKI_Coe * PID.liEkVal[0]; //KI*E(k)? ? ? ? ? ? Temp[2] = (uInt32)PID.uKD_Coe * Temp[2];? ? ? ? //KD*[E(k-2)+E(k)-2E(k-1)]? ? ? ? ? ? /* 以下部分代碼是講所有的正數(shù)項(xiàng)疊加昂羡,負(fù)數(shù)項(xiàng)疊加 */? ? ? ? ? ? /* ========= 計(jì)算KP*[E(k)-E(k-1)]的值 ========= */? ? ? ? ? ? if(PID.uEkFlag[0] == 0)? ? ? ? ? ? ? ? PostSum += Temp[0];? ? ? ? ? ? ? ? ? ? ? ? //正數(shù)和? ? ? ? ? ? else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NegSum += Temp[0];? ? ? ? ? ? ? ? ? ? ? ? ? //負(fù)數(shù)和? ? ? ? ? ? /* ========= 計(jì)算KI*E(k)的值 ========= */? ? ? ? ? ? if(PID.uEkFlag[1] == 0)? ? ? ? ? ? ? ? ? ? PostSum += Temp[1];? ? ? ? ? ? ? ? ? ? ? ? //正數(shù)和? ? ? ? ? ? else? ? ? ? ? ? ? ? ;? /* 空操作絮记。就是因?yàn)镻ID.iSetVal > PID.iCurVal(即E(K)>0)才進(jìn)入if的,? ? ? ? ? ? ? ? ? ? 那么就沒可能為負(fù)虐先,所以打個(gè)轉(zhuǎn)回去就是了 */? ? ? ? ? ? /* ========= 計(jì)算KD*[E(k-2)+E(k)-2E(k-1)]的值 ========= */? ? ? ? ? ? if(PID.uEkFlag[2]==0)? ? ? ? ? ? ? ? PostSum += Temp[2];? ? ? ? ? ? //正數(shù)和? ? ? ? ? ? else? ? ? ? ? ? ? ? NegSum += Temp[2];? ? ? ? ? ? ? //負(fù)數(shù)和? ? ? ? ? ? /* ========= 計(jì)算U(k) ========= */? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PostSum += (uInt32)PID.iPriVal;? ? ? ? ? ? ? ? ? ? if(PostSum > NegSum)? ? ? ? ? ? ? ? //是否控制量為正數(shù)? ? ? ? ? ? {? ? ? ? ? ? ? ? Temp[0] = PostSum - NegSum;? ? ? ? ? ? ? ? if(Temp[0] < 100 )? ? ? ? ? ? ? //小于上限幅值則為計(jì)算值輸出? ? ? ? ? ? ? ? ? ? PID.iPriVal = (uInt16)Temp[0];? ? ? ? ? ? ? ? elsePID.iPriVal = 100;? ? ? ? //否則為上限幅值輸出? ? ? ? ? ? }? ? ? ? ? ? else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //控制量輸出為負(fù)數(shù)怨愤,則輸出0(下限幅值輸出)? ? ? ? ? ? ? ? PID.iPriVal = 0;? ? ? ? }? ? }? ? elsePID.iPriVal = 0;? ? ? ? ? ? ? ? ? ? ? //同上,嘿嘿}/* ********************************************************/* 函數(shù)名稱:PID_Output()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 函數(shù)功能:PID輸出控制? ? ? ? ? ? ? ? /* 入口參數(shù):無(隱形輸入蛹批,U(k))? ? ? ? ? ? ? ? ? ? ? ? /* 出口參數(shù):無(控制端)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ******************************************************** */voidPID_Output(void){? ? staticuInt16 iTemp;? ? staticuChar8 uCounter;? ? iTemp = PID.iPriVal;? ? if(iTemp == 0)? ? ? ? ConOut = 1;? ? //不加熱? ? elseConOut = 0;? ? //加熱? ? if(g_bPIDRunFlag)? //定時(shí)中斷為100ms(0.1S)撰洗,加熱周期10S(100份*0.1S)? ? {? ? ? ? g_bPIDRunFlag = 0;? ? ? ? if(iTemp) iTemp--;? ? ? //只有iTemp>0,才有必要減“1”? ? ? ? uCounter++;? ? ? ? if(100 == uCounter)? ? ? ? {? ? ? ? ? ? PID_Operation();? ? //每過0.1*100S調(diào)用一次PID運(yùn)算腐芍。? ? ? ? ? ? uCounter = 0;? ? ? ? ? }? ? }}/* ********************************************************/* 函數(shù)名稱:PID_Output()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 函數(shù)功能:PID輸出控制? ? ? ? ? ? ? ? /* 入口參數(shù):無(隱形輸入差导,U(k))? ? ? ? ? ? ? ? ? ? ? ? /* 出口參數(shù):無(控制端)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ******************************************************** */voidTimer0Init(void){? ? TMOD |= 0x01;? // 設(shè)置定時(shí)器0工作在模式1下? ? TH0 = 0xDC;? ? TL0 = 0x00;? ? // 賦初始值? ? TR0 = 1;? ? ? ? // 開定時(shí)器0? ? EA = 1;? ? ? ? // 開總中斷? ? ET0 = 1;? ? ? ? // 開定時(shí)器中斷} voidmain(void){? ? Timer0Init();? ? while(1)? ? {? ? ? ? PID_Output();? ? }} voidTimer0_ISR(void) interrupt 1{? ? staticuInt16 uiCounter = 0;? ? TH0 = 0xDC;? ? TL0 = 0x00;? ? uiCounter++;? ? if(100 == uiCounter)? ? {? ? ? ? g_bPIDRunFlag = 1;? ? }}