<track id="zxlr8"></track>
<u id="zxlr8"><sub id="zxlr8"></sub></u>
  • <track id="zxlr8"></track>
    1. <ins id="zxlr8"><table id="zxlr8"></table></ins><wbr id="zxlr8"><ins id="zxlr8"></ins></wbr>
      <wbr id="zxlr8"><table id="zxlr8"></table></wbr><u id="zxlr8"><bdo id="zxlr8"></bdo></u>
    2. <video id="zxlr8"></video>
      <rp id="zxlr8"><input id="zxlr8"></input></rp>
    3. <u id="zxlr8"></u>

      RS485網絡的整幀數據收發

       2020-7-28     作者:黃志超    

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


        本文介紹在ESM6800、ESM7000和ESM8000主板上,利用iMX6/7/8串口的9bit RS485模式,實現RS485通訊網絡的整幀數據收發的功能。該功能可大大簡化應用程序接收線程的復雜性,提高RS485通訊的效率。


        整幀數據擁有固定的數據長度,由地址和數據構成,地址為一個字節,其余都為數據字節,如下圖:


      RS485網絡的整幀數據收發.png


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


        英創工控主板中,能夠支持9bit RS485模式的主板和串口如下表,其中ES6801/ES6801L和ESM6800L這三款核心板能夠滿足低成本的需求,可以考慮作為RS485網絡中的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模式,需要在程序中進行使能,使能后串口就會進入到該模式中,在發送數據的時候,可以支持兩種方式,一種是發送地址字節,另一種是發送數據字節。在接收數據字節的時候,分為master和slave兩種模式,這兩種模式都需要先接收地址字節,才能夠接收數據字節,如果沒有接收到地址字節,會自動將數據字節自動全部濾掉。他們的區別在于master模式下,只要接收到地址字節,就會將這之后的數據字節全部接收,并交給應用程序處理。而在slave模式下,需要先設置設備地址,只有接收到的地址字節和設備地址相同時,才會開始接收數據字節。


        master模式下,接收數據示意圖:


      RS485網絡的整幀數據收發-2.png


        Slave模式下,接收數據示意圖:


      RS485網絡的整幀數據收發-3.png


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


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


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


        在類實例化的時候,代入參數就可以決定串口是處于master模式還是slave模式,如果是出于slave模式可以一起代入需要設定的設備地址:


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


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


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


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


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


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


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


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


      RS485網絡的整幀數據收發.png


        感興趣的客戶可以和英創的工程師聯系,索取完整的測試工程。

      A毛看片免费观看视频视频在线播放,国产a片欧美一级毛 片在线观看,2019午夜75福利不卡片在线,久久精品国产99国产精,最近更新中文字幕免费,久久人人97超碰,中文字幕无码A片久久东京热 亚洲伊人成综合人影院,亚洲国产中文字幕在线视频,天天五月缴情在线观看,97国产在线看片免费人成视频,天干夜天天夜天干天,免费A级毛片高清视频,窝窝午夜色视频国产精品 92福利视频合集100午夜,人人天天夜夜曰曰狠狠狠,免费观看网站 亚洲自国产拍偷拍,国产免费888在线观看,久久天天躁狠狠躁夜夜躁2020,无羞耻肉动漫在线观看 欧美成人电影,日本不卡免费一区二区,老司机精品视频在线观看,快播影院在线观看,无遮挡又色又黄的免费视频,美女一黄色网站,成年无码AV片在线观看,亚洲AVAV天堂Av在线不卡 色就色欧美综合在线影院,亚洲欧美卡通另类丝袜美腿,老司机福利在线观看,夜夜爽8888免费视频,国内自拍99re久久,2018Av天堂在线视频精品观看,少妇无码精品12p 午夜天堂欧美成人在线视频,超碰91自拍国产自拍,激情综合色综合啪啪五月,男人的天堂在线视频,午夜理理伦A级毛片天天看,无码熟妇人妻AV在线偷拍,大量偷拍情侣自拍视频 精品国产自在现线拍在线,无码专区人妻系列日韩,色婷婷色综合缴情网站,猛男操的我高潮连连,国产片av国语在线观看手机版,久久人人97超碰精品,亚洲最大AV网站在线观看
      久久亚洲精品无码爱剪辑,亚洲欧美国产vr在线观,国产真实乱子伦精品视频,日韩精品一区二区中文免费在线观看,在线A亚洲V天堂网2018,免费观看欧美大片毛片不用播放器 日本极品高清不卡AV,亚洲AⅤ天堂AV在线电影猫咪,五月色婷婷综合狠狠爱,碰超79网站,印度女人牲交视频免费播放,va在线看国产免费,狠狠躁夜夜躁人人爽天天古典 免费 在线 av 日本,免费A片在线观看,一本道久在道最新2021,人妻无码不卡中文字幕系列,午夜爽爽爽男女免费观看HD,日本高清视频永久网站www,东京热人妻无码人av 人人插人人莫人人干在线,AV天堂久久天堂AV色综合,欧美A色爱综合网欧美V,亚洲图欧美日韩在线,亚洲中文字幕曰本毛片,中文字幕97超碰大香寡妇蕉,久爱在线 亚洲AV片不卡无码久久,亚洲人成免费观看视频在线,欧洲亚洲偷自拍第一页,av在线播放日韩亚洲欧,一日本道不卡高清A无码,97碰碰碰人妻无码视频,加勒比最新无码AV免费资源 国内精品自线在拍,日韩一区二区三不卡高清,伊人中文字幕无码专区视频在线播放网站,看全黄大色黄大片美女蓝光在线看,无码av高清毛片在线看,人人超人人超碰超国产 小草视频手机在线视频,免费黃色大片,偷欧洲亚洲另类图片AV天堂,久久国产乱子伦,国产乱子伦精品视频,日本高清色本在线视频观看,加勒比一本HEYZO高清视频 AV无码东京热亚洲男人的天堂,315电影网A级毛片,深夜A级毛片视频免费,亚洲日本VA午夜在线电影,日本无码免费不卡AV二区,在线看午夜福利片国产,亚洲中文字幕aⅴ天堂 无码刺激性A片,成上人色爱A∨综合网,午夜性影院在线观看视频播放,手机国产乱子伦精品视频,无码99久热只有精品视频在线,狠狠噜天天噜日日黑人亚洲,在线观看无码不卡 真实国产乱子伦对白视频不卡,国产成人亚洲精品,老司机亚洲精品影院无码,亚洲成av人片在线观看天堂无码,美国一级a片,狠狠狠的在啪线香蕉亚洲,AV男人的天堂在线观看第三区