□□ ,
(1.山西職業(yè)技術(shù)學(xué)院,山西 太原 030006;2.天津工業(yè)職業(yè)學(xué)院,天津 300232)
按照規(guī)定的順序依次完成各種操作的控制系統(tǒng)稱為順序控制。在工業(yè)應(yīng)用方面,順序功能圖(SFC)是順序控制程序設(shè)計中的一種方法,該方法可以描述控制系統(tǒng)的整個工作過程,是設(shè)計電氣控制系統(tǒng)的重要方法,廣泛用于可編程控制器(PLC)的程序設(shè)計。如果采用單片機(jī)代替可編程控制器,可以降低成本,但此時單片機(jī)需要在C語言的支持下。C語言具有很強(qiáng)的邏輯描述能力,比可編程控制器中使用的梯形圖語言更加好用。本文就如何用C語言實現(xiàn)順序功能圖(SFC)進(jìn)行探討。
啟動單片機(jī)后就進(jìn)入有效工作步??梢栽O(shè)置一個局部變量,該變量在while(1)循環(huán)語句執(zhí)行前為1,在循環(huán)語句結(jié)束前使該變量為0,這樣該局部變量只在第一個while(1)循環(huán)中為1,因此可以作為進(jìn)入有效工作步的條件。另外,還可以使用按鈕進(jìn)入有效工作步,但應(yīng)該加以限制條件,以避免按鈕的按下影響工作步正常轉(zhuǎn)移的情況。
可以使用按鈕停止流程,方法是在while(1)循環(huán)結(jié)束前增加語句:
if(n0){step0=0;step1=0;…stepn=0;}//n0是按鈕,stepn是工作步。
停止有效工作步后,若返回到工作步step0,則可以按照如下語句描述:
if(n0){step0=1;step1=0;…stepn=0;}//n0是按鈕,stepn是工作步。
一般情況下,需要在最后一個工作步完成之后,返回第一個工作步,但有時需要做一些判斷,例如在一個工藝流程結(jié)束后,是否進(jìn)行第二個工藝流程等。
如果在程序中有tj=1為條件停止有效工作步的語句,或者有tj=0為條件返回第一個工作步的語句,則可實現(xiàn)下一個流程的啟動與停止操作。一般是增加一個鈕子開關(guān)判斷語句:
if(n1)tj=1;else tj=0;//n1是鈕子開關(guān)信號,如果n1=1,則tj=1,否則tj=0。
轉(zhuǎn)移條件可以是來自單片機(jī)外部的按鈕、行程開關(guān)、傳感器等輸出的信號,也可以是來自內(nèi)部的定時器的時間到條件、計數(shù)器的計數(shù)數(shù)值條件等。
單片機(jī)中可以直接使用定時器的時間數(shù)值。例如if(t0>12),表示定時器t0的數(shù)值>12時就滿足轉(zhuǎn)移條件,其中t0是對單片機(jī)定時器中斷計數(shù)的全局變量;又例如,if(cnt>8)表示計數(shù)器cnt數(shù)值>8時就滿足轉(zhuǎn)移條件,其中cnt是可以對按鈕動作、流程循環(huán)次數(shù)等計數(shù)的全局變量。
工作步的得電條件是:該步的上一個工作步是有效工作步,而該步的下一步?jīng)]有工作,這時若出現(xiàn)轉(zhuǎn)移條件,則該工作步就會得電變成有效工作步。
工作步失電的條件是:該步的下一個工作步得電,則該工作步失電。
一般情況下工作步都需要自鎖。例如:若step0,step1和step2是三個順序執(zhí)行的工作步,則step1得電與失電的條件可以寫為:If(((step0&轉(zhuǎn)移條件)I step1)&step2) step1=1;else step1=0;
一般工作步得電與失電條件的梯形圖如圖1所示。
圖1 工作步梯形圖
選擇性分支是指各分支具有各自的工作步得電的條件,若滿足該條件,則該分支工作步得電;若不滿足,則該分支工作步就不能得電。
選擇性分支如圖2所示,圖中n0,n1,n2,n3是按鈕或開關(guān)條件。其中step1的得電條件是:step0得電,step3失電,選擇條件n1=1。應(yīng)該使轉(zhuǎn)移條件n1與n2互斥,就是只能向一個分支轉(zhuǎn)移。
圖2 選擇性分支
對應(yīng)的C語言描述如下:
start=1;//啟動條件,在while語句中,只在一個周期中有效。
while(1)
{if(((n0&step3) I step0 l start)&! step1&! step2)step0=1;else step0=0;//n0為轉(zhuǎn)移條件,step3為有效工作步。
if(((n1&step0) I step1)&!step3) step1=1;else step1=0;//分支step1,n1為轉(zhuǎn)移條件,step0為有效工作步。
if(((n2&step0) I step2)&!step3) step2=1,else step2=0;//分支step2,n2為轉(zhuǎn)移條件,step0為有效工作步。
if(((n3&step1 I n3&step2) I step3)&!step0) step3=1;else step3=0;
start=0;//n3為轉(zhuǎn)移條件,step1或step2為有效工作步。
}
并發(fā)工作步是指在一個得電條件下,幾個并發(fā)分支都得電,所以幾個并發(fā)分支的得電條件是一樣的。所有并發(fā)工作步都結(jié)束后,才能進(jìn)行工作步轉(zhuǎn)移。所以,若要工作步轉(zhuǎn)移,則需要所有并發(fā)分支的轉(zhuǎn)移條件相“與”。
圖3所示為一個具有并發(fā)分支的SFC圖。圖中工作步step1和工作步step2是并發(fā)分支,n0,n1,n2,n3是按鈕或開關(guān)條件。
圖3 具有并發(fā)分支的SFC圖
start=1;//第1周期信號。
while(1)
{
if(((n0&step3) l step0 l start)&! Step1&! step2) step0=1;else step0=0;
if(((n1&step0) I step1)&! step3)step1=1;else step1=0;//并發(fā)分支step1。
if(((n1&step0) I step2)&! step3)step2=1;else step2=0;//并發(fā)分支step2。
if(((n2&n3&step1& step2) I step3)&! step0)step3=1;else step3=0;
start=0;}//第一周期信號失效語句。
第0工作步是單片機(jī)上電后的狀態(tài)。當(dāng)除了第0工作步以外的工作步都無效時,第0工作步有效。所以,第0工作步的一個得電條件是,除了第0工作步以外的工作步都無效。停止條件出現(xiàn)后,程序應(yīng)該回到第0工作步。
在有些系統(tǒng)中,工作步就是動作輸出。在這種情況下,工作步的繼電器就是單片機(jī)的輸出引腳。而在另一些系統(tǒng)中,動作輸出是工作步的邏輯組合。
動作開始時刻就是工作步得電時刻,動作結(jié)束時刻就是工作步失電時刻。若動作時間是一個工作步,則工作步就可以是輸出;若該動作還需要在下一個工作步繼續(xù)動作,則這時該動作就是這兩個工作步的“或”。
描述SFC的一般C語言結(jié)構(gòu)如下:
while(1)
{
輸入掃描部分;
工作步流程部分;
輸出部分;
其他部分;
}
其中:
(1)輸入掃描部分就是處理按鈕、行程開關(guān)、傳感器等信號。
(2)工作步流程部分就是按照輸入條件,實現(xiàn)工作步的轉(zhuǎn)移。輸入條件可以是按鈕、行程開關(guān)或傳感器等外部輸入的信號,也可以是單片機(jī)內(nèi)部的定時器或計數(shù)器信號。
(3)輸出部分就是描述對應(yīng)各個工作步的輸出動作。
(4)其他部分:停止信號、首次whie(1)循環(huán)有效信號、按鈕信號和歸零信號等。
圖4是送料小車運行的示意圖,該小車可以在A和B之間往返運動,在A和B點各存在一個行程開關(guān),小車從A點向B點前進(jìn),到達(dá)B點后,停車6 s,然后從B點后退到A點,在A點停車8 s后再向B點前進(jìn),如此循環(huán)往復(fù)。在這個過程中,要求可以人為控制小車的前進(jìn)啟動和后退啟動,并且能夠在任何時候可以使小車停止運行。根據(jù)所描述過程,該控制的信號接線如圖5所示。
圖4 小車運行示意圖
圖5 小車運行信號接線圖
該工作過程的工作步是小車前進(jìn)、在B點定時6 s、小車后退、在A點定時8 s,一共四步:轉(zhuǎn)移條件是小車到達(dá)B點后行程開關(guān)閉合、B點定時6 s時間到、小車到達(dá)A點后行程開關(guān)閉合和A點定時8 s時間到;動作是小車從A點向B點的前進(jìn)動作、啟動6 s定時器動作、小車從B點向A點的退回動作和啟動8 s定時器動作。
該工作過程要求小車能夠前進(jìn)啟動和后退啟動,這時需要采用選擇分支結(jié)構(gòu)。當(dāng)按下前進(jìn)啟動按鈕時,小車向B點前進(jìn);當(dāng)按下后退啟動按鈕時,小車向A點后退。停止按鈕的動作是停止正在工作的步,回到第0步。
綜上所述,該工作過程的SFC圖如圖6所示。
圖6 小車運行SFC圖
根據(jù)工作過程,有變量(PLC中又稱為地址)如下:
n0前進(jìn)按鈕、n1后退按鈕、n2停止按鈕、n3為B點行程開關(guān)、n4為A點行程開關(guān);step0上電狀態(tài)步、step1為小車前進(jìn)運行步、step2為B點定時工作步、step3為小車后退運行步、step4為A點定時工作步。run0前進(jìn)啟動、run1后退啟動,time0為B點定時器、time1為A點定時器。
該工作過程的C語言程序如下:
#include"AT89X51.h"
unsigned char code table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
unsigned char n0,n1,n2,n3,n4,sn;
unsigned char kk=8,start,run0,run1;
unsigned char step0=0,step1=0,step2=0,step3=0,step4=0;
unsigned char time0,time1;
unsigned char t0,t1;
void main ()
{
unsigned int nn;//如下是定時器0初始化描述:
TMOD=0x01;//定時器0,M1M0=01(模式1),gate=0,C/T=0。
TH0=0x3c;//初值為0x3cb0=65 536-50 000=15 536,50 ms中斷一次,20次/s,時鐘12 MHz。
TL0=0xb0;//TL初值。
TR0=1;//啟動定時器0。
ET0=1;//設(shè)置中斷使能寄存器,允許定時器0中斷。
EA=1;//允許所有中斷。
Start=1;//第一周期啟動標(biāo)志1。
while(1)
{
P3=0xff;//P3口連接8個按鍵作為輸入,用按鍵代替前進(jìn)、后退和停止按鈕與行程開關(guān)等。
if(P3_0==0) //如果與P3.0引腳(n0)連接的按鍵按下,前進(jìn)啟動。
{for(nn=0;n<1 000;nn++);//延時消抖。
if(P3_0==0){n0=1;kk=0;}
else{n0=0;}
}
if(P3_1==0)//如果與P3.1引腳(n1)連接的鍵按下,后退啟動。
{for(nn=0;nn<1 000;n++);
if(P3_1==0){n1=1;kk=1;}
else{n1=0;}
}
if(P3_2==0)//如果與P3.2引腳(n2)連接的按鍵按下,小車停止運行。
{for(nn=0;nn<1 000;nn++);
if(P3_2==0){n2=1;Kk=2;}
else{n2=0;}
}
if(P3_3==0)//如果與P3.3引腳(n3)連接的按鍵核下,到達(dá)B點。
{for(nn=0;nn<1 000;nn++);
if(P3_3==0){n3=1;kk=3;}
else{n3=0;}
}
if(P3_4==0)//如果與P3.4引腳(n4)連接的按鍵按下,返回A點。
{for(nn=0;nn<1 000,nn++);
if(P3_4=0){n4=1;kk=4;}
else{n4=0;}
}
if(n0&! step1&! step2&!step3&!step4) run0=1;else run0=0;//小車前進(jìn),不自鎖,手工控制到B點。
if(n1&! step1&! step2&!step3&!step4) run1=1;else run1=0;//小車后退,不自鎖,手工控制到A點。
if((start I step0)&!step1&!step3) step0=1;else step0=0;//上電初始步step0=1。
if((run0&step0 I time1&step4 I step1)&!step2) step1=1;else step1=0;//前進(jìn)步step1=1。
if((n3&step1 l step2)&!step3)step2=1,else{step2=0;t0=0;}//到達(dá)B點,step2=1,啟動定時t0。
if(t0>6)time0=1;else time0=0;//如果t0>6,定時器time0=1。
if((run1&step0 I time0&step2 I step3)&! step4) step3=1;else step3=0;//后退步,step3=1。
if((n4&step3 I step4)&! step1) step4=1;else{step4=0;t1=0;}//到達(dá)A點,step4=1,啟動定時t1。
if(t1>8)time1=1;else time1=0;//如果t1>8,定時器time1=1。
if(step1)P2_6=0;else P2_6=1;//前進(jìn)動作信號輸出,LED燈顯示小車前進(jìn)。
if(step3)p2_7=0;else P2_7=1;//后退動作信號輸出,LED燈顯示小車后退。
if(n2){Step0=1;step1=0;step2=0;step3=0;step4=0;}//停止按鈕按下,回到初始步step0。
start=0;//上電啟動標(biāo)志清零。
if(step0)sn=0;//將工作步轉(zhuǎn)換成數(shù)子在數(shù)碼管上顯示。
if(step1)sn=1;
if(step2)sn=2;
if(step3)sn=3;
if(step4)sn=4;
P0=table[sn〗;//與P0口連接的數(shù)碼管顯示工作步。
if(step0)P2_0=0;e1se P2_0=1;//用LED燈顯示工作步。
if(step1)P2_1=0;e1se P2_1=1;
if(step2)P2_2=0;e1se P2_2=1;
if(step3)P2_3=0;e1se P2_3=1;
if(step4)P2_4=0;e1se P2_4=1;
if(step2)P1=table[t0];//將定時數(shù)據(jù)顯示在與P1口連接的數(shù)碼管上。
if(step4)P1=table[t1];
}}
void timer0() interrupt 1 //定時器0中斷服務(wù)程序。
{
static unsigned char jj;
TH0=0x3c;//重置初值。
TL0=0xb0;//重置初值。
jj++;
if(jj==20) //如果jj=20,則為1 s,為調(diào)試方便,可以減小jj值。
{jj=0;
t0++;
if(t0>10)t0=0;
t1++;
if(t1>10)t1=0;
}}
當(dāng)采用51單片機(jī)實現(xiàn)SFC圖,可以使學(xué)習(xí)者從可編程控制器和單片機(jī)兩個不同的角度拓展編程思路。同時,利用C語言進(jìn)行編程,邏輯性強(qiáng),操作簡單,降低成本,比可編程控制器中使用的順序功能圖(SFC)語言更為好用。