激情综合丁香-激情综合六月-激情综合婷婷亚洲图片-激情综合图区-激情综合网五月

低成本嵌入式Linux CAN應用方案

 2010-8-27             

        CAN(Controller Area Network)即控制器局域網,由于具有高性能、高可靠性以及簡單的網絡結構,在工業系統中越來越受到人們的重視,并迅速成為了目前國際上應用最廣泛的現場總線之一。

 

        英利嵌入式Linux工控主板EM9260是一款面向工業自動化領域的高性價比工控板,板上帶有標準CAN通訊接口。與板上其他標準通訊接口一樣,EM9260的CAN接口實現了相應的嵌入式Linux驅動程序,應用程序可以通過打開文件的進行讀寫的標準方式實現對CAN總線接口的數據通訊。本文側重于介紹CAN通訊方案。

 

硬件組成

 

EM9260嵌入式Linux工控板CAN總線示意圖

 

        EM9260嵌入式Linux工控板的CAN均采用了PHILIPS半導體公司的SJA1000T CAN總線控制器,SJA1000是一款獨立的控制器,主要用于汽車和一般工業環境中的控制器局域網絡(CAN)芯片,它是PHILIPS半導體PCA82C200 CAN控制器(BasicCAN)的替代產品,而且它增加了一種新的工作模式(PeliCAN),這種模式支持具有很多新特性的CAN 2.0B協議。

 

        EM9260的CAN通訊接口可提供高達1Mbps的數據傳輸速率,當采用5Kbps的的數據傳輸速率時其通訊距離最高可達到10KM。硬件的錯誤檢定特性也增強了CAN的抗電磁干擾能力,這給數據的遠程可靠傳輸提供了有利保證。

 

        EM9260的CAN通訊接口根據用戶的需要分為兩種:一種帶光電隔離,一種不帶光電隔離。帶光電隔離CAN總線通訊模塊的CAN收發器端的所有信號和電源與其它部分完全隔離,可承受至少1Kv(有效值)的電壓沖擊。光電隔離的功能可在EM9260的應用底板上來實現,英利公司在EM9260評估底板上提供了相應的參考電路。

 

CAN驅動接口函數

 

        1、CAN報文的幀格式簡介
        在CAN2.0B中存在兩種不同的幀格式,其主要的區別在于標識符的長度,具有11位標識符的幀稱為標準幀,而包括有29位標識符的幀稱為擴展幀。下面分別介紹數據幀的格式。

 

        1、CAN2.0B標準幀
        CAN標準幀信息為11個字節,包括兩部分:信息和數據部分。前3個字節為信息部分,如圖所示:

 

CAN2.0B標準幀

        注:1、字節1為幀信息。D7位表示幀格式,在標準幀中,FF=0;D6位表示幀的類型,RTR=0表示為數據幀,RTR=1表示為
                      遠程幀,在一般的數據通訊中,只使用數據幀;DLC表示數據幀實際的數據長度
                2、字節2、字節3為報文識別碼,11位有效
                3、字節4~字節11為數據幀的實際數據,遠程幀時無效

 

        2、CAN2.0B擴展幀
        CAN標準幀信息為13個字節,包括兩部分:信息和數據部分。前5個字節為信息部分,如圖所示:

 

