<strike id="kiyse"></strike>
  • <tr id="kiyse"></tr>
  • <strike id="kiyse"></strike><samp id="kiyse"><tbody id="kiyse"></tbody></samp>
    <strike id="kiyse"><s id="kiyse"></s></strike>
    <tr id="kiyse"></tr>
    <noframes id="kiyse"><code id="kiyse"></code></noframes>
    <th id="kiyse"></th>
    <samp id="kiyse"></samp>
  • <th id="kiyse"><s id="kiyse"></s></th>
  • RS485網(wǎng)絡(luò)的整幀數(shù)據(jù)收發(fā)

     2020-7-28     作者:黃志超         

      背景:RS485是最常用的工業(yè)現(xiàn)場通訊手段,它的傳輸字節(jié)采用了異步串口UART的規(guī)范。在通常的工控應(yīng)用中,需要傳輸由多個字節(jié)組成的數(shù)據(jù)幀,而RS485并沒有對數(shù)據(jù)幀有任何規(guī)范,需要應(yīng)用程序自己做數(shù)據(jù)幀的鑒別。


      本文介紹在ESM6800、ESM7000和ESM8000主板上,利用iMX6/7/8串口的9bit RS485模式,實現(xiàn)RS485通訊網(wǎng)絡(luò)的整幀數(shù)據(jù)收發(fā)的功能。該功能可大大簡化應(yīng)用程序接收線程的復(fù)雜性,提高RS485通訊的效率。


      整幀數(shù)據(jù)擁有固定的數(shù)據(jù)長度,由地址和數(shù)據(jù)構(gòu)成,地址為一個字節(jié),其余都為數(shù)據(jù)字節(jié),如下圖:


    RS485網(wǎng)絡(luò)的整幀數(shù)據(jù)收發(fā).png


      9bit RS485模式使用了串口固定校驗位的功能,定義了地址字節(jié)和數(shù)據(jù)字節(jié),地址字節(jié)是指固定校驗位始終為1的字節(jié)。而數(shù)據(jù)字節(jié)則是指固定校驗位始終為0的字節(jié)。同時9bit RS485模式實現(xiàn)了一些硬件過濾的功能,在接收的時候,必須要先接收到地址字節(jié)才會開始接收數(shù)據(jù)字節(jié),否則硬件會將收到的數(shù)據(jù)字節(jié)全部過濾掉,通過這種方式降低了設(shè)備的負載。所以9bit RS485模式顧名思義,通常使用在RS485模式上面,因為RS485可以作為總線掛接多個設(shè)備,在多路設(shè)備通訊的情況下通過這種校驗方式可以有效的降低設(shè)備負載和軟件的復(fù)雜程度。


      英創(chuàng)工控主板中,能夠支持9bit RS485模式的主板和串口如下表,其中ES6801/ES6801L和ESM6800L這三款核心板能夠滿足低成本的需求,可以考慮作為RS485網(wǎng)絡(luò)中的Slave端:


    主板型號支持9bit RS485模式的串口備注
    ES6801(L)ttyS1—ttyS6適合作為Slave
    ESM6800(H)ttyS1—ttyS5適合作為Master
    ESM6800EttyS1—ttyS6適合作為Master
    ESM6800LttyS1—ttyS6適合作為Slave
    ESM6802ttyS1—ttyS4適合作為Master
    ESM7000ttyS1—ttyS6適合作為Master


      如果要使用9bit RS485模式,需要在程序中進行使能,使能后串口就會進入到該模式中,在發(fā)送數(shù)據(jù)的時候,可以支持兩種方式,一種是發(fā)送地址字節(jié),另一種是發(fā)送數(shù)據(jù)字節(jié)。在接收數(shù)據(jù)字節(jié)的時候,分為master和slave兩種模式,這兩種模式都需要先接收地址字節(jié),才能夠接收數(shù)據(jù)字節(jié),如果沒有接收到地址字節(jié),會自動將數(shù)據(jù)字節(jié)自動全部濾掉。他們的區(qū)別在于master模式下,只要接收到地址字節(jié),就會將這之后的數(shù)據(jù)字節(jié)全部接收,并交給應(yīng)用程序處理。而在slave模式下,需要先設(shè)置設(shè)備地址,只有接收到的地址字節(jié)和設(shè)備地址相同時,才會開始接收數(shù)據(jù)字節(jié)。


      master模式下,接收數(shù)據(jù)示意圖:


    RS485網(wǎng)絡(luò)的整幀數(shù)據(jù)收發(fā)-2.png


      Slave模式下,接收數(shù)據(jù)示意圖:


    RS485網(wǎng)絡(luò)的整幀數(shù)據(jù)收發(fā)-3.png


      采用9bit RS485模式,有兩個優(yōu)點,第一點是不需要判斷是否接收到地址字節(jié),因為串口要在接收到地址字節(jié)(校驗位為1)后,才會接收數(shù)據(jù)字節(jié),特別是在slave模式下,只有當(dāng)?shù)刂纷止?jié)和設(shè)置的設(shè)備地址相等時,才會接收數(shù)據(jù)。第二點是不需要切換校驗方式,當(dāng)串口啟用了9bit RS485模式,就可以正常接收所有地址字節(jié)和數(shù)據(jù)字節(jié)了,只有在發(fā)送地址字節(jié)和數(shù)據(jù)字節(jié)的時候需要切換不同的設(shè)置,可以減少軟件上的操作。


      英創(chuàng)公司在提供的例程Step2_serialtest中封裝的串口類CSerial的基礎(chǔ)上派生出一個專用于9bit RS485的類CRS485,在這個類中我們增加使能9bit RS485模式的函數(shù),讓客戶可以直接調(diào)用來實現(xiàn)相關(guān)功能。


    /**
     *    派生用于9bit RS485的類
     *
    **/
    class CRS485 : public CSerial
    {
    private:
           //串口模式、設(shè)備地址和接收超時時間
           int serial_mode;
           int serial_addr;
     
    public:
           //接收數(shù)據(jù)緩存和長度
           char frame[100];
           int  frame_len;
     
           /**
            *    派生類的構(gòu)造函數(shù)
            *
            *    在構(gòu)造函數(shù)中初始化變量,以及設(shè)置9-bit RS485模式下的串口是處于master還是slave模式
            *
            *    參數(shù)說明:
            *    mode:值為0對應(yīng)master模式,值為1對應(yīng)slave模式
            *    addr:設(shè)備地址,大小為8bit,當(dāng)且僅當(dāng)mode為1是有效。
            *
           **/
           CRS485(int mode, int addr);
     
           /**
            *    發(fā)送9bit RS485整包數(shù)據(jù)
            *
            *    函數(shù)會將地址字節(jié)和數(shù)據(jù)字節(jié)填寫,并設(shè)置為相應(yīng)的模式一并發(fā)送
            *
            *    參數(shù)說明:
            *    addr:設(shè)備地址,大小為8bit,填入發(fā)送數(shù)據(jù)的地址字節(jié)中
            *    Buf:發(fā)送的數(shù)據(jù)字節(jié)
            *    len:發(fā)送數(shù)據(jù)字節(jié)的長度
            *
            *    返回值說明:
            *    len:成功
            *    -1:失敗
            *
           **/
           int send_rs485_frame(char addr, char *Buf, int len);
     
           /**
            *    接收9bit RS485整包數(shù)據(jù)
            *
            *    函數(shù)會阻塞接收指定長度的數(shù)據(jù),可以設(shè)置超時時間,如果超過超時時間沒有接收到指定長度的數(shù)據(jù),則返回-1
            *
            *    參數(shù)說明:
            *    Buf:接收的數(shù)據(jù)字節(jié)
            *    len:發(fā)送數(shù)據(jù)字節(jié)的長度
            *    timeout:超時時間,單位毫秒。如果在超時時間內(nèi)沒有收到指定長度的數(shù)據(jù),則返回-1。值為0則不阻塞,讀取不到數(shù)據(jù)立即返回。值為-1則沒有超時時間,如果接受不到指定長度數(shù)據(jù)會一直等待
            *
            *    返回值說明:
            *    成功則返回接收到的數(shù)據(jù)長度
            *    -1:超時
            *
           **/
           int recv_rs485_frame(char *Buf, int len, int timeout);
     
           /**
            *    繼承自CSerial類的接收處理函數(shù)
            *
            *    在CSerial類的接收線程中會調(diào)用這個函數(shù),可以在函數(shù)中調(diào)用recv_rs485_frame()函數(shù),并處理接收到的數(shù)據(jù)字節(jié)
            *     
            *
           **/
           int PackagePro();
    };


      在類實例化的時候,代入?yún)?shù)就可以決定串口是處于master模式還是slave模式,如果是出于slave模式可以一起代入需要設(shè)定的設(shè)備地址:


    //master模式
    class CRS485  m_Serial(0, 0);
     
    //slave模式,設(shè)備地址為0x55
    class CRS485  m_Serial(1, 0x55);



      接收處理的時候,數(shù)據(jù)的長度通過宏DATA_LEN定義,客戶可以在PackagePro()函數(shù)中可以定義超時時間,然后調(diào)用recv_rs485_frame()函數(shù)來接收整包數(shù)據(jù),recv_rs485_frame()函數(shù)會阻塞,直至收到指定長度的數(shù)據(jù),或者到達超時時間才會返回。接收到整包數(shù)據(jù)后,就可以開始進行數(shù)據(jù)的處理,在接收線程調(diào)中循環(huán)調(diào)用PackagePro函數(shù):


    #define DATA_LEN 10                    // 數(shù)據(jù)長度
     
    // 接收串口數(shù)據(jù)處理函數(shù)
    int CRS485::PackagePro()
    {
           int i1, timeout;
     
           //設(shè)置超時時間,單位毫秒
           timeout = 500;
     
           //調(diào)用接收函數(shù)來獲取指定長度的整包數(shù)據(jù)
           i1 = recv_rs485_frame(DatBuf, m_DatLen, timeout);
     
           //接收到整包數(shù)據(jù),調(diào)用處理程序,這里只是簡單的打印
           if(i1 != -1)
           {
                  printf("frame addr = 0x%x\n", frame[0]);
                  printf("frame data = ");
                  for(i1=1; i1<DATA_LEN; i1++) {
                         printf("0x%x ", frame[i1]);
                  }
                  printf("\n");
     
                  //處理完數(shù)據(jù),清除各個變量,重新設(shè)置串口以等待下一包數(shù)據(jù)
                  memset(frame, 0, 100);
                  frame_len = 0;
           }
           else
                  printf("time out!\n");
     
           return i1;
    }


      在線程中的處理,循環(huán)調(diào)用接收處理函數(shù)即可,因為recv_rs485_frame()函數(shù)會阻塞,直至收到指定長度的數(shù)據(jù),或者到達超時時間才會返回:


    int CSerial::ReceiveThreadFunc(void* lparam)
    {
           CSerial *pSer = (CSerial*)lparam;
     
           //定義讀事件集合
           fd_set fdRead;
           int ret;
           struct timeval     aTime;
     
           while( 1 )
           {
                  //接收處理函數(shù)
                  pSer->PackagePro( pSer->DatBuf, pSer->m_DatLen);
     
           }
     
           printf( "ReceiveThreadFunc finished\n");
           pthread_exit( NULL );
           return 0;
    }



      串口在發(fā)送的時候,比較簡單,直接調(diào)用send_rs485_frame()函數(shù),填入需要發(fā)送的地址和數(shù)據(jù)即可,使用下面的代碼來測試:


    char        addr = 0x55;
    char    Buf[2];
     
    Buf[0] = 0x55;
    Buf[1] = 0xaa;
     
    //發(fā)送地址字節(jié)和數(shù)據(jù)字節(jié)
    m_Serial.send_rs485_frame(addr, Buf, sizeof(Buf));


      主板實際輸出的波形如下:


    RS485網(wǎng)絡(luò)的整幀數(shù)據(jù)收發(fā).png


      感興趣的客戶可以和英創(chuàng)的工程師聯(lián)系,索取完整的測試工程。

    国产偷窥熟女精品视频大全| 久久伊人精品青青草原日本| 久久99国产精品成人| www.亚洲精品| 精品国产一区二区三区AV| 奇米影视7777久久精品| 久久国产香蕉一区精品| 日本精品一区二区三区视频 | 国产午夜精品一区理论片| 国产精品视频无圣光一区| 亚洲精品美女视频| 日本精品在线视频| 精品人体无码一区二区三区| 精品国产麻豆免费网站| 国产精品视频a播放| 久久影院综合精品| 久久亚洲国产精品一区二区| 精品久久久久一区二区三区| 色精品一区二区三区| 精品国产香蕉伊思人在线又爽又黄| 精品国产伦一区二区三区在线观看 | 久久久99精品成人片| 久久99精品国产自在现线小黄鸭| 中文字幕精品亚洲无线码一区应用| 午夜国产精品无套| 国产成人精品无缓存在线播放| 国产精品一区视频| 亚洲va精品中文字幕 | 久久精品国产网红主播| 国产成人亚洲精品狼色在线| 国产精品九九久久免费视频| 免费视频成人国产精品网站| 国产精品十八禁在线观看| 国产精品扒开腿做爽爽的视频| 日韩视频在线精品视频免费观看 | 国产成人精品高清在线观看93 | 国产成人久久精品二三区麻豆| 国产精品资源在线观看网站| 2020国产精品| 亚洲国产美女精品久久久| 久久亚洲精品专区蓝色区 |