1. <delect id="hbm07"><option id="hbm07"></option></delect><s id="hbm07"><option id="hbm07"><bdo id="hbm07"></bdo></option></s>
    <s id="hbm07"></s>

      1. <p id="hbm07"><option id="hbm07"><bdo id="hbm07"></bdo></option></p>

        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


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

        酥酥影院18禁止-日本三级吹潮在线观看-国产成人亚洲日韩欧美-无码中文天天av天天爽-欧美人与动牲交A-一本之道高清在线不卡视频-久久99热只有频精品 2021年国产精品青青草原-三级香港三级韩国三级-又色又爽又黄的视频还免费-亚洲老熟女-特级婬片女子高清视频-国产午夜福利1000集-无码AV无码天堂资源网 在线播放国产不卡免费视频-国第一产在线精品亚洲区-人妻少妇久久中文字幕-成 人影片 毛片免费观看-亚洲国产在线精品一区在线观看-亚洲精品国产第一区二区 2021超清国产小视频-亚洲城人在线视频-国产乡下三级-人妻少妇精品无码专区无码-国产在线视频一区二区三区-2021中文一卡二卡三卡-国产在线精品亚洲一区 2021超清国产小视频-亚洲城人在线视频-国产乡下三级-人妻少妇精品无码专区无码-国产在线视频一区二区三区-2021中文一卡二卡三卡-国产在线精品亚洲一区 国产 日产 欧美最新-人妻少妇精品专区性色av-欧美性色av性色在线观看-日本三级韩国-国产真实迷奷学生在线-国产一级特黄高清大片自怕-黑粗硬大欧美在线视频 国产国产人免费人成免费视频-日本三级香港三级人妇电影99-人妻熟女精品视频专区-色综合久久无码中文字幕-人妻丰满熟妇AV无码区影片资源-欧美av色爱综合网欧美av 亚洲va不卡在线-日本A级视频在线播放-亚洲国产精品无码中文字幕-久久无码高潮喷水-欧美老熟妇喷水-丰满巨臀大屁股BBw-JAPANESE55丰满熟妇-亚洲欧美日韩高清一区 久久爱在线播放视频-免费播放观看在线视频-卡通动漫图片-中文字幕熟女人妻一区二区-AV无码AV在线A∨天堂-欧美国产日产一区二区-人妻无码-人人澡人人播色屋av
        2021最新国产在线不卡A-国产精品专区第5页-亚洲图揄拍自拍另类图片-无码专区国产精品-欧美特黄三级免费视频-特级毛片A片全部免费-国产在线视精品在亚洲 免费A级毛片无码A∨-子夜精品视频在线-国产免费精品美女视频-免费人妻少妇精品-日韩人妻无码潮喷中文视频在线-欧美老妇牲交视频-无码少妇一级AV片在线观看 国产好大好硬好爽免费视频-香港三级片电影-免费韩伦影院在线观看-日本熟妇人妻高清无码视频-国产一级伦奷毛片未删减版-国产学生a片-AV爆乳无码专区-浓毛少妇a片 2021超清国产小视频-亚洲城人在线视频-国产乡下三级-人妻少妇精品无码专区无码-国产在线视频一区二区三区-2021中文一卡二卡三卡-国产在线精品亚洲一区 国产精品永久免费-单亲乱L仑视频在线观看-无码 人妻 在线视频-被公侵犯玩弄漂亮人妻-女人高潮抽搐潮.I喷视频-国产成年无码AV片在线观看-亚洲日本无码一区二区 久久爱视频-青青青国产费观看-成年片黄网站色大全男女-国产高清在线看AV片-av无码播放一级毛片免费-97人人超碰国产精品最新-亚洲乱码中文字幕综合-中国丰满熟妇av 120秒试看无码体验区-99国产免费-日本制服美女-中文字幕乱码免费-日韩成视频在线精品-久久婷综合五月-永久免费AV无码网站打屁股-国模无码视频一区 一个人看免费视频WWW-日本三级成本人网站-日本老熟妇无码色视频网站-AV天堂中AV世界中文在线播放-波多野结衣一区二区三区AV高清-成年美女黄网站色奶头大全 亚洲精品熟女国产-五月婷之久久综合丝袜美腿-女神高潮喷水正在播放-少妇人妻系列无码专区视频-亚洲人成网站18禁止-国产一级A片免费无码-av无码在线