多年前勇哥的一篇論文,關於plc仿真器的開發。有需要的朋友可以拿來參考一下。
為了能夠不依賴實際的硬體可編程控制器來實現基於可編程控制器的控制,研究和利用C#.net程式語言開發的可編程控制器仿真軟體.研究了基於面向對象軟體設計方法的梯形圖繪製技術,以及基於二叉樹數據結構的梯形圖向指令表的轉換問題.最終的的仿真器軟體實現了仿真三菱的FX系列PLC基本指令表,並利用組態組件的概念設計了軟體交互功能的UI,可以實時呈現指令運行的效果. 利用該虛擬可編程控制器仿真軟體可以用於可編程控制器的實訓和實驗教學.
關鍵詞:可編程控制器,PLC仿真,梯形圖,Visual c#
目 錄
1. 前言…………………………………………………………………………… 5
2. 系統的總體框架……………………………………………………………… 5
3. 梯形圖的編輯………………………………………………………………… 6
4. 梯形圖向指令表的轉換……………………………………………………… 12
5. 組態元件……………………………………………………………………… 14
6. 虛擬仿真實驗………………………………………………………………… 17
7. 結論…………………………………………………………………………… 20
8. 參考文獻……………………………………………………………………… 21
前 言
可編程邏輯控制器(PLC)與傳統的繼電器控制相比,具有可靠性高、抗幹擾能力強、操作簡單、擴展功能強等特點。PLC在工業控制領域得到了廣泛的應用,是自動技術的3大支柱之一。
可編程控制器應用技術實踐性非常強,實踐環節至關重要,只有通過實際編程操作,才能使PLC的操作人員真正掌握可編程控制器技術。但由於實踐所需要的設備具有價格昂貴、外圍元件連接複雜、維護困難等特點,這就為PLC技術的培訓帶來很大的瓶頸。
本文利用Visual C#開發平臺,研究和開發PLC仿真軟體,從而在沒有任何外部硬體電路的情況下,使用一臺運行windows作業系統的PC機,即可實現一臺實際硬體的PLC的控制功能。
1系統的總體框架
一臺實際的硬體PLC,具有與計算機類似的硬體,如中央處理器(CPU)、存儲器、輸入輸出部件等。PLC的標準程式語言由IEC61131-3標準提出,共有5種,分別是:梯形圖、功能塊圖、順序功能圖、指令表和結構化文本。其中梯形圖直觀明了,為大多數工程人員所喜用,是編寫PLC程序的首先語言。
本文開發的PLC模擬器支持梯形圖和指令表兩種方式。實際上,由梯形圖編制的PLC程序最終都是先經過編譯並轉換為指令表程序後,才可以加載到軟PLC執行系統上運行。所以如何把梯形圖轉為指令表是一個關鍵技術問題。
不同公司的PLC的指令集是不同的,我從流行度方向考慮,選擇三菱PLC的指令集做為本文PLC模擬器的指令集,這個指令集只包括一些最常見的基本指令集,差不多可以滿足一般PLC實訓或者實驗。
傳統的自動化設備,往往是PLC搭配組態軟體與設備,以實現人機互動。如觸控螢幕幕及其軟體就相當於完成了組態軟硬體與PLC的交互。本文的PLC模擬器也需要現實類似於組態軟體的模塊化元件,例如點動按鈕、文字輸入與文字顯示等元件,這些元件可以通過設置參數與PLC的內存單元關聯起來。有了這些組態模塊,使用可以方便的控制以及觀察PLC程序的運行狀態及效果。
圖1給出了PLC仿真系統的總體框架。
2 梯形圖的編輯
梯形圖是一種圖形語言,它與傳統的繼電器電路非常相似,它沿用繼電器的觸點、線圈,與指令表一道,構成了2種常用的PLC編程表達方式。對於一般的實驗來說,所用到的編程元件主要是輸入繼電器X、輸出繼電器Y、輔助繼電器M、定時器T;對於三菱系統的PLC來說這些元件主要用於基本順序控制指令、移位指令。
整個梯形圖可以看作主要由常開觸點、常閉觸點和線圈構成的一個個梯級。因此,在開發過程中,可以抽象為C#的一個類。這個類描述了梯形圖元件這個對象以及這個對象應具有的屬性。它可以方便的實現各種編程元件的繪製。
梯形圖的數據結構如下:
public struct LADDER //梯形圖數據結構
{
public partTypeEnum ladderType; //梯型圖類型
public string ladderParam; //指令參數
public bool isHaveVline; //有豎線 (所有元件都允許有豎線)
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj is LADDER)
{
var b = (LADDER)obj;
return this.isHaveVline == b.isHaveVline &&
this.ladderParam == b.ladderParam &&
this.ladderType == b.ladderType;
}
return base.Equals(obj);
}
};
其中,梯形圖類型是個枚舉變量,包括下面的類型:
public enum partTypeEnum
{
//nopPart空元件, lineNumPart行號元件,logicSymbol邏輯符號元件(虛擬不可見,
//由梯型圖編譯器使用)
anyPart = 0, nopenPart, closePart, orOpenPart, orClosePart,
coilPart, applicationPart, pPart, fPart, orpPart,
orfPart, notPart, hlinePart, vlinePart, nopPart,
lineNumPart, logicSymbol, leftParenthesis, rightParenthesis, nullSymbol, comma
}
其中 nopenPat為常開觸點,closePart為常閉觸點,pPart為上升沿檢測觸點,fPaft為下降沿檢測觸點,coilPart為線圈。其它一些類型為編輯器與指令編譯器用的特殊符號。
梯形圖繪製只需要實例化這些元件,就可以繪製出常開觸點、常閉觸點、線圈等元件。所有繪製通過函數drawPart()實現,在它的參數中,需要傳入繪製元件的X,Y坐標,和元件類型的實例。
private void drawPart(Graphics g, int startX, int startY, LADDER ladderNode)
{
Pen p = new Pen(Color.Black, 1);
switch (ladderNode.ladderType)
{
case partTypeEnum.nopenPart: //-||-
drawNopenPart(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.closePart: //-|/|-
drawClosePart(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.orOpenPart: //+-| |-+
darwOrOpenPart(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.orClosePart: //+-| / |-+
drawOrClosePart(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.coilPart: //— ( )—
drawCoilPart(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.applicationPart: //-[ ]-
drawApplicationPart(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.pPart: //—| P |—
drawP(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.fPart: //—| F |—
drawF(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.orpPart: //+-| P |-+
drawOrp(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.orfPart: //+-| F |-+
drawOrf(g, p, startX, startY, ladderNode);
break;
case partTypeEnum.notPart: //——/——
g.DrawLine(p, new Point(startX + 26, startY + 12), new Point(startX + 18, startY + 28));
break;
case partTypeEnum.hlinePart: //————
g.DrawLine(p, new Point(startX, startY + 20), new Point(startX + 44, startY + 20));
break;
case partTypeEnum.vlinePart: // |
break;
case partTypeEnum.nopPart: //空元件
break;
case partTypeEnum.lineNumPart:
g.DrawString(ladderNode.ladderParam, new Font("宋體", 10), new SolidBrush(Color.Black), startX + 10, startY + 15);
break;
}
if (ladderNode.isHaveVline)
g.DrawLine(p, new Point(startX, startY + 20), new Point(startX, startY + 60));
vline(g);
}
圖2是梯形圖中的常開觸點。
在C#中繪製這個常開觸點是採用畫線的方式,下面給出代碼,其畫線的方式和圖2所示意的一致。
private void drawNopenPart(Graphics g, Pen p, int startX, int startY, LADDER ladderNode)
{
//畫1,2
g.DrawLine(p, new Point(startX, startY + 20), new Point(startX + 18, startY + 20));
//畫3,4
g.DrawLine(p, new Point(startX + 18, startY + 12), new Point(startX + 18, startY + 28));
//畫5,6
g.DrawLine(p, new Point(startX + 26, startY + 12), new Point(startX + 26, startY + 28));
//畫7,8
g.DrawLine(p, new Point(startX + 26, startY + 20), new Point(startX + 44, startY + 20));
g.DrawString(ladderNode.ladderParam.LadderGetParam()[0], new Font("宋體", 10), new SolidBrush(Color.Black), startX - 2, startY - 1);
}
在編輯過程中,整個梯形圖被分割為若干個行和列。相當於元件只能繪製在各個方塊中。由於梯形圖的梯級數、行數、每行元件數、類別都是未知的,整個編輯過程是一個動態存儲過程。因此,以動態列表方式來記錄梯形圖的所有信息。這種數據結構也便於梯形圖向指令錶轉換以及指令的編譯運行。
圖3是仿真軟體的梯形編輯器全貌。
編輯器左邊是常用編程元件和常用功能,包括保存載入梯形圖,梯形圖轉為指令表等;空白區域是編輯區,藍色框是光標。基本編輯規則與三菱PLC編程軟體GX Developer類似。
整個編輯器利用C#的面向對象編程方法進行了封裝。編輯器myPanel是一個繼承於畫板Panel自定義控制項;這種方式可以促進組件重用,例如可以把這個編輯器用於其它的軟體,只需要做為控制項拖入到界面上即可。
3 梯形圖向指令表的轉換
梯形圖是由很多個梯級構成的。在梯形圖的人工轉換過程中,遵循著自上而下、從左往右的原則,逐個梯級進行轉換。因此,梯形圖本質上就是一個有向圖。梯形圖在繪製過程中,通過梯形圖的存儲數據結構,表明了各個元件所在的行與列。梯形圖的轉換過程就是把梯形圖先轉換為一棵二叉樹,然後根據二叉樹來識別相應的指令。
一幅梯形圖可以看成是觸點或者電路塊之間的串聯與並聯。而電路塊實質上就是2個或者2個以上的觸點構成的。所以本質上琮是觸點的串聯與並聯。串聯用「*」表示,並聯用「+」表示。如圖5所示是一個梯形圖。
按照自上而下、從左往右的原則,該梯形圖可轉換為圖6所示的二叉樹。
二叉樹是梯形圖向指令錶轉換的關鍵,每個梯級均對應一棵二叉樹。二叉樹清晰地表達了觸點之間的關係,通過對二叉樹進行遍歷,結合對應的觸點類型,進行指令表的書寫。轉換過程如下:
Step1:第1個看到的是1個部分,為常開觸點X0,故為LD X0;
Step2:第二部分對應的是常開觸點X1和常開觸點X3構成的電路塊。X1為電路塊開始的第一個常開觸點,故為 LD X1, X3與X1的關係為邏輯「與」,故為 AND X3
Step3:看到的是「+」號(注意圖上+號後面的數字為序號,只是為了方便查看,無其它意義),兩者的結果與X0進行「或」,電路塊的或為ORB。
Step4:看到的是第3部分,為常開觸點X2,與前者關係為+,故為OR X2。
Step5:看到的是第4部分,為輔助寄存器M0,與前者的關係為「*」,故為AND M0。
Step6:最後看到的是第5部分,為線圈Y0,關係為*,故直接輸出OUT Y0。
圖7給出了梯形圖與其轉換的代碼。
梯形圖向指令錶轉換完畢,即可獲得了1個邏輯表達式。利用該邏輯表達式,實現了指令表的編譯。針對圖4所示的梯形圖及其轉換過程,對應的邏輯表達式為:
4 組態元件
組態元件用於構建用戶與PLC進行交互的UI界面。常見的有輸入元件,例如按鈕或者輸入框,還有顯示元件,用於顯示PLC某些編程元件的值。
圖7是仿真軟體的組態輸入與輸出元件,其中「外接觸點開關」、「外接自鎖開關」,「輸出點」是輸入元件,用於顯示PLC的輸入繼電器的狀態和輸出繼電器的狀態。
最下面是兩個連接到輸入繼電器X5,X6的自鎖按鈕, 和連接到輸入繼電器X0,X1的點動按鈕。
圖中還可以看到,自鎖開關按下去後,輸出繼電器X5保持導通;而點動開關X1按下去後X1導通,但鬆手後X1不導通。
在C#中,組態元件被定義成一組自定義控制項,它編制完成後做為一組控制項可以被放置於Form窗體中,並且設置其特定的屬性。例如上面的按鈕組態元件,可以設定關聯到那個輸入繼電器。
所有的組態組件擁有共同的基類ScadaClass, 它們有公用屬性:圖片地址,組件名稱,通訊用的命名管道。
class ScadaClass : Panel
{
public readonly string partImagePath = "c:\\partImg";
public string partName { get; set; }
public static NamedPipeClientStream pipeClient =
new NamedPipeClientStream("127.0.0.1", "scadaPipe",
PipeDirection.InOut, PipeOptions.Asynchronous,
TokenImpersonationLevel.None);
}
下面是定義輸入組件的基類,所有的具體類型的按鈕都以此為基類。
class ScadaButton : ScadaClass
{
private string eleName;
private ushort eleNo;
private bool onOff;
private bool isSelfLock;
private string imageOnFilePath;
private string imageOffFilePath;
public TextBox tbMsg = new TextBox();
public ScadaButton()
{
this.Controls.Add(tbMsg);
tbMsg.TextChanged += new EventHandler(tbMsg_TextChanged);
EleName = "X";
OnOff = false;
}
void tbMsg_TextChanged(object sender, EventArgs e)
{
var txt = ((TextBox)sender).Text;
if (txt != null && txt.Length > 1)
{
var res = txt.splitNameAndValue();
EleName = res.Item1;
EleNo = (ushort)res.Item2;
}
}
protected override void OnPaint(PaintEventArgs e)
{
tbMsg.Width = 40;
tbMsg.Text = EleName + EleNo;
base.OnPaint(e);
}
public ushort EleNo
{
get { return eleNo; }
set { eleNo = value; }
}
public string EleName
{
get { return eleName; }
set { eleName = value; }
}
public bool OnOff
{
get { return onOff; }
set { onOff = value; }
}
public bool IsSelfLock
{
get { return isSelfLock; }
set { isSelfLock = value; }
}
public string ImageOnFilePath
{
get { return imageOnFilePath; }
set { imageOnFilePath = value; }
}
public string ImageOffFilePath
{
get { return imageOffFilePath; }
set { imageOffFilePath = value; }
}
}
下圖展示了組態組件中一個觸點開關與一個自鎖開關按下時的效果。
5 虛擬仿真實驗
本系統利用上述各模塊的功能,為PLC的實驗教學提供了一個直觀、形象的虛擬環境。使用該系統進行實驗的步驟如下:
1) 根據給定的控制要求,在該仿真軟體平臺上繪製梯形圖;
2) 生成對就原指令表,然後點擊「開始仿真」。
3) 根據屏幕顯示的結果進行調試和修改PLC程序,返回1。
這裡選用交通燈控制實例來進行仿真實驗,用於檢驗虛擬PLC仿真軟體的運行效果。
控制要求為:
(1) 按輸入信號開始執行程序。
(2) 按每十秒鐘切換一組信號燈顯示,紅(y0),綠(y1),藍(y2),循環執行。
按照上述要求,編制的梯形圖與其生成的指令表以及運行結果如圖9所示。
下圖是梯形圖生成的指令表。
圖10 指令表
下圖是本實驗的梯形圖代碼。
圖12 程序用到資源的實時監控
下圖是組態元件的顯示結果,從中我們看到紅燈(Y0)正在被點亮;十秒鐘後綠燈(Y1)將被點亮,接下來是藍燈(Y2)將被點亮;程序會不斷循環這個過程。
6 結論
本文利用C#開發了一個仿三菱系列PLC的虛擬仿真軟體,並構建了虛擬實驗環境,主要討論了梯形圖繪製和梯形圖轉換為指令表2個關鍵的技術問題。針對交通燈控制的仿真實驗表明,該仿真軟體可以直觀的用於PLC的實驗與教學。本軟體對於想入門PLC的初學者是非常適用的。
進一步,可以在該平臺的基礎上,增加3D虛擬實驗環境;或者是增加對應的硬體通訊與IO接口,用於控制實際的實驗對象。
參考文獻
[1]袁雲龍,基於組態軟體的PLC控制系統仿真實驗[J] 自動化儀表,2006,27(5):57-58,61.
[2] 李傑臣,劉瓊.PLC軟體仿真技術在教學中的應用[J].成都航空職業技術學院學報,2006,22(1);25-27.
-
作者:hackpig
來源:www.skcircle.com
版權聲明:本文為博主原創文章,轉載請附上博文連結!