2、發(fā)送子程序(Send)
在PLC接收到上位機(jī)的讀取數(shù)據(jù)命令后,調(diào)用發(fā)送程序?qū)⒅付ǖ臄?shù)據(jù)通過端口0發(fā)送給上位機(jī)。在PLC的存儲(chǔ)區(qū)中,從VB126到VB141為約定的數(shù)據(jù)存儲(chǔ)區(qū),VB125為發(fā)送的數(shù)據(jù)個(gè)數(shù)。發(fā)送完數(shù)據(jù)后,打開發(fā)送完成中斷。
//發(fā)送子程序
LD SM0.0
R SM87.7, 1
R M0.0, 1
RCV VB100, 0
MOVB 103, VB126
MOVB 16#01, VB127
MOVB 26, VB141
MOVB 16, VB125
LD SM0.0
FOR VW121, +1, +12
XORB *VD121, VB148
INCD VD181
NEXT
LD SM0.0
HTA VB148, VB140, 1
XMT VB125, 0
3、接收子程序(Recv)
LD SM0.0
R SM87.7, 1
R M0.0, 1
RCV VB100, 0
MOVB 21, VB125
MOVB 103, VB126
MOVB 16#02, VB127
MOVB 16, VB141
LD SM4.5
XMT VB125, 0
4、接收完成中斷(INT_0)
接收完成中斷用來處理接收完成中斷事件,它將接收緩沖區(qū)的數(shù)據(jù)還原并保存,同時(shí)將M0.1置位。
//接收完成中斷
LD SM0.0
ATH VB102, VB123, 1
ATH VB104, VB129, 1
ATH VB115, VB140, 1
S M0.1, 1
MOVB 0, VB147
MOVD &VB102, VD120
5、發(fā)送完成中斷(INT_1)
發(fā)送完成中斷用于處理發(fā)送完成中斷事件,主要是將M0.0復(fù)位、BCC碼寄存器清零、將接收緩沖區(qū)中存放結(jié)束字符的字節(jié)清零等。
//發(fā)送完成中斷
LD SM0.0
R M0.0, 1
S SM87.7, 1
MOVB 0, VB147
MOVB 0, VB148
MOVD &VB102, VD120
MOVB 0, VB100
6、BCC校驗(yàn)程序(Verify)
將接收到的數(shù)據(jù)進(jìn)行異或和校驗(yàn)。
LD SM0.0
R M0.1, 1
LD SM0.0
FOR VW143, +1, +12
LD SM0.0
XORB *VD121, VB147
LD SM0.0
INCD VD121
NEXT
LDB= VB147, VB119
AB= VB116, 71
S M0.0, 1
LDB= VB116, 71
AB<> VB147, VB119
MOVB 16, VB119
MOVB 16#03, VB125
R SM87.7, 1
RCV VB100, 0
XMT VB125, 0
LDB<> VB116, 71
MOVB 16, VB125
MOVB 16#04, VB127
R SM87.7, 1
RCV VB100, 0
XMT VB125, 0
1.4 上位機(jī)的通信模塊設(shè)計(jì)
該恒壓供水監(jiān)控系統(tǒng)采用一臺(tái)工控機(jī)對(duì)泵房的水泵機(jī)組進(jìn)行監(jiān)控,監(jiān)控程序程序的功能包括水位、水壓、電機(jī)速度信號(hào)的采集;監(jiān)測(cè)顯示水泵機(jī)組的工作狀態(tài)和運(yùn)行情況;檢測(cè)故障信號(hào),進(jìn)行報(bào)警及語言提示;相關(guān)數(shù)據(jù)的存儲(chǔ)、動(dòng)態(tài)實(shí)時(shí)報(bào)表、歷史數(shù)據(jù)的隨時(shí)查詢、打?。桓鶕?jù)現(xiàn)場(chǎng)工作情況發(fā)出控制指令給PLC實(shí)行水泵機(jī)組的切換;根據(jù)生產(chǎn)實(shí)際情況修改工作參數(shù)等等。系統(tǒng)軟件采用Delphi高級(jí)語言編程,能夠及時(shí)準(zhǔn)確地對(duì)供水自動(dòng)化生產(chǎn)實(shí)行監(jiān)控。串行通信作為上位機(jī)和下位機(jī)聯(lián)系的橋梁,因此上位機(jī)通信模塊設(shè)計(jì)在整個(gè)監(jiān)控程序占有非常重要的地位。
用Delphi實(shí)現(xiàn)串口通信,最常用的辦法是使用控件(如MSCOMM等),利用MSCOMM控件開發(fā)串口通信程序,只需設(shè)置相關(guān)的屬性,使用相關(guān)的方法與相應(yīng)的事件,實(shí)現(xiàn)串口通信較為簡(jiǎn)單方便。本系統(tǒng)中上位機(jī)的信息管理及監(jiān)控軟件運(yùn)行在bbbbbbs2000/NT操作系統(tǒng)下,并利用MSCOMM控件開發(fā)設(shè)計(jì)了上位機(jī)與PLC的串行通信程序,對(duì)供水系統(tǒng)的運(yùn)行狀態(tài)進(jìn)行監(jiān)控。MSComm32控件的主要屬性、方法及事件如下[6-8]:
CommPort屬性:用于設(shè)置或返回通訊端口號(hào)。計(jì)算機(jī)的串行通訊端口一般有COM1和COM2兩個(gè),必須在打開端口以前設(shè)置該屬性。如果設(shè)置的端口不存在,運(yùn)行時(shí)會(huì)產(chǎn)生設(shè)備無效錯(cuò)誤。
CommEvent屬性:返回通信事件或錯(cuò)誤。
Setting屬性:設(shè)置并返回初始化參數(shù),即波特率、奇偶校驗(yàn)、傳輸數(shù)據(jù)位和停止位。
bbbbbMode屬性:設(shè)置或返回接收到的數(shù)據(jù)的類型。缺省為CombbbbbModeText表示以文本(ASCII碼)形式接收數(shù)據(jù),而CombbbbbModeBinary表示以二進(jìn)制形式接收數(shù)據(jù)。
bbbbb屬性:返回并刪除接收緩沖區(qū)中的數(shù)據(jù),在設(shè)計(jì)時(shí)Output屬性:向輸出緩沖區(qū)中寫入數(shù)據(jù),在設(shè)計(jì)時(shí)無效,運(yùn)行時(shí)為只讀。
Output屬性:向輸出緩沖區(qū)中寫入數(shù)據(jù),在設(shè)計(jì)時(shí)無效,運(yùn)行時(shí)為只讀。
PortOpen屬性:設(shè)置并返回通信端口開或關(guān)的狀態(tài),運(yùn)行時(shí)有效。
CommInit方法:初始化并打開指定的串口。
RecvData方法:接收數(shù)據(jù)。
SendData方法:發(fā)送數(shù)據(jù)。
ComOpenOrClose方法:打開或關(guān)閉串口。
OnComm事件:當(dāng)CommEvent屬性的值發(fā)生變化時(shí),就產(chǎn)生此事件,標(biāo)志發(fā)生了一個(gè)通信事件或錯(cuò)誤。
通信模塊作為上位機(jī)和PLC交換數(shù)據(jù)的平臺(tái),具有十分重要的作用。通信模塊的設(shè)計(jì)主要包括幾個(gè)方面:
1、串口初始化。串口初始化包括設(shè)置通信協(xié)議、輸入輸出緩沖區(qū)大小等內(nèi)容。
2、數(shù)據(jù)的接收和發(fā)送以及校驗(yàn)。上位機(jī)首先發(fā)出命令給PLC,PLC從串口輸出緩沖區(qū)內(nèi)接收數(shù)據(jù),然后PLC自動(dòng)發(fā)送一個(gè)響應(yīng)幀,上位機(jī)檢測(cè)到輸入緩沖區(qū)的數(shù)據(jù)開始接收數(shù)據(jù)。命令幀的格式為站號(hào)、讀/寫操作類型、發(fā)送數(shù)據(jù)、校驗(yàn)碼、結(jié)束字符。響應(yīng)幀的格式為站號(hào)、接收數(shù)據(jù)、校驗(yàn)碼、結(jié)束字符。為了保證通信數(shù)據(jù)的正確性,上位機(jī)對(duì)接收到的數(shù)據(jù)需要進(jìn)行校驗(yàn),校驗(yàn)是通過一個(gè)BCC校驗(yàn)函數(shù)來進(jìn)行。BCC校驗(yàn)碼就是將要傳送的字符串的ASCII碼以字節(jié)為單位作異或運(yùn)算,并將異或運(yùn)算結(jié)果作為指令的一部分傳送出去。
3、數(shù)據(jù)轉(zhuǎn)換。由于PLC在發(fā)送數(shù)據(jù)時(shí),有些模擬量數(shù)據(jù),如管網(wǎng)壓力和電機(jī)轉(zhuǎn)速,采用的是二進(jìn)制的形式,在計(jì)算機(jī)接受到數(shù)據(jù)之后必須進(jìn)行轉(zhuǎn)換,方能正確顯示。
4、錯(cuò)誤處理和報(bào)警。對(duì)于傳輸過程中可能出現(xiàn)的各種錯(cuò)誤,需要采取相應(yīng)的處理措施,不可恢復(fù)的嚴(yán)重錯(cuò)誤必須報(bào)警。
通信模塊中的部分事件源代碼如下:
//串口初始化
procedure TfrmCommTest.commInit;
begin
if MSComm1.PortOpen then MSComm1.PortOpen:=false;
MSComm1.Settings:=cboSetting.Text;
if chkTextOrBin.Checked then
MSComm1.bbbbbMode:=CombbbbbModeText//文本形式
else MSComm1.bbbbbMode:=CombbbbbModeBinary;//二進(jìn)制形式
MSComm1.bbbbbLen:=0;//讀接收緩沖區(qū)所有數(shù)據(jù)
MSComm1.InBufferSize:=CommOption.inbuffer;//設(shè)置緩沖區(qū)大小
MSComm1.OutBufferSize:=CommOption.outbuffer;
MSComm1.RThreshold:=1;//每接收到一個(gè)字符都產(chǎn)生OnComm事件
if cboCommPort.Text='COM1' then
MSComm1.CommPort:=1
else
MSComm1.CommPort:=2;
MSComm1.Handshaking:=CommOption.handshake;//設(shè)置握手協(xié)議
end;
procedure TfrmCommTest.chkSendHexClick(Sender: Tbbbbbb);
var bChk:boolean;
str:bbbbbb;
begin
if chkSendHex.Checked then //十六進(jìn)制形式
begin
bChk:=true;
end
else //字符串形式
begin
bChk:=false;
end;
str:=ConvertHexChar(memSend.Text,bChk);
memSend.bbbbb;
memSend.Text:=str;
end;
procedure TfrmCommTest.chkRecvHexClick(Sender: Tbbbbbb);
var bChk:boolean;
str:bbbbbb;
begin
if chkRecvHex.Checked then //十六進(jìn)制形式
begin
bChk:=true;
end
else //字符串形式
begin
bChk:=false;
end;
str:=copy(memRecv.Text,1,length(memRecv.Text));//需轉(zhuǎn)換的字符
str:=ConvertHexChar(str,bChk);
memRecv.bbbbb;
memRecv.Text:=str;
end;
//發(fā)送數(shù)據(jù)
procedure TfrmCommTest.SendData;
var str:bbbbbb;
begin
str:='';
if not MSComm1.PortOpen then//串口未打開
begin
MessageDlg('請(qǐng)先打開串口! ',mtInbbbbation,[mbOk],0);
exit;
end
else //串口已打開
begin
if memSend.Text='' then
MessageDlg('請(qǐng)輸入需要發(fā)送的數(shù)據(jù)! ',mtInbbbbation,[mbOk],0);
str:=memSend.Text;
sumSend:=sumSend+length(str);
MSComm1.Output:=str;
edit2.Text:=inttostr(sumSend);
end;
end;
//接收數(shù)據(jù)
procedure TfrmCommTest.RecvData;
var s:bbbbbb;
vTmp:Variant;
ovTmp:oleVariant;
i,iRecv:integer;
bTmp:Byte;
begin
if MSComm1.bbbbbMode=CombbbbbModeText then//文本形式
begin
iRecv:=MSComm1.InBufferCount;
s:=MSComm1.bbbbb;
if chkAutobbbbb.Checked then
memRecv.Text:=s
else memRecv.Text:=memRecv.Text+s;
sumRecv:=sumRecv+iRecv;
edit3.Text:=inttostr(sumRecv);
end
else //二進(jìn)制形式
begin
iRecv:=MSComm1.InBufferCount;
ovTmp:=MSComm1.bbbbb;
vTmp:=VarArrayCreate([0,127],varByte);
vTmp:=ovTmp;
s:='';
for i:=0 to iRecv-1 do //將接收到數(shù)據(jù)轉(zhuǎn)換為字符串
begin
bTmp:=vTmp[i];
s:=s+bbbbat('%2x',[bTmp]);
end;
if Length(s)=50 then
begin
for i:=1 to 50 do
begin
if s[i]=' ' then
s[i]:='0';
end;
memRecv.Text:=memRecv.Text+s;
end;
sumRecv:=sumRecv+iRecv;
edit3.Text:=inttostr(sumRecv);
end;
end;
procedure TfrmCommTest.cmdSendClick(Sender: Tbbbbbb);
begin
SendData;
end;
procedure TfrmCommTest.chkAutoSendClick(Sender: Tbbbbbb);
begin
if chkAutoSend.Checked then //選中自動(dòng)發(fā)送
begin
if MSComm1.PortOpen then
begin
timer1.Interval:=strtoint(lbTimeGap.Text);
timer1.Enabled:=true;
lbTimeGap.Enabled:=false;
lbTimeGap.Color:=clBtnFace;
cmdSend.Enabled:=false;
end
else
begin
MessageDlg('請(qǐng)先打開串口! ',mtInbbbbation,[mbOk],0);
chkAutoSend.Checked:=false;
cmdSend.Enabled:=true;
end;
end
else
begin
timer1.Enabled:=false;
lbTimeGap.Enabled:=true;
lbTimeGap.Color:=clbbbbbb;
end;
end;
1.5 小結(jié)
由于串行通信是兩級(jí)計(jì)算機(jī)控制系統(tǒng)中聯(lián)系上位機(jī)和下位機(jī)的橋梁。本章通過研究上位機(jī)和PLC之間的串行通信,對(duì)其中上位機(jī)和PLC通信模塊的設(shè)計(jì)進(jìn)行了詳細(xì)分析。
1.通過對(duì)上位機(jī)和PLC之間的串行通信的方式以及接口標(biāo)準(zhǔn)的研究,確定了本控制系統(tǒng)中的通信子系統(tǒng)所使用的通信標(biāo)準(zhǔn)和接口。
2.通信協(xié)議是保證串行通信的穩(wěn)定性和可靠性的重要環(huán)節(jié)。本章對(duì)上位機(jī)和SIMATIC S7-200系列PLC之間采用自定義通信協(xié)議的串行通信進(jìn)行了研究,并對(duì)自定義通信協(xié)議中的重要指令的格式定義進(jìn)行了詳細(xì)的設(shè)計(jì)和分析。此外,還對(duì)通信程序的發(fā)送、接收、應(yīng)答、BCC校驗(yàn)和數(shù)據(jù)維護(hù)子模塊的設(shè)計(jì)進(jìn)行了詳細(xì)的分析。