CAN2.0B擴展幀

        注:1、字節1為幀信息。D7位表示幀格式,在擴展幀中,FF=1;D6位表示幀的類型,RTR=0表示為數據幀,RTR=1表示為
                      遠程幀;DLC表示數據幀實際的數據長度
                2、字節2~字節5為報文識別碼,29位有效
                3、字節6~字節13為數據幀的實際數據,遠程幀時無效

 

        2、CAN應用數據結構
        英利公司提供的基于嵌入式Linux下的CAN操作API函數,為了方便用戶的使用,結合目前常用的一些方法,對于CAN接口接收的數據報文采用了以下結構。

 

        struct can_frame
        {
                canid_t can_id; /* 用于定義CAN報文ID以及 EFF/RTR/ERR等標志 */
                __u8 can_dlc; /* 用于定義can報文數據包長度0-8 */
                __u8 data[8]; /* 用于定義can報文數據 */
        };

 

        其中的can報文ID為一個32 bit大小的結構,其中各個bit位定義如下:
        typedef __u32 canid_t;
                bit 0-28: CAN 報文的id(標準幀11bit/擴展幀為29bit).
                bit 29 : CAN報文錯誤幀標志(0 = data frame, 1 = error frame)
                bit 30 : CAN報文遠程幀標志( 1 = rtr frame )
                bit 31 : CAN報文幀格式標志 (0 = 標準幀, 1 = 擴展幀 )

 

        在進行CAN通訊時需要設置相關的參數,包括波特率、選取的數據濾波方式等,其中對于濾波器的設置,在濾波器的作用下,只有當接收報文中的標識位和驗收濾波器預定義的位值相等時,CAN控制器才允許將收到的報文存入RXFIFO中。為了方便使用,在英利公司的API函數中采用了一個struct accept_filter用來設置相關驗收濾波器的相關定義。

 

        struct accept_filter
        {
                unsigned int accept_code; /* 用于定義CAN報文驗收代碼位 32bit*/
                unsigned int accept_mask; /* 用于定義CAN報文驗收屏蔽位 32bit*/
                unsigned char filter_mode; /* 用于定義CAN報文濾波模式 */
        };

 

        3、CAN通訊接口API函數
        EM9260的系統內核中實現了CAN接口的驅動,實現CAN接口 open( ) / close() 、read( ) / write( )等函數操作。和在Linux下操作設備的方式和操作文件的方式一樣,調用open( )打開設備文件,再調用read( )、write( )對CAN接口進行數據讀寫操作。另外在此驅動程序的基礎上,封裝了一套簡單實用的API函數,以滿足對于CAN接口一些特殊參數設置的需要。各個函數的定義在can_api.h文件下,在該頭文件中對于各個API函數均有相應的中文說明。

 

        具體在進行應用程序開發時,首先調用CAN接口的open( )函數打開CAN接口:
        sprintf( portname, '/dev/em9x60_can%d', CanNo );
        m_fd = open(portname, O_RDWR |O_NONBLOCK );

 

        得到有效的文件描述符m_fd后,然后可調用can_api.h文件中定義的API函數對CAN接口進行相應的通訊參數設置:
        CAN_StartChip( m_fd );
        CAN_SetBaudRate( m_fd, baudrate );
        CAN_SetGlobalAcceptanceFilter( m_fd, AcceptanceFilter );

 

        再調用read( ) / write( ) 實現CAN數據的收發操作。

        4、CAN通訊接口的數據收發應用示例
        在英利公司提供的CAN方案中,CAN通訊的數據收發均采用的中斷方式,驅動程序中已自動完成了數據的收發,以及內部定義的CAN接收緩沖區和發送緩沖區的管理。對于用戶開發應用程序來說,只需要調用英創公司提供的CAN通訊API函數中的收發函數即可。本小節主要介紹一個CAN通訊的綜合應用示例程序。

 

        app_cantest是一個支持CAN數據通訊的示例,該例程采用了面向對象的C++編程,把CAN數據通訊作為一個對象進行封裝,用戶調用該對象提供的接口函數即可方便地完成CAN數據通訊的操作。

 

        // 定義CAN通訊類
        class EM9X60_CAN
        {
        private:
                // 通訊線程標識符ID
                pthread_t m_thread;
                // CAN接收線程
                static int ReceiveThreadFunc( void* lparam );
        public:
                EM9X60_CAN();
                virtual ~EM9X60_CAN();
                // 已打開的CAN文件描述符
                int m_fd;
                unsigned int m_canid;

                can_frame rxmsg;

                // 退出數據接收線程標志
                int m_ExitThreadFlag;

                // 按照指定的參數打開CAN接口,并創建CAN接口接收線程
                int OpenCAN( int CanNo, CAN_BAUDRATE baudrate, accept_filter *AcceptanceFilter );
                // 關閉接口并釋放相關資源
                int CloseCAN( );

                // 初始化設置CAN數據包id信息
                int InitCanIDInfo( struct CanIDInfo* pcanid );
                // CAN接口寫數據
                int WriteCAN( char* Buf, int len );
                // CAN接收數據處理函數
                virtual int PackagePro( char* Buf, int len );
        };

 

        OpenCAN 函數用于根據輸入參數打開CAN設備,并創建CAN數據接收線程。

        res = pthread_create( &m_thread, &attr, (void*)&ReceiveThreadFunc, (void*)this );

 

        ReceiveThreadFunc函數是CAN數據接收和處理的主要核心代碼,在該函數中調用select( ),等待串口數據的到來。對于接收到的數據處理也是在該函數中實現,在本例程中處理為簡單的數據回發,用戶可結合實際的應用修改此處代碼,修改PackagePro( )函數即可。流程如下:

 

CAN接口API函數流程圖

 

        int EM9X60_CAN::ReceiveThreadFunc(void* lparam)
        {
                EM9X60_CAN *pCAN = (EM9X60_CAN*)lparam;
                int len;

                // 定義讀事件集合
                fd_set fdRead;
                int ret;
                struct timeval aTime;

                while( 1 )
                {
                        // 收到退出事件,結束線程
                        if( pCAN->m_ExitThreadFlag )
                        { 
                                break;
                        }

                        FD_ZERO(&fdRead);
                        FD_SET(pCAN->m_fd,&fdRead);

                        aTime.tv_sec = 0; 
                        aTime.tv_usec = 30000;

                        ret = select( pCAN->m_fd+1,&fdRead,NULL,NULL,&aTime );

                        if (ret < 0 )
                        {
                                pCAN->CloseCAN( );
                                break;
                        }

                        if (ret >= 0)
                        {
                                // 判斷是否讀事件
                                if (FD_ISSET(pCAN->m_fd,&fdRead))
                                {
                                        len = read( pCAN->m_fd, (char*)&pCAN->rxmsg, sizeof(can_frame) );
                                        while( len > 0 ) 
                                        {
                                                // 對接收的數據進行處理,這里為簡單的數據回發 
                                                pCAN->PackagePro( (char*)&pCAN->rxmsg, len );
                                                // 處理完畢
                                                len = read( pCAN->m_fd, (char*)&pCAN->rxmsg, sizeof(can_frame) );
                                        }
                                }
                        } 
                }

                printf( 'ReceiveThreadFunc finished\n' );
                pthread_exit( NULL );
                return 0;
        }

 

        需要注意的是,select( )函數中的時間參數在Linux下,每次都需要重新賦值,否則會自動歸0。

主站蜘蛛池模板: 俄罗斯小younv| 国产一级黄色片子| 成人国产| 99久久国语露脸精品国产| 日韩乱视频| 在线观看亚洲精品国产| 国产精品福利视频主播真会玩 | 国产大乳喷奶水在线看| 欧美人在线视频| 午夜精品久久久久久99热7777 | 成人黄色片在线观看| 欧美国产一区二区三区| 国产成人啪午夜精品网站| 视频久久精品| 黄色一级在线| 强开小嫩苞一区二区三区l| 国产福利微拍精品一区二区| 精品五夜婷香蕉国产线看观看 | 九九天天影视| 日本一二区免费| 日韩亚洲欧美一区二区三区| 欧美日本韩国一区二区| 国产小视频2023| 国产肉丝在线| 国产麻豆自拍| 国产精品久久久久久久午夜片| 涩涩网站在线观看| 黄色录像一级毛片| 综合网在线| 麻豆精品传媒成人精品| 91短视频在线观看手机| 99精品久久秒播无毒不卡| 国产超薄肉色丝袜的免费网站| 青草视频在线观看国产| 手机看片日韩在线| 思思99| 亚洲国产精品xo在线观看| 亚洲人人视频| 亚洲女人性视频| 亚洲精品乱码电影在线观看| 亚洲欧美国产五月天综合|