關 閉

        新聞中心

        EEPW首頁 > 工控自動化 > 設計應用 > 基于C++Builder API函數的歐姆龍PLC串行通信

        基于C++Builder API函數的歐姆龍PLC串行通信

        作者: 時間:2016-10-10 來源:網絡 收藏

        1 引言

        本文引用地址:http://www.104case.com/article/201610/306696.htm

        計算機串行通信是計算機與控制設備(plc)進行數據傳送的基本通信方式,也是實現工業自動控制經常用到的通信模式。每一種通信方式都嚴格約定了與其對應的通信協議,要確保計算機與plc之間能正常通信,就必須遵照其通信協議編寫通信程序。

        2

        串行通信在工業系統控制的范疇中一直占據著極其重要的地位,串行端口(rs-232)是計算機上的標準配置,常用于連接調制解調器來傳輸數據,在計算機的硬件設備管理器中可以看到,定義為com1、com2等。常用的串行通信方式有兩種,分別是rs-232和rs-485,本文以rs-232方式為例進行介紹。

        3 上位機編程

        3.1 c++builder編程

        c++builder是由borland公司推出的產品。它采用c++語言作為開發語言,是面向對象語言,具有可視化編程界面且功能強大。

        3.2 c++builder串行通信相關api函數

        c++builder本身并不提供單獨的串行通信組件,而是使用一些windows api的函數來達到此目的。這些函數是由操作系統所提供,可以為程序設計人員提供相當多的執行功能。api中與串行通信相關的函數約有20個,本文將對經常使用的函數作討論。

        (1) 打開串行端口

        hcomm=createfile(comno,generic_read|generic_write,0,null,open_existing,0,0)

        函數參數定義如下:

        hcomm:createfile()函數的返回值,程序使用此返回值進行相關的串行端口操作。

        comno:定義串行端口號,為com1、com2等。

        generic_read|generic_write:對串行端口的讀/寫操作。

        0:是否共享串行端口,通常不會將串行端口與其它程序共享,因此設為0,否則為1。

        null:函數的返回值hcomm是否可被子程序繼承,此處設為不可繼承。

        open_existing:打開端口的方式,串行端口是一種設備,必須指定為open_existing方式。

        0:使用同步或異步方式傳輸數據,同步方式編程簡單,速率快,因此設為0,否則為1。

        0:由于使用串行端口編程,設為0。

        (2) 得到串行端口狀態:

        getcommstate(hcomm,dcb)

        函數參數定義如下:

        hcomm:createfile()函數的返回值。

        dcb:串行端口控制塊地址,負責對串行端口參數進行設置,具體參數如下:

        dcb.baudrate:設置串行端口的波特率,有19200kb/s、9600kb/s、4800kb/s幾種,一般為:9600kb/s。

        dcb.bytesize:設置串行端口的數據位數,有5、6、7、8幾種,歐姆龍plc數據位數為7。

        dcb.parity:設置串行端口的校驗位檢查,有none、even、odd幾種,設為none。

        dcb.stopbits:設置串行端口的停止位數,有1、1.5、2幾種, 歐姆龍plc的停止位數為1。

        (3) 設置串行端口狀態:

        setcommstate (hcomm,dcb)

        函數參數定義與getcommstate()函數相同。

        (4) 向串行端口寫數據:

        writefile(hcomm,senddata,bs,lrc,null)

        函數參數定義如下:

        hcomm:createfile()函數的返回值。

        senddata:寫數據的地址。

        bs:寫入數據的字節數。

        lrc:被寫入的數據地址。

        null:寫入數據的同步檢查,串行端口采用同步通信時可以設為null。

        (5) 清除串行端口的錯誤或將串行端口當前的數據狀態送至輸入緩沖區:

        clearcommerror(hcomm,dwerror,cs)

        函數參數定義如下:

        hcomm:createfile()函數的返回值。

        dwerror:返回錯誤信息代碼。

        cs:指向串行端口狀態的結構變量。

        (6) 從串行端口的輸入緩沖區讀出數據:

        readfile(hcomm,inbuff,cs.cbinque,nbytesread,null);函數參數定義如下:

        hcomm:createfile()函數的返回值。

        inbuff:指向用來存儲數據的地址。

        cs.cbinque:讀取數據的字節數。

        nbytesread:總的讀取字節數。

        null:如果不進行后臺工作,串行端口設為null。

        (7) 關閉串行端口:

        closehandle(hcomm)

        函數參數定義如下:

        hcomm:createfile()函數的返回值。

        4 plc通信數據幀介紹

        計算機與歐姆龍plc通信時,按應答方式進行。由計算機發給plc一組ascii碼字符數據,這一組數據成為命令塊。plc收到命令塊后經分析認為命令正常,則按照命令進行操作,將操作結果返回給計算機。plc返回給計算機的這一組數據稱為響應塊。若plc收到命令后經分析確認命令不正常,則返回給計算機錯誤命令塊。計算機和plc通信時,歐姆龍plc是被動的,必須先由計算機給plc發出命令塊,plc再給計算機發出響應塊。命令塊和響應塊以幀(frame)為單位進行傳送,一幀最多由131個字符組成。下面將歐姆龍plc命令幀與響應幀的組成結構介紹如下:

        4.1 命令幀

        命令幀組成結構如圖1所示。

        14.jpg

        幀結構解析:

        @:在起始處必須放置

        節點號:有效值為00—31, 表示pc機最多可同32臺plc通信

        頭代碼:plc的命令代碼

        發送文本:pc機發送的命令參數

        fcs(frame check sequence) :幀檢查順序代碼(幀校驗碼)

        幀校驗碼是2位(bit) 十六進制數。它是由幀數據包含的所有字符的ascii碼進行位異或運算的結果。

        終止符:“*”號和回車符“cr”

        舉例如下:

        讀h區命令幀結構如圖2所示。

        13.jpg

        4.2 響應幀

        響應幀結構如圖3所示。

        12.jpg

        幀結構解析:

        @ :返回命令頭

        節點號 :有效值為00—31,返回數據的plc節點號

        頭代碼 :plc的命令代碼

        尾代碼 : 返回命令完成狀態碼

        接收文本: 在有數據時返回的數據

        fcs :幀檢查順序代碼

        終止符:“*”號和回車符“cr”

        舉例如下:

        讀h區響應幀結構圖4所示。

        11.jpg

        4.3 fcs(幀數據冗余校驗碼)的計算

        為了降低串行通信的誤碼率,在接收和發送端都必須對數據進行校驗,常用的方法是進行fcs校驗。對幀數據進行冗余校驗計算時,應對幀數據中各個字符的ascii碼進行位異或運算,然后將結果轉為2位十六進制字符。

        5 c++builder api函數應用

        5.1 通信主程序的設計架構

        通信主程序的主要功能:實現計算機對plc的運行控制和狀態監視,即構成一個閉環監控系統,程序設計架構如圖5所示。

        10.jpg

        5.2 打開串信端口

        (1) 打開通信端口,對端口進行初始化設置,工作流程如圖6示。

        9.jpg

        (2) 打開通信端口程序源代碼:

        void__fastcall tform1::button1click(tobject *sender)

        {

        char *comno;

        dcb dcb;

        string temp;

        temp=“com”+inttostr(rdcom-》itemindex+1);

        comno=temp.c_str() ;

        hcomm=createfile(comno,generic_read|generic_write,

        0,null,open_existing,1,0);

        if(hcomm==invalid_handle_value)

        {

        messagebox(0,“打開通信端口錯誤,請檢查端口是否被占用!!” ,“comm error”,mb_ok);

        return;

        }

        getcommstate(hcomm,dcb);

        dcb.baudrate=cbr_9600;

        dcb.bytesize =7;

        dcb.parity =evenparity;

        dcb.stopbits =onestopbit;

        setcommstate(hcomm,dcb);

        if(!setcommstate(hcomm,dcb))

        {

        messagebox(0,“通信端口設置錯誤!!!”,“set error”,mb_ok);

        closehandle(hcomm);

        return;

        }

        }

        5.3 寫plc內存數據

        (1) 將計算機發出的命令寫入plc,實現計算機對plc的控制功能。工作流程如圖7示。

        8.jpg

        (2) 寫plc內存函數程序源代碼:

        string tform1::write(string address,string value)

        {

        unsigned long lrc,bs;

        string temp;

        char *senddata;

        char inbuff[1024];

        int ln,i=0;

        string word,check;

        dword nbytesread,dwevent,dwerror;

        comstat cs;

        word=“@00wd”+address+value;

        if(hcomm==0)

        {

        messagebox(0,“串口未打開!!!”,“錯誤信息”,mb_ok);

        return(0);

        }

        temp=outchecksum(word);

        senddata=temp.c_str() ;

        bs=strlen(senddata);

        loop:

        if(++i《=3)

        {

        writefile(hcomm,senddata,bs,lrc,null);

        sleep(100);

        if(hcomm==invalid_handle_value) return(0);

        clearcommerror(hcomm,dwerror,cs);

        if(cs.cbinque》sizeof(inbuff))

        {

        purgecomm(hcomm,purge_rxclear);

        return(0);

        }

        readfile(hcomm,inbuff,15,nbytesread,null);

        check=inbuff;

        if(check.substring(6,2)!=“00”)

        {

        goto loop;

        }

        }

        else

        {

        messagebox(0,“數據寫錯誤”,“通信錯誤”,mb_ok);

        }

        }

        5.4 讀plc內存數據

        (1)從plc中讀取數據,監視plc的運行數據,工作流程如圖8示。

        7.jpg

        (2) 讀plc內存函數程序源代碼:

        string tform1::read(string address,string value)

        {

        string readdata,readdata1,readdata2;

        string temp;

        unsigned long lrc,bs;

        char *senddata;

        int ln,i=0,len;

        dword nbytesread,dwevent,dwerror;

        comstat cs;

        char inbuff[1024];

        string word;

        word=“@00rd”+address+value;

        if(hcomm==0) return(0);

        temp=outchecksum(word);

        senddata=temp.c_str();

        bs=temp.length();

        loop:

        if(++i《=3)

        {

        writefile(hcomm,senddata,bs,lrc,null);

        sleep(100);

        if(hcomm==invalid_handle_value) return(0);

        clearcommerror(hcomm,dwerror,cs);

        if(cs.cbinque》sizeof(inbuff))

        {

        purgecomm(hcomm,purge_rxclear);

        return(0);

        }

        cs.cbinque=4*strtoint(value)+11;

        readfile(hcomm,inbuff,cs.cbinque,nbytesread,null);

        inbuff[cs.cbinque]=`

        主站蜘蛛池模板: 华宁县| 曲阳县| 盐源县| 西宁市| 青州市| 乃东县| 沛县| 马龙县| 大化| 福泉市| 宁波市| 苏尼特左旗| 晋江市| 分宜县| 即墨市| 尤溪县| 康平县| 辉南县| 芜湖市| 闸北区| 定襄县| 八宿县| 博白县| 宁国市| 北川| 瑞昌市| 阿拉善左旗| 台湾省| 蚌埠市| 渭源县| 龙州县| 方正县| 江安县| 濮阳县| 镇巴县| 达拉特旗| 本溪市| 青冈县| 绍兴县| 丰城市| 全椒县|