歡迎進(jìn)入上海茂碩機(jī)械設(shè)備有限公司網(wǎng)站!
經(jīng)常有人問(wèn),這個(gè)PLC有沒有某某指令,或者,有沒有指令可以實(shí)現(xiàn)這樣那樣的功能?
產(chǎn)生這樣的疑問(wèn),部分原因是不熟悉這款PLC的指令。部分原因是為了選型,想找到一種PLC能夠內(nèi)置一些功能,使得自己的編程得到簡(jiǎn)化。
甚至有一些人認(rèn)為,PLC沒有這個(gè)指令就是沒有這個(gè)功能,不能完成某個(gè)任務(wù)。如果指令能自己做,那就沒有這個(gè)問(wèn)題了。那我們就試著自己做自己需要的指令。
本系列文章圍繞S7-200 SMART PLC為中心,分為三篇講解如何編寫自己需要的指令,編程語(yǔ)言主要以梯形圖的方式為主。
注意:前方高能!超長(zhǎng)文章,請(qǐng)大家拿著奶茶慢慢看~
梯形圖的所有指令一般遵循掃描原則進(jìn)行執(zhí)行。執(zhí)行一個(gè)完整的程序,過(guò)程中由于掃描有先后次序,所以必然在一個(gè)瞬間只能執(zhí)行一個(gè)指令。那么當(dāng)掃描到程序中間的時(shí)候,程序前部分的程序先獲得掃描并執(zhí)行過(guò),執(zhí)行的結(jié)果將已經(jīng)產(chǎn)生影響。后面部分的程序未曾執(zhí)行,將來(lái)的執(zhí)行當(dāng)中所有條件將以新的形態(tài)執(zhí)行。
從I0.0 = False(0)之后的某個(gè)掃描周期開始看看掃描的過(guò)程。此時(shí),所有變量都沒有接通。
當(dāng)有一個(gè)掃描周期I0.0 = True(1)的時(shí)候,并且方框處的程序剛剛處理完的時(shí)刻,1段的Q0.0顯然跟以前的掃描一樣,不接通。而此時(shí)此刻的M0.0已經(jīng)接通,它將開始影響以后程序的執(zhí)行。然后在這個(gè)掃描周期結(jié)束的時(shí)候Q0.1將接通了,但是Q0.0卻沒有接通。
下一個(gè)周期開始,掃描一個(gè)M0.0觸點(diǎn)的時(shí)候,此時(shí)的M0.0才開始影響一行程序。
所以,掃描到并執(zhí)行出的結(jié)果是影響往后的所有掃描的。并沒有掃描周期之分。所有執(zhí)行都基于掃描。
一行程序最左邊粗實(shí)線是能流的源,這里永遠(yuǎn)是True(1)。通過(guò)各種觸點(diǎn)的True(1)與False(0)組合,能流能到達(dá)右側(cè)的線圈指令的話,就可以使線圈置位(1)。能流不能到達(dá)右側(cè)線圈的話線圈就復(fù)位(0)。能掃描到的指令,基本能按照這種意愿執(zhí)行。
要正確理解能流True(1)與False(0)兩種狀態(tài)對(duì)程序的影響,如圖2所示。
圖2程序
當(dāng)I0.0 = True(1)的時(shí)候,兩個(gè)指令都得到了能流。計(jì)時(shí)器指令按照自己的屬性進(jìn)行計(jì)時(shí)。傳送指令把源地址數(shù)據(jù)傳送到目的地址,無(wú)論目的地址原來(lái)有什么值都執(zhí)行傳送更新目的地址。
當(dāng)I0.0 = False(0)的時(shí)候,兩個(gè)指令都沒有了能流。計(jì)時(shí)器在沒有能流的時(shí)候把當(dāng)前值寫成0,把計(jì)時(shí)器位寫成False(0)。值得注意的是,這個(gè)指令在False(0)的時(shí)候不是什么都不做的,而是在做False(0)時(shí)應(yīng)該做的事情。有這樣特點(diǎn)的指令還有輸出線圈指令等。傳送指令在沒有能流的時(shí)候不再傳送,不再理會(huì)目的地址。大量位于能流最右側(cè)的指令都有這個(gè)特點(diǎn)。
不追究這個(gè)詞的歷史背景了。反正大家都知道在一個(gè)程序里面對(duì)同一個(gè)線圈出現(xiàn)過(guò)兩次輸出線圈就是雙線圈。
雙線圈不會(huì)當(dāng)作是一種錯(cuò)誤程序。它可以按照程序的行為作出解釋。也就是說(shuō)它沒有語(yǔ)法錯(cuò)誤,但是可能會(huì)導(dǎo)致邏輯執(zhí)行錯(cuò)誤。
如圖3所示的例子,可能作者希望自動(dòng)動(dòng)作時(shí)的三個(gè)步驟Q0.0得電。而且切換到點(diǎn)動(dòng)的時(shí)候又可以控制Q0.0。結(jié)果,由于出現(xiàn)了雙線圈,影響了期望的動(dòng)作。這是雙線圈的錯(cuò)誤使用。
圖3程序
對(duì)于輸出點(diǎn)Q,總是按照一個(gè)周期中一個(gè)輸出指令刷新輸出到物理點(diǎn)的。
下面舉一個(gè)案例,看看怎么處理比較好?
有一個(gè)輸出點(diǎn),根據(jù)工藝已經(jīng)做好了程序并且調(diào)試成功。程序片段如圖4所示。
圖4程序
突然甲方來(lái)了一個(gè)要求,要求Q0.0在原來(lái)的基礎(chǔ)上并聯(lián)一個(gè)現(xiàn)場(chǎng)按鈕,無(wú)論Q0.0是否動(dòng)作,現(xiàn)場(chǎng)按鈕按下時(shí),Q0.0都要為True(1)。現(xiàn)場(chǎng)按鈕松開時(shí),不影響原來(lái)的程序作用。同時(shí)要求,Q0.1不受現(xiàn)場(chǎng)按鈕影響。于是如圖5所示做了如下修改。
圖5程序
Ok!程序沒有問(wèn)題。要是改成如圖6所示的程序,結(jié)果會(huì)怎樣?同樣,這個(gè)程序也可以完成上述任務(wù)。
圖6程序
這是一個(gè)雙線圈的程序。第二個(gè)輸出線圈由于帶有一個(gè)線圈的執(zhí)行結(jié)果,觸點(diǎn)先繼承了前面所有的邏輯,在此邏輯下增加了一個(gè)現(xiàn)場(chǎng)按鈕。解決了Q0.0的需求,但是又沒有對(duì)Q0.1有任何的影響。程序卻非常簡(jiǎn)單。
再看一個(gè)雙線圈使用的例子。如圖7所示:
圖7程序
先看網(wǎng)絡(luò)1 2 3?!皥?bào)警"和“運(yùn)行中"兩個(gè)信號(hào)由于有公共相似的邏輯,所以用一個(gè)線圈把公共部分記錄下來(lái),再在下面的程序多次使用這樣的公共部分。為了使程序簡(jiǎn)單一點(diǎn),不用在報(bào)警和運(yùn)行的線圈前都把相同的公共部分重復(fù)寫一次。然而,網(wǎng)絡(luò)4才是Q輸出點(diǎn)最終要達(dá)成的控制邏輯目的。Q只是在前面的工作中臨時(shí)客串,義務(wù)送了一個(gè)人情。臨時(shí)變量的影子也悄悄地在這個(gè)例子中流露出來(lái)。
多重賦值是說(shuō)明一個(gè)地址,在程序多個(gè)地方都有出現(xiàn)對(duì)其寫入的操作。雙線圈是一種典型的多重賦值。執(zhí)行寫入的主動(dòng)操作者可以是用戶程序,可以是系統(tǒng)行為,可以是來(lái)自通訊端口改寫。還可以是其他。
在早先一些PLC還不允許出現(xiàn)雙線圈的時(shí)代,要繞過(guò)雙線圈的規(guī)則,有這樣的一種方法。程序開頭對(duì)線圈復(fù)位。后面的自動(dòng)程序需要什么步驟輸出線圈,就用置位指令代替線圈指令。最終掃描結(jié)束輸出物理信號(hào)的時(shí)候取決于是否對(duì)線圈置位,如圖8所示,程序在“步1"、“步2"、“步7",這三個(gè)步驟時(shí)輸出。
圖8程序
如圖8這樣的程序結(jié)構(gòu),在多個(gè)地方都出現(xiàn)對(duì)Q0.0寫入值。當(dāng)然這樣各種的值都是不同的,相同的話就不必多重了。我們應(yīng)該小心處理邏輯關(guān)系,避免出現(xiàn)不希望的值。
再看一個(gè)例子,如圖9所示:
圖9程序
程序中把輸入量傳給輸出量。但是當(dāng)發(fā)現(xiàn)輸出量是負(fù)數(shù)的時(shí)候,把0傳給輸出量。也就是說(shuō)限制輸出量最小值是0,不可以再小了。
雙線圈和多重賦值都是自定義庫(kù)程序范圍中一個(gè)非常重要的思想。不能很好理解這兩個(gè)概念,將會(huì)對(duì)制作庫(kù)程序產(chǎn)生很大的障礙。
在操作數(shù)引腳(實(shí)參)上直接使用常數(shù)、地址、符號(hào)這三種方式是編程中使用最多寫法。另外,還有符號(hào)定義的常量和間接尋址兩種方式相對(duì)比較少去使用。如圖10所示:
圖10程序
間接尋址包括制作指針和使用指針。
指針是指向目的區(qū)域目的地址的標(biāo)記。目前,CPU除了AC、HC、L區(qū)不能作為目的區(qū)域其他區(qū)域都可以間接尋址。
在后面的文章中,都只將V區(qū)作為間接尋址的目的地址做說(shuō)明或者做例子。這并不表示不能尋址到其余區(qū)域。
例子中的 "T40" 的設(shè)定值填寫的是一個(gè)間接尋址。意思就是說(shuō)這個(gè)位置雖然不是一個(gè)具體的設(shè)定時(shí)間,但是,具體的值位于這個(gè)指針?biāo)傅牡胤?。而這個(gè)地方當(dāng)時(shí)是什么值,那么計(jì)時(shí)器的設(shè)定值就是什么值。
簡(jiǎn)單講就是“你要的東西用紙(址)包著"和“你要的東西用紙(址)寫著"。
現(xiàn)在就圍繞這句話,聊一聊間接尋址。
首先說(shuō)說(shuō)這張包東西的紙(址),不是什么地方都可以做的。什么材料可以做這張紙?材料可以是全部V區(qū)、全部L區(qū)、AC區(qū)的AC1 AC2 AC3可以裝載指針。并且只能用連續(xù)的4個(gè)字節(jié)組成的雙字裝載指針。起始地址不介意是奇數(shù)還是偶數(shù)。
要用紙包著東西,必須把東西放進(jìn)去紙里面。MOVW 100 VW0 這里 "100" 就是東西, "VW0" 就是一張紙。小的東西就用一張紙包(一個(gè)字節(jié)),很大的東西就用四張紙拼成一張大紙包(一個(gè)雙字)。用這件東西的人只要找到這張紙直接就得到里面的東西。
你要的東西用紙寫著,那就是說(shuō)事前必然有人在紙上已經(jīng)寫了字,后面才能有人看見。MOVD &VB400 VD4 。這里 "VB400" 就是寫在上面的字,"&" 符號(hào)是說(shuō)明寫著這幾個(gè)字是一個(gè)地址,不是普普通通的字。"VD4" 就是一張大紙。這就是制作指針。
手里拿著這張紙后,自然要根據(jù)這張紙的指引做一些事。如圖10程序一行指令。執(zhí)行一個(gè)計(jì)時(shí)器指令時(shí)使用了" *VD2" 這張紙 ……,如果只寫 "VD2",那么就好像是使用 "VD2" 的值作為計(jì)時(shí)器設(shè)定值,但是事實(shí)并非如此。這里 "VD2" 前面帶*號(hào)。星號(hào)表示 "VD2" 里面的值是指引真正包含設(shè)定值的地址。由于 "VD2" 里面先前一個(gè)指令寫入了 "&VB0" ,所以這張紙其實(shí)是指引計(jì)時(shí)器到 "VW0" 找尋設(shè)定值。這就是使用指針。當(dāng)然這是因?yàn)槭窃诙〞r(shí)器的時(shí)間設(shè)置用到指針,而這個(gè)設(shè)置變量的類型是字。而如果在MOVB輸入用到相同指針 "VD2",那么輸入的就是 "VB0" 而不是 "VW0" 了,因?yàn)镸OVB指令需要的輸入變量的是字節(jié),也就是指針保存的是起始地址,具體使用的變量取決于指令需要。
使用間接尋址的好處在于通過(guò)計(jì)算改變指針的值,可以尋址到附近的任何地址。當(dāng)指針指向VB10的時(shí)候,把指針增加10,那么指針就會(huì)指向VB20。尋址就改變到VB20。指針再減少3,那么尋址就會(huì)找到VB17。對(duì)于一片連續(xù)的V空間只要知道一個(gè)地址,就可以尋址到連續(xù)的第n個(gè)地址。
在以后的子程序使用中將會(huì)非常多地用到間接尋址的。
子程序是整個(gè)程序的一個(gè)片段。根據(jù)編程者的需求,把一部分程序歸入到一個(gè)子程序里面,完成相關(guān)的功能。整個(gè)子程序可以根據(jù)用戶程序的邏輯選擇調(diào)用或者不調(diào)用。調(diào)用的話就按照掃描次序掃描一次子程序,然后回到調(diào)用處。不調(diào)用的話就等于程序沒有了這部分片段。在其他地方再次出現(xiàn)調(diào)用這個(gè)子程序的話,子程序又得到一次運(yùn)行。PLC并沒有限制用戶調(diào)用子程序的次數(shù),只不過(guò)調(diào)用一次就要增加一點(diǎn)掃描時(shí)間。必要時(shí)候就調(diào)用,沒必要的時(shí)候調(diào)用了也不產(chǎn)生什么效益。
偶爾會(huì)看見有人在問(wèn):有幾個(gè)數(shù)據(jù)需要求平均值。PLC有沒有求平均的指令???
不好意思,200 SMART PLC沒有計(jì)算平均指令。還是好好地編程寫吧。
下面我試試用兩種方式的子程序完成這個(gè)多個(gè)值的累加。至于除法求平均就不介紹了?,F(xiàn)以4個(gè)字變量計(jì)算總和為例介紹。
程序要求:VW0、VW2、VW4、VW6四個(gè)值求和,結(jié)果放在VW100中。
看看先用比較簡(jiǎn)單的方法,先完成要求的功能,如圖1所示:
圖1程序
在子程序里面就是幾個(gè)很簡(jiǎn)單的加法指令。而在主程序調(diào)用子程序的前后,加上了一些簡(jiǎn)單的傳送指令。
先看子程序。子程序中三個(gè)加法指令把四個(gè)MW累加到MW8中。前面四個(gè)MW中并沒有什么值。累加之后的結(jié)果MW8也沒有什么實(shí)際意義。
再看主程序。題目要求的四個(gè)已知值,在調(diào)用子程序之前就傳到了子程序使用的MW地址。此時(shí)調(diào)用子程序,這些MW就有了值。經(jīng)過(guò)子程序的運(yùn)算,結(jié)果就放置在MW8。然后回到調(diào)用處,再把子程序的值傳到題目要求的地方,完成題目的要求。
在這個(gè)例子中,主程序的這個(gè)網(wǎng)絡(luò)可以多次使用。在需要的地方就按照上面例子的方法使用子程序就可以再次實(shí)現(xiàn)求和的作用。子程序只是作為一個(gè)計(jì)算法則,而這個(gè)法則又是很簡(jiǎn)單的幾個(gè)計(jì)算。當(dāng)遇到比較復(fù)雜的算法的時(shí)候,并且又有機(jī)會(huì)多次調(diào)用。不妨可以試試這個(gè)程序結(jié)構(gòu)。這個(gè)結(jié)構(gòu)有一個(gè)優(yōu)勢(shì),就是任何品牌的PLC都可以互通。哪怕就是20年前的PLC也一樣可以用這個(gè)方法。不過(guò)當(dāng)今的200 SMART PLC顯然不推薦使用這樣的方式了。這個(gè)方式的編程,只是用于說(shuō)明帶參數(shù)子程序的一部分參數(shù)傳遞原理,將在日后詳細(xì)介紹。
1.調(diào)用子程序的前后,需要把參數(shù)傳送到的地址,供子程序使用。
這些地址成為了這一個(gè)子程序的專用地址;每次調(diào)用子程序都要做這個(gè)事情。
2.子程序占用了公共資源;
當(dāng)一個(gè)程序有很多個(gè)子程序的時(shí)候,消耗在這兩方面的工作和資源就會(huì)很多。當(dāng)一個(gè)子程序工作需要很多個(gè)參數(shù)的時(shí)候,要寫很多MOV指令,也要占用很多公共資源M地址。對(duì)于200 SMART PLC,M區(qū)只有32個(gè)字節(jié),如果需要32字節(jié)以上的區(qū)域,那就只能在比較大的V區(qū)找地方了。而當(dāng)子程序很多,或者子程序是不同編程者的話,就可能會(huì)有不同子程序使用到了相同的區(qū)域。這樣必然需要修改一些地址,使地址不發(fā)生重復(fù)。
假如有辦法解決上述兩個(gè)問(wèn)題,將是一個(gè)非常美滿的結(jié)果。辦法是有的。先不說(shuō)這個(gè)。
現(xiàn)在,再用現(xiàn)在的方式寫一個(gè)子程序完成求和的功能。四個(gè)步驟就可以創(chuàng)建一個(gè)帶參數(shù)的子程序。
步驟一:
新建一個(gè)子程序。在子程序?qū)傩岳锩婢幒米映绦蛎Q和塊編號(hào)(子程序號(hào)),如圖2所示。這里要求不嚴(yán)格,主要是編程者自己容易分辨就好。當(dāng)然如果是要做成庫(kù),把塊編號(hào)設(shè)置大些,以便于調(diào)用時(shí)不會(huì)沖突。
圖2 設(shè)置塊屬性
第二步:
如圖3所示,打開變量表。
圖3 變量表
第三步:
向變量表填入需要的輸入輸出參數(shù),如圖4所示。
圖4 設(shè)置參數(shù)
變量表的各個(gè)列的意思是:
地址:變量對(duì)應(yīng)L區(qū)的地址。這個(gè)地址由系統(tǒng)分配,不能由編程者輸入。每增加一個(gè)變量或者插入一行,地址自動(dòng)改變。并且如果編程當(dāng)前正在用符號(hào)名編程的時(shí)候,增刪行導(dǎo)致的地址變更,不會(huì)影響編程關(guān)系。相反,如果正在用地址編程,而你又增刪過(guò)行,那么程序地址將會(huì)混亂。
符號(hào):這個(gè)是變量的名字。如果正在用地址編程的時(shí)候,此時(shí)修改名字,不會(huì)影響已寫好的程序。相反,如果正在用符號(hào)編程,此時(shí)修改名字,那么程序符號(hào)立即紅色報(bào)錯(cuò),程序已找不到這個(gè)名字了。
變量類型:無(wú)法修改。輸入?yún)?shù)填寫在IN行。輸入/輸出參數(shù)填寫在IN_OUT行。輸出參數(shù)填寫在OUT行。臨時(shí)變量在最后TEMP。填寫完畢會(huì)自動(dòng)增加新行。
IN類型表示子程序運(yùn)行的數(shù)據(jù)來(lái)源,就像上述例子的4個(gè)加數(shù)。
OUT類型表示經(jīng)過(guò)子程序的運(yùn)算,得到的結(jié)果。輸出在這個(gè)位置。
IN/OUT類型,組合兩種類型,先輸入給子程序再運(yùn)算得到結(jié)果輸出到相同的位置。
TEMP類型,這個(gè)類型既不輸入也不輸出,僅僅在子程序中充當(dāng)過(guò)渡用的中間變量。
數(shù)據(jù)類型:這個(gè)參數(shù)是一個(gè)點(diǎn)位還是一個(gè)字節(jié)還是一個(gè)浮點(diǎn)數(shù)等等的性質(zhì)。這個(gè)下拉選擇將會(huì)影響地址欄的分配跨度。因?yàn)椴煌念愋驼加貌煌奈婚L(zhǎng)。
注釋:給自己看的一些關(guān)于本行變量的備忘信息。
到此,一個(gè)帶參數(shù)的子程序就已經(jīng)完成了。雖然并沒開始編寫子程序的內(nèi)容,但是你已經(jīng)可以觀察一下由主程序調(diào)用這個(gè)子程序的樣子。如圖5所示。
圖5 子程序調(diào)用
網(wǎng)絡(luò)1是當(dāng)子程序沒有填寫變量表的時(shí)候的樣子,它不帶任何參數(shù)。網(wǎng)絡(luò)2是剛才建立了變量表的求和子程序。此時(shí)的子程序未確定任何實(shí)質(zhì)性的參數(shù)地址。點(diǎn)擊每個(gè)問(wèn)號(hào)地方,按照題目要求左側(cè)輸入VW0;VW2;VW4;VW6,右側(cè)輸入VW100,調(diào)用基本就完成了。
子程序輸入輸出參數(shù)的排序會(huì)按照你剛才填寫變量表的先后順序布置。在實(shí)際程序中,你在向子程序編程之前先確認(rèn)一下這個(gè)外觀效果,每一個(gè)輸入輸出參數(shù)是否能夠按照使用的習(xí)慣排列所有參數(shù)。例如我們表達(dá)一個(gè)長(zhǎng)方體的尺寸的時(shí)候通常都說(shuō)“長(zhǎng)寬高",沒有人會(huì)說(shuō)“高長(zhǎng)寬"的次序的。這個(gè)就是習(xí)慣。當(dāng)參數(shù)很多的時(shí)候,盡量按照有關(guān)習(xí)慣填寫變量表的順序。可以用插入刪除行的方法編輯次序。
第四步:對(duì)子程序編程
子程序內(nèi)的加法過(guò)程的編程在此就省略了。其實(shí)就是圖1的子程序。只不過(guò)是將全部的MW改寫成LW就可以了。
好了,一個(gè)帶參數(shù)的子程序就完整建立完畢了。它將會(huì)出現(xiàn)在指令樹里面項(xiàng)目的程序塊里面。它因?yàn)楸旧砭褪且粋€(gè)子程序,所以也是顯示為一個(gè)子程序。
后面的內(nèi)容更精彩??赡懿皇悄阆胂蟮哪腔厥屡秪
一份程序中建立多個(gè)子程序,每個(gè)子程序完成相對(duì)比較獨(dú)立的功能。而子程序也是圍繞主程序的要求,并且還根據(jù)主程序給出的條件完成這個(gè)要求。此時(shí)主程序和子程序之間或者說(shuō)子程序和它下級(jí)的子程序之間,就必然有一些數(shù)據(jù)的交流。下面將介紹一下這種參數(shù)的傳遞。
再提一下變量表,子程序里面的變量表,這是最重要的上下級(jí)程序之間數(shù)據(jù)傳遞的方式,但不是的方式。主程序把將要給子程序的數(shù)值擺放在一個(gè)或一片約定的全局地址,然后子程序讀取這些全局的地址……這種做法作為傳遞參數(shù),簡(jiǎn)單不過(guò)。但是,這里不討論這樣的傳遞方式。
現(xiàn)在隨便做一個(gè)子程序,觀察一下在主程序中調(diào)用時(shí)候的外觀。
圖1
圖2
如圖1所示是在主程序里面調(diào)用SBR_0的情況,還有一個(gè)常見的計(jì)數(shù)器指令。如圖2所示是SBR_0中變量表所填入的變量設(shè)置。
圖1中一個(gè)標(biāo)注SBR_0的指令塊跟計(jì)數(shù)器指令外觀很相似。但是各自的接口和參數(shù)都不同。它們都有觸點(diǎn)接口和數(shù)據(jù)接口?,F(xiàn)在看看子程序的調(diào)用,主程序通過(guò)什么渠道把參數(shù)傳遞到子程序。
SBR_0左邊上方開始有兩個(gè)連接著開關(guān)觸點(diǎn)的接口。
【EN】有能流表示執(zhí)行這個(gè)子程序。沒有能流的話將從子程序門口經(jīng)過(guò),不進(jìn)入子程序。一個(gè)子程序就算沒有任何參數(shù)都會(huì)有這個(gè)接口的。
【點(diǎn)輸入1】下邊也是一個(gè)能流型的接口,表示這里有一個(gè)開關(guān)量的能流輸入。
當(dāng)鼠標(biāo)指向這個(gè)指令塊的時(shí)候,會(huì)彈出一個(gè)框,如圖3所示。這里說(shuō)明了所有參數(shù)的變量類型(in;in/out;out)和數(shù)據(jù)類型(b;B;W;D)。
圖 3
【字輸入】從彈框得知這是一個(gè)字型的輸入?yún)?shù)。這里接口必須填寫一個(gè)字型的變量或者常數(shù)。
【點(diǎn)輸入2】這也是一個(gè)布爾量的輸入?yún)?shù),但是因?yàn)橛衅溆囝愋偷膮?shù)分割,導(dǎo)致沒有從開始處連續(xù)排列布爾量的輸入?yún)?shù),所以這個(gè)布爾量輸入也顯示為數(shù)據(jù)接口形式。
【字節(jié)入出】從彈框得知這是一個(gè)輸入輸出雙向的參數(shù),需要填入一個(gè)字節(jié)型的變量。
【字輸出】這個(gè)參數(shù)在右側(cè),位置上已經(jīng)表明這是一個(gè)輸出型的參數(shù)。
綜上所述,輸入型的參數(shù)將安排在左側(cè)的最上方,并且如果上方有連續(xù)的開關(guān)量,都會(huì)以能流的形式連接這個(gè)參數(shù)。接下來(lái)是數(shù)據(jù)型的輸入?yún)?shù)接口。然后下方是雙向的參數(shù)接口。右邊一律是數(shù)據(jù)接口形式連接所有輸出參數(shù)。
上級(jí)程序就是通過(guò)這樣的接口把子程序所需的參數(shù)傳入到子程序的,再進(jìn)入到子程序里面。接下來(lái)看看子程序方面,得到的參數(shù)將會(huì)是如何出現(xiàn)的。
觀察上面圖2這個(gè)變量表。自從建立了這個(gè)變量表開始,子程序里面的L地址的前面部分就已經(jīng)成為了子程序參數(shù)的載體。L地址從個(gè)字節(jié)開始,往后安排IN參數(shù);IN/OUT參數(shù);OUT參數(shù)。按照字節(jié)為最小占用單位來(lái)安排能流接口的參數(shù),從L0.0開始向更高位連續(xù)安排,EN不占用地址。對(duì)于布爾量,一個(gè)布爾量點(diǎn)占用整個(gè)字節(jié),八個(gè)以內(nèi)的連續(xù)布爾量點(diǎn)也占用一個(gè)字節(jié)。下一個(gè)非布爾量參數(shù)或者不同類型變量(IN、IN/OUT、OUT)從下一個(gè)字節(jié)開始安排。所以【點(diǎn)輸入1】參數(shù)分配到L0.0,【字輸入】參數(shù)分配到LW1?!咀止?jié)入出】參數(shù)分配到LB4。然后子程序使用上級(jí)傳遞的參數(shù)就只要讀取這些L地址就可以得到。
外面的情況了解了,里面的情況也了解了,參數(shù)傳遞……沒說(shuō)完,還有最不為人知的一部分。
——中間的過(guò)程。
中間過(guò)程就像一份快遞的工作,在上級(jí)下級(jí)程序之間搬運(yùn)數(shù)據(jù)。只要子程序被調(diào)用,那么快遞就會(huì)把的數(shù)據(jù)傳送到子程序內(nèi)。子程序結(jié)束后,快遞又會(huì)把的參數(shù)傳送到上級(jí)程序的接口。要是沒有接口參數(shù)自然沒有這個(gè)崗位。
作為用戶程序,只要上級(jí)程序把參數(shù)放置到位,又在子程序里面存取對(duì)應(yīng)的L地址,中間怎么從上級(jí)傳達(dá)到下級(jí)是無(wú)需做任何事情的。這個(gè)過(guò)程由系統(tǒng)代勞了。但不等于不用理解這個(gè)過(guò)程。你不知道的事情可能恰恰就在這里。做以下的程序?qū)嶒?yàn)一下。
圖4
建立三個(gè)子程序,各自就只有變量表填寫了一行參數(shù),如圖4所示。子程序里面無(wú)任何用戶程序。主程序編輯這樣的調(diào)用邏輯。把程序下載到PLC,看看執(zhí)行會(huì)怎樣?
PLC運(yùn)行后,由于程序存在QB0和M0.0,沒有任何用到的其他地址了,所以我們的焦點(diǎn)就關(guān)注著這兩個(gè)地方,而QB0更是最容易看見。此時(shí)輸出點(diǎn)還是熄滅的。用狀態(tài)表把M0.0寫入1,與此同時(shí)QB0也顯示2#10010000(注意硬件的燈高位在右側(cè),書寫二進(jìn)制高位在左側(cè)。)然后把M0.0寫入0,此時(shí)QB0變成顯示2#11001100。我們?cè)俅伟袽0.0寫入1之后QB0再次顯示2#10010000 。
為什么輸出點(diǎn)會(huì)有這樣的三種狀態(tài)呢?用戶程序沒有對(duì)輸出點(diǎn)做過(guò)邏輯和賦值,而子程序里面也沒有任何程序。能夠有動(dòng)作的只能是系統(tǒng)的動(dòng)作了。究竟會(huì)是什么時(shí)候使輸出點(diǎn)得到了一些值?程序里面跟QB0有點(diǎn)關(guān)系的就是SBR2子程序了。為什么SBR0、SBR1兩個(gè)子程序的值會(huì)到了SBR2子程序里面去的?那么就要理一理參數(shù)傳遞的中間過(guò)程了。
運(yùn)行初期,網(wǎng)絡(luò)1不接通,網(wǎng)絡(luò)2沒產(chǎn)生邊沿信號(hào)。前兩個(gè)子程序都沒有調(diào)用。第三個(gè)子程序SBR2一直在調(diào)用。
接通M0.0,SBR0得到了執(zhí)行。在進(jìn)入子程序后,運(yùn)行子程序用戶指令之前,系統(tǒng)把引腳上的IN參數(shù)值復(fù)制到了LB0。然后執(zhí)行子程序的用戶程序,由于沒有程序可運(yùn)行,退出了子程序。
網(wǎng)絡(luò)2沒有執(zhí)行子程序。網(wǎng)絡(luò)3一直在執(zhí)行。SBR2子程序沒有輸入?yún)?shù),沒有子程序內(nèi)容,離開子程序之前,系統(tǒng)必須要給一個(gè)值到輸出參數(shù)。系統(tǒng)的這個(gè)動(dòng)作不會(huì)因?yàn)槌绦蛑杏袥]有內(nèi)容或者說(shuō)程序執(zhí)行的怎么樣,而不去做這個(gè)傳送,它是必然會(huì)做這個(gè)動(dòng)作的。那么這個(gè)時(shí)候,LB0到底是一個(gè)什么值呢?我們就要追溯到這個(gè)LB0最后賦值的是什么地方。之前由于執(zhí)行SBR0輸入?yún)?shù)使LB0曾經(jīng)有過(guò)2#10010000這個(gè)值。這個(gè)值由于遵從多重賦值的原因,這個(gè)值在當(dāng)時(shí)產(chǎn)生,一直擱置到現(xiàn)在,被SBR2撈上來(lái)了,然后就給了QB0。當(dāng)M0.0恢復(fù)到0時(shí),SBR1前的上升沿發(fā)生了,調(diào)用了一次。就這一次,把LB0寫入了2#11001100。在沒有什么地方再給LB0寫入值的情況下,LB0將不會(huì)改變。(當(dāng)一個(gè)子程序不調(diào)用的時(shí)候,并不會(huì)由此使得某些線圈、某些地址自動(dòng)復(fù)位為零,但是仍有不少的人有這樣的錯(cuò)覺。)大家也可以參考M0.0,編程軟件寫入了的值可以一直保持住的。你沒有去更改它,還有誰(shuí)去修改它?所以把一個(gè)值寫入到某地址之后,就可以一直保持住,SBR2也就可以輸出2#11001100這個(gè)值。
手冊(cè)并沒有說(shuō)明局部?jī)?chǔ)存區(qū)的值是從何而來(lái),手冊(cè)上面有一段話,如圖5所示。
圖 5
當(dāng)手冊(cè)沒有清楚說(shuō)明的情況下,我會(huì)假設(shè)一種較為合理的假設(shè),然后在日后的編程中一直證實(shí)這個(gè)假設(shè),并使用這種假設(shè),同時(shí)一直關(guān)注著這個(gè)問(wèn)題。假如一直使用都沒有明確顯示這種假設(shè)不成立,將認(rèn)為這是真的,繼續(xù)使用。我總覺得PLC只會(huì)按照有限的法則以固定的方法實(shí)施一些運(yùn)算。既然一個(gè)假設(shè)一直沒有被tf,那么這個(gè)假設(shè)可能永遠(yuǎn)也不會(huì)被tf。
15214375780