計算機與PLC的通訊格式和實現方法
本文簡要介紹了PLC編程數據口的操作命令格式及其VC++語言實現通訊方法,并給出了四類操作的VC++語言實現,為監控和管理PLC的運行提供了一種良好的方法。
關鍵詞:PLC;編程口;串口通訊;VC++語言
一、引言
可編程序控制器(PLC)都有一個編程口。以日本三菱公司生產的PLC為例(包括FX系列和A系列),其編程口為RS-422格式,根據PLC型號不同又分為8針座編程口和25針座編程口。對于后者,可直接將SC—08編程電纜將PLC的編程口和微型計算機的RS—232口連接起來;對于后者,則還需要一根轉換電纜將PLC 的8針座編程口和25針編程電纜相連。無論何種情況,一旦將PLC用戶程序由微型計算機編程環境傳到PLC 用戶程序區,其編程口大多就沒有被再利用。其實,這是一種浪費。也就是說,可利用此編程口實現微型計算機和PLC 的數據通訊,將PLC的工作狀態納入微型計算機管理之下。
二、編程口操作命令類型與通訊端口初始化
串行通訊是計算機與其它機器之間進行通訊的一種常用方法,在WINDOWS操作系統中提供了實現各種串行通訊的API函數。通過SC—08編程電纜或FX232AW模塊,可將微型計算機的串行通訊口RS—232和PLC 的編程口連接起來,這樣微型計算機就可對PLC的RAM區數據進行讀、寫操作。由PLC本身所具有的特性,可對PLC進行以下四種類型的操作:
(1)位元件或字元件狀態讀操作(CMD0);
(2)位元件或字元件狀態寫操作(CMD1);
(3)位元件強制ON操作(CMD7);
(4)位元件強制OFF操作(CMD8)。
另外,在進行上述四類操作以前,首先要對端口進行初始化操作,即設定通訊協議(包括設置通訊波特率、數據位數、數據停止位及奇偶校驗)。在WINDOWS的SDK中定義了一個結構DCB,該結構詳細地說明了如何對通訊端口進行控制,所以通訊端口的初始化也是圍繞著對這個結構的正確設置為中心進行的。用VC++語言實現端口初始化如下:
BOOL CSerial::Open(int nPort)
{
//nPort 為微型計算機串行通訊口端口號。nport=1為端口1;nPort=2為端口2。
char szPort\[15\];
DCB dob;
m_hIDComDev=CreateFile(szPort, GENERIC_READ│GENERIC_WRITE,O,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL│FILE_FLAG_OVERLAPPED,NULL);
dcb.DCB1ength=sizeof(DCB);
GetCommState(m_hIDComDev,&dcb);//取得通訊資源當前設置
dcb.BaudRate=9600;//設定波特率為9600
dcb.ByteSize=7;//7數據位
dcb.Parity=2;//偶校驗
dcb.StopBits=0;//設定1個停止位
if(SetCommState(m_hIDComDev,&dcb)return(TRUE);
else return(FALSE);//設置端口,若設置成功則返回TRUE,否則返回FALSE
}
需要說明的是CSerial是一個用于串行通訊的類,它包含了進行串行通訊的所需的函數。除上述端口初始化成員函數Open外,還包括另兩個重要成員函數:一個是endData,把數據從一個緩沖區發送到串行端口。另一個是ReadData,從端口的接收緩沖區中讀入數據。
其次,在每進行一次上述四類操作中的一種操作以前,還要進行握手聯絡。對PLC發請求訊號ENQ(代碼為OX05),然后讀PLC 的響應訊號。如果讀到的響應訊號為ACK(代碼為OX06),則表示PLC已準備就緒,等待接收通訊數據。握手聯絡VC++語言示PLC已準備就緒,等待接收通訊數據。握手聯絡VC++語言實現為:
BOOL CNTJD1g::ReadFromPLC(char *Read_char char *Read_address,int Read_bytes)
{
CSerial Serial;//用于串行通訊的類
char read_BUFFER;
if(Serial.Open(2)//初始化串行口通訊口COM2
{ Serial.SendData(&ENQ_request,1);//發送聯絡訊號
Sleep(1000);//等待1秒鐘
Serial.ReadData(&read_BUFFER,1);//讀取PLC響應訊號
if(read_BUFFER==ACK)
{ 如果PLC響應訊號等于ACK,則進行上述四種操作:}}
Serial.Close()://操作完畢后,關閉通訊口
}
三、編程口命令操作
(1)位元件或字元件狀態讀操作
操作對象元件:PLC內部的X、Y、M、S、T、C、D元件;命令格式:
說明:①為讀命令起始標志STX,代碼為OX02;
②為位元件或字元件狀態讀命令CMDO,命令代碼為OX30;
③為讀位元件或字元件的4位起始地址,高位先發,低位后發,且是以ASCII碼的形式發送;
④為一次讀取位元件或字元件的個數,最多一次可讀取OXff個字節的元件,以ASCII碼的形式發送;
⑤為停止位標志ETX,代碼為OX03;
⑥為2位和校驗,和累計為②、③、④項代碼,取其和最低兩位轉化成ASCII碼,高位先發,低位后發。
在發送完上述命令格式代碼后,就可直接讀取PLC響應的信息。響應信息格式如下:
VC++語言實現:
BOOL CNTJDlg::ReadFromPLC(char *Read_char char
*Read_address, int Read_bytes)
{
char senddatasum_CHECK\[2\];char readdatasum_CHECK\[2\]; char total_DATABYTES\[2\];
char readdatasum_check\[2\];int readdata_sum;
int datasum_check=0; int i;
Serial.SendData(&STX_start,1);/向PLC發送“開始”標志代碼
Serial.SendData(&CMDO_read,1);//發送“讀”命令代碼datasum_check+=CMDO_read;
for(i=0;i<4;i++){Serial.SendData(&Read_address\[i\],1);//發送起始元件地址的ASCII代碼datasum_check+=Read_address\[i\];}
Change to ASCII(total DATABYTES,Read_bytes);//將字節數轉化成ASCII代碼
for (i=0;i<2;i++){Serial.SendData(&total_DATABYTES\[i\],1);//發送元件字節數的ASCII代碼)datasum_check+total_DATABYTES\[i\];}
Serial.SendData(&ETX_end,1);//發送“結束”標志代碼senddatasum_CHECK+ETX_end;
Change_to_ASCII(senddatasum_CHECK,senddatasum_CHECK);//將“和”轉化成ASCII碼
for (i=0;i<2;i++) Serial.SendData(&senddatasum_CHECK\[i\],1);
Sleep(1000);//等待PLC響應
Serial.ReadData(&read_BUFFER,1);
if(read_BUFFER==STX_start){
readdata_sum=0;
for(i=0;i<2*Read_bytes;i++){Serial.ReadData(&Read_char\[i\],1);//讀Read_bytes個字節readdata_sum+Read_char\[i\];}
Serial.ReadData(&read_BUFFER,1);
if(read_BUFFER==ETX_end){Serial.ReadData(readdatasum_CHECK,2);//讀入的“和”的低2位ASCII碼Readdata_sum+=ETX_end;}
Change_to_ASCII(readdatasum_check,readdata_sum);//將計算得到的“和”轉化成ASCII碼
if(*readdatasum_CHECK==*readdatasum_check)//“和”校驗
{ AfxMessageBox(“數據讀出成功!”)return TRUE;}
else { AfxMessageBox(“校驗錯誤”)return FALSE.}
}
(2)位元件或字元件狀態寫操作
操作對象元件:同3(1);命令格式:
說明:①為寫命令起始標志STX,代碼為OX02;
②為位元件或字元件狀態寫命令CMD1,命令代碼為OX31;
③為寫位元件或字元件的4位起始地址,高位先發,低位后發,且是以ASCII碼的形式發送;
④為一次寫入位元件或字元件的個數,以ASCII碼的形式發送;
⑤為待寫到PLC RAM區的數據DATA,以ASCII碼形式發送;
⑥為停止位標志ETX,代碼為OX03;
⑦為2位和校驗,和累計為②、③、④項代碼,取其和最低兩位轉化成ASCII碼,高位先發,低位后發。
VC++語言實現:
BOOL CNTJDlg::WritePLC(char *data_ADDRESS,char *Write_ASC,int bytesnumber)
{
char total_BYTES\[2\];char senddatasum_CHECK\[2\];
char read_BUFFER;char read_finishBUFFER;
int datasum_check=0; int i=0;
Serial.SendData(&STX_start,1);//向PLC發送“開始”標志代碼
datasum_check=0;Serial.SendData(&CMD1_write,1);//發送“寫”命令代碼
datasum_check+CMD1_write;
for(i=0;i<4;i++) {Serial.SendData(&data_ADDRESS\[i\],1);//發送起始元件地址的ASCII碼
datasum_check+=data_ADDRESS\[i\];
Change_to_ASCII(total_DATABYTES,bytesnumber);//將字節數轉化成ASCII碼
for(i=0;i<2;i++)
{
Serial.SendData(&total_BYTES\,1);//發送元件字節數的ASCII代碼
datasum_check+=total_BYTES\[i\];}
for {i=0;i
Serial.SendData(&Write_ASC\[i\],1);//發送要寫入的數據的ASCII碼
datasum_check+=Write_ASC\[i\];}
Serial.SendData(&ETX_end,1);//發送“結束”標志代碼
datasum_check+=ETX_end;
Change_to_ASCII(senddatasum_CHECK,datasum_check);//將“和”轉化成ASCII碼
Serial.SendData(&senddatasum_CHECK,2);
Sleep(1000); Serial.ReadData(&read_finishBUFFER,1);
if (read_finishBUFFER==ACK_reply)
{AfxMessageBox(“數據寫入 OK”)return TRUE;}
else {AfxMessageBox(“數據寫入失敗”)return FALSE。}
(3)位元件強制ON操作
操作對象:X、Y、M、S、T、C元件;
命令格式:
說明:①為強制ON命令起始標志STX,代碼為OX02;
②為強制ON命令CMD7,命令代碼為OX37;
③為強制ON位元件4位起始地址,高位先發,低位后發,是以ASCII碼形式發送;
④為停止位標志ETX, 代碼為OX03;
⑤為2位和校驗,和累計為②、③、④項代碼,取其和低兩位轉化成ASCII碼,高位先發,低位后發。
VC++語言實現:
void NTJDlg::ForceOnOperation (char *ON_Address)
{ int i;
char│syn_Check\[2\];
char read_buffer;
int Sum=0;
Serial.SendData(&STX_start,1);//向PLC發送“開始”標志代碼
Serial.SendData(&CMD7_ForceON,1);//發送“ON”命令代碼
Sum+=CMD7 ForceON;
for (i=0; i<4; i++) {Serial.SendData(&ON_Address\[i\],1)//發送起始元件地址的ASCII碼
Sum+=ON_Address\[i\];}
Serial.SendData(&ETX_end,1);//發送“結束”標志代碼Sum+=ETX_end;
Change_to_ASCII(Sum_Check,Sum);//將“和”轉化成ASCII碼
Serial.SendData(&Sum_Check,2);
Sleep(1000);
Serial.ReadData(&read_buffer,1);
if(read_finishBUFFER==ACK_reply) AfxMessageBox(“ON 操作 OK”);
else AfxMessageBox(“ON 操作失敗”)。
}
(4)位元件強制OFF操作
操作對象L同3(3);命令格式:
說明:①為強制OFF命令起始標志STX,代碼為OX02;
②為強制OFF命令CMD8,命令代碼為OX38H;
③為強制OFF位元件4位起始地址,高位先發,低位后發,以ASCII碼形式發送;
④為停止位標志ETX,代碼為OX03;
⑤為2位和校驗,和累計為②、③、④項代碼,取其和最低兩位轉化成ASCII碼,高位先發,低位后發。
VC++語言實現:
void NTJDlg::ForceOffOperation (char *OFF_Address)
{
int i;
char Sum_Check\[2\];
char read_buffer;
int Sum=0;
Serial.SendData(&STX_start,1);//向PLC發送“開始”標志代碼
Serial.SendData(&CMD8_ForceOFF,1);//發送“OFF”命令代碼
Sum=CMD8_ForceOFF;
for (i=0;i<4;i++) {
Serial.SendData(&OFF_Address\[i\],1);//發送起始元件地址的ASCII碼
Sum+=OFF_Address\[i\];}
Serial.SendData(&ETX_end,1);//發送“結束”標志代碼
Sum+=ETX_end;
Change_to_ASCII(Sum_Check,Sum);//將“和”轉化成ASCII碼
Serial.SendData(&Sum_Check,2);
Skeeo(1000);
Serial.ReadData(&read_buffer,1);
if(read_fininhBUFFER==ACK_reply) AfxMessageBox(“OFF 操作 OK ”);
else AfxMessageBox(“OFF 操作失敗”)。
}
注意:必須嚴格按照上述四種操作命令格式進行發送,在發送前,起始地址、數據、數據個數、校驗和都必須按位轉換成ASCII碼。從PLC讀到的數據亦是ASCII碼形式,需要經過適當轉換才能利用。另外,要注意強制命令地址與讀寫地址的順序不是一樣,且一次最多只能傳送64個字節數據。
四、結論
利用上述四種操作命令,就可對PLC的RAM區數據進行管理操作。將PLC的工作狀態納入微型計算機管理之下。在此基礎上,用戶可以應用VC很方便地設計自己的PLC人機接口界面,為監控與管理PLC的運行提供一種良好的方法。
評論
查看更多