讀書(shū)的時(shí)候因?yàn)閷W(xué)的自動(dòng)化所以一直以為PLC是控制的王道,經(jīng)常鄙視樓下電子系搞單片機(jī)的,而且灰常2B的認(rèn)為單片機(jī)都TM弱電太嬌氣不耐艸玩單片機(jī)的都是吊絲!所以經(jīng);燠E于PLC實(shí)驗(yàn)室電子實(shí)驗(yàn)室居然只去了幾次,然而隨著對(duì)單片機(jī)和PC機(jī)的了解逐漸加深,越來(lái)越覺(jué)得自己當(dāng)年的自己太傻太天真了哎……
個(gè)人覺(jué)得PLC和單片機(jī)的關(guān)系就好比圖章和圓珠筆一樣,圖章操作簡(jiǎn)單傻子能蓋出漂亮的圖案但缺點(diǎn)也顯而易見(jiàn)靈活性太差了你不能用圖章蓋出一些復(fù)雜的圖案,圓珠筆就正好相反雖然操作難度大點(diǎn)但靈活性強(qiáng)了n個(gè)數(shù)量級(jí)。
既然單片機(jī)的靈活性那么強(qiáng)那么我們能用單片機(jī)來(lái)模擬PLC嗎,很明顯是可以的而且PLC的核心其實(shí)也是單片機(jī),那么該怎么模擬PLC呢?PLC分程序和硬件部分,硬件部分主要是做好外圍電路設(shè)計(jì),實(shí)現(xiàn)PLC的IO輸入輸出功能,一般用光耦做IO口電路設(shè)計(jì)提高單片機(jī)的抗干擾能力,做好穩(wěn)定的電源設(shè)計(jì),電源是可靠性的基礎(chǔ)。其實(shí)模擬PLC的關(guān)鍵再于程序部分,思路是寫(xiě)個(gè)編譯器把梯形圖編譯成 單片機(jī)能執(zhí)行的機(jī)器碼,但寫(xiě)編譯器工程太大了,我們只是模擬又不是造PLC所以不用考慮寫(xiě)那種直接把梯形圖編譯成機(jī)器碼的編譯器了,我們可以把編譯過(guò)程分解為梯形圖—>指令表—>C51代碼—>機(jī)器碼,這樣的話問(wèn)題就簡(jiǎn)單多了梯形圖轉(zhuǎn)指令表可以手工完成或者寫(xiě)個(gè)圖形編輯程序來(lái)完成但這不是重點(diǎn),指令表轉(zhuǎn)C51代碼才是模擬PLC的靈魂所在,雖然是個(gè)偽編譯器但每條指令的翻譯都是蛋疼的過(guò)程,我肯定是沒(méi)辦法把所有的三菱指令都模擬出來(lái)的,要完成這個(gè)任務(wù)還得認(rèn)真學(xué)學(xué)編譯原理啊……
這是PLC模擬程序的運(yùn)行截圖,對(duì)應(yīng)指令表的邏輯,發(fā)現(xiàn)運(yùn)行結(jié)果是正確的,雖然只完成了幾條最簡(jiǎn)單指令的翻譯而且與反指令還存在問(wèn)題但畢竟思路是正確的完成只是時(shí)間問(wèn)題了,太晚了不搞了果然比泥瑪搬磚還辛苦想問(wèn)題的時(shí)候根本睡不了……艾瑪
下面是我的模擬程序,因?yàn)橹粚?shí)現(xiàn)了幾條指令而且還并不完善所以編譯程序和PLC指令表程序混在一起的,但這只是個(gè)思路因?yàn)槲野l(fā)現(xiàn)有些指令按我的辦法基本不能實(shí)現(xiàn)但也算是個(gè)開(kāi)始后面再慢慢改進(jìn)吧,如果你想做一個(gè)更牛的可以去參考 http://www.torrancerestoration.com/mcu/1985.html 下面是模擬編譯的程序:
#include<reg52.h>
//指令表模擬
#define AND &&
#define ANI && !
#define LD if(
#define LDI if( !
#define OUT )
//輸入輸出指令模擬
#define X000 P1_0
#define Y000 P2_0=1; else P2_0=0;
#define X001 P1_1
#define Y001 P2_1=1; else P2_1=0;
#define X002 P1_2
#define Y002 P2_2=1; else P2_2=0;
#define X003 P1_3
#define Y003 P2_3=1; else P2_3=0;
#define X004 P1_4
#define Y004 P2_4=1; else P2_4=0;
#define X005 P1_5
#define Y005 P2_5=1; else P2_5=0;
#define X006 P1_6
#define Y006 P2_6=1; else P2_6=0;
#define X007 P1_7
#define Y007 P2_7=1; else P2_7=0;
//輸入輸出口資源定義
int P1_0,P2_0,P1_1,P2_1,P1_2,P2_2,P1_3,P2_3,P1_4,P2_4,P1_5,P2_5,P1_6,P2_6,P1_7,P2_7;
//初始化函數(shù)
void chushihua()
{
P1_0=0;
P2_0=0;
P1_1=0;
P2_1=0;
P1_2=0;
P2_2=0;
P1_3=0;
P2_3=0;
P1_4=0;
P2_4=0;
P1_5=0;
P2_5=0;
P1_6=0;
P2_6=0;
P1_7=0;
P2_7=0;
}
//顯示輸入輸出狀態(tài)
void shurushuchu()
{
printf("輸入輸出口狀態(tài)表\n");
printf("X0->%d X1->%d X2->%d X3->%d X4->%d X5->%d X6->%d X7->%d\n",P1_0,P1_1,P1_2,P1_3,P1_4,P1_5,P1_6,P1_7);
printf("Y0->%d Y1->%d Y2->%d Y3->%d Y4->%d Y5->%d Y6->%d Y7->%d\n\n",P2_0,P2_1,P2_2,P2_3,P2_4,P2_5,P2_6,P2_7);
}
//采集輸入狀態(tài)
void shuru()
{
printf("請(qǐng)更新輸入點(diǎn)狀態(tài)\n");
printf("X0<-");
scanf("%d",&P1_0);
printf("X1<-");
scanf("%d",&P1_1);
printf("X2<-");
scanf("%d",&P1_2);
printf("X3<-");
scanf("%d",&P1_3);
printf("X4<-");
scanf("%d",&P1_4);
printf("X5<-");
scanf("%d",&P1_5);
printf("X6<-");
scanf("%d",&P1_6);
printf("X7<-");
scanf("%d",&P1_7);
}
int main()
{
int x=0;
chushihua();
while(1)
{
shuru();
//進(jìn)入PLC指令表程序部分編譯器主體完工的話就能把這部分直接拿出來(lái)通過(guò)編譯器編譯了
LD X000
AND X002
ANI X001
OUT Y000
LD X003
AND X004
ANI X006
AND X007
OUT Y001
shurushuchu();
}
return 0;
}