英創(chuàng)ARM9系列嵌入式主板一大特色就是提供了CAN接口,并實現(xiàn)了相應的驅動程序,用戶只需直接調用CAN_API函數(shù)即可實現(xiàn)CAN數(shù)據(jù)報文的通訊操作。目前EM9000以及EM9X60系列板卡所提供的CAN接口均是采用的是SJA1000 CAN總線控制器,SJA1000是一款獨立的控制器,主要用于汽車和一般工業(yè)環(huán)境中的控制器局域網絡(CAN)芯片。CAN通訊接口可提供高達1Mbps的數(shù)據(jù)傳輸速率,當采用5Kbps的的數(shù)據(jù)傳輸速率時其通訊距離最高可達到10KM。硬件的錯誤檢定特性也增強了CAN的抗電磁干擾能力,這給數(shù)據(jù)的遠程可靠傳輸提供了有利保證。
硬件上來說,英創(chuàng)提供的CAN通訊接口根據(jù)用戶的需要分為兩種:一種帶光電隔離,一種不帶光電隔離。帶光電隔離CAN總線通訊模塊的CAN收發(fā)器端的所有信號和電源與其它部分完全隔離,可承受至少1Kv(有效值)的電壓沖擊。
軟件上英創(chuàng)出廠的帶有CAN通訊接口的ARM9板卡均帶有相應的驅動,基于WinCE系統(tǒng)配置了標準的WinCE流式驅動程序,基于Linux系統(tǒng)是將CAN接口配置為字符設備驅動程序。CAN通訊的數(shù)據(jù)收發(fā)均采用的中斷方式,驅動程序中已自動完成了數(shù)據(jù)的收發(fā),以及內部定義的CAN接收緩沖區(qū)和發(fā)送緩沖區(qū)的管理。
接收緩沖區(qū) |
發(fā)送緩沖區(qū) |
|
WinCE |
64k |
4k |
Linux |
64k |
4k |
為了方便用戶的使用,在CAN驅動程序的基礎上為客戶封裝了一套簡單實用的API函數(shù)。各個函數(shù)的定義在can_api.h文件下,在該頭文件中對于各個API函數(shù)均有相應的中文說明。本文將詳細介紹各個接口函數(shù)的使用。
1、CAN接口API函數(shù)定義
英創(chuàng)公司提供的CAN通訊接口的驅動程序采用標準的驅動程序,用戶可以用標準的打開文件、關閉文件的方式,來打開該CAN設備。相關的一些函數(shù)定義如下:
/*
* 功能描述:設置CAN控制芯片為操作模式。
* 輸入參數(shù):
* fd: CAN設備文件描述符
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_StartChip( int fd );
/*
* 功能描述:設置CAN控制芯片為復位模式。
* 輸入?yún)?shù):
* fd: CAN設備文件描述符
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_StopChip( int fd );
/*
* 功能描述:設置CAN通訊的波特率
* 輸入?yún)?shù):
* fd: CAN設備文件描述符
* Baud: 枚舉變量,分別對應不同的波特率
* CAN_BAUDRATE_10K = 0: 10Kbps
* CAN_BAUDRATE_20K = 1: 20Kbps
* CAN_BAUDRATE_50K = 2: 50Kbps
* CAN_BAUDRATE_100K = 3: 100Kbps
* CAN_BAUDRATE_125K = 4: 125Kbps
* CAN_BAUDRATE_250K = 5: 250Kbps
* CAN_BAUDRATE_500K = 6: 500Kbps
* CAN_BAUDRATE_1000K = 7: 1Mbps
* CAN_BAUDRATE_60K = 8: 60Kbps
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_SetBaudRate( int fd , CAN_BAUDRATE Baud );
/*
* 功能描述:設置CAN通訊驗收濾波器配置
* 輸入?yún)?shù):
* fd: CAN設備文件描述符
* *AcceptanceFilter: 驗收濾波器結構指針
* struct accept_filter
* {
* unsigned int accept_code;
* unsigned int accept_mask;
* unsigned char filter_mode;
* };
* accept_code: 濾波器接收碼
* accept_mask: 濾波器屏蔽碼
* filter_mode: 0-雙濾波器 1-單濾波器
*
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_SetGlobalAcceptanceFilter( int fd , accept_filter *AcceptanceFilter );
/*
* 功能描述:用于啟動或關閉CAN自檢測模式
* 輸入?yún)?shù):
* fd: CAN設備文件描述符
* Mode: 1-啟動自檢測模式
* 0-關閉自檢測模式,返回正常模式
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_SelfTest( int fd , int Mode );
/*
* 功能描述:獲取CAN通訊時的錯誤編碼
* 輸入?yún)?shù):
* fd: CAN設備文件描述符
* 輸出參數(shù):
* *ErrorPtr:錯誤編碼
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_GetError( int fd , DWORD *ErrorPtr);
/*
* 功能描述:獲取CAN通訊中相關統(tǒng)計數(shù)據(jù)以及CAN控制芯片的狀態(tài)寄存器值
* 輸入?yún)?shù):
* fd: CAN設備文件描述符
* 輸出參數(shù):
* *DriverStatistics:得到相應統(tǒng)計結構數(shù)據(jù)
* 返回值:
* 0: 成功
* <0: 失敗
*/
int CAN_GetCANDriverStatistics( int fd , drv_statistics *DriverStatistics );
在can_api.h中還定義了一個CAN驅動的統(tǒng)計數(shù)據(jù)結構struct DRIVERSTATISTICS,這個結構中記錄了CAN通訊的一些統(tǒng)計參數(shù),包括CAN中斷次數(shù),CAN數(shù)據(jù)幀發(fā)送成功統(tǒng)計次數(shù)等等。這些參數(shù)可通過API函數(shù)中CAN_GetCANDriverStatistics來獲取,這些參數(shù)可以作為分析CAN通訊的狀態(tài)的一個重要參考。以下為這些參數(shù)的定義。
typedef struct
{
DWORD NumISTEvents; // CAN中斷事件統(tǒng)計次數(shù)
DWORD NumRxDataFrameInt; // CAN數(shù)據(jù)幀接收中斷統(tǒng)計次數(shù)
DWORD NumRxDataFramePutRing; // CAN接收數(shù)據(jù)幀放入接收環(huán)形數(shù)據(jù)
// BUF的統(tǒng)計次數(shù)
DWORD NumTxDataFramePutRing; // CAN發(fā)送數(shù)據(jù)幀放入發(fā)送環(huán)形數(shù)據(jù)
// BUF的統(tǒng)計次數(shù)
DWORD NumTxDataFrameInt; // CAN數(shù)據(jù)幀發(fā)送中斷統(tǒng)計次數(shù)
DWORD NumTxSuccessful; // CAN數(shù)據(jù)幀發(fā)送成功統(tǒng)計次數(shù)
DWORD NumTxFailed; // CAN數(shù)據(jù)幀發(fā)送失敗統(tǒng)計次數(shù)
DWORD NumErrorWarningInt; // CAN通訊錯誤報警中斷的統(tǒng)計次數(shù)
DWORD NumErrorWarningLevel; // CAN通訊出錯的統(tǒng)計次數(shù),錯誤指至
// 少一個錯誤計數(shù)器滿或由錯誤報警限
// 制寄存器(EWLR)定義的CPU報警
// 限制
DWORD NumErrorPassive; // CAN通訊中錯誤消極中斷的統(tǒng)計次數(shù)
DWORD NumErrorBusOff; // CAN通訊錯誤中總線關閉錯誤的統(tǒng)計次數(shù)
DWORD NumSwitchedToNormalOperation; // CAN通訊中錯誤狀態(tài)切換到正常
// 狀態(tài)(總線開啟)的統(tǒng)計次數(shù)
DWORD NumOverrunInt; // CAN通訊中數(shù)據(jù)溢出中斷的統(tǒng)計次數(shù)
DWORD NumBusErrorInt; // CAN通訊中數(shù)據(jù)BUSOFF錯誤中斷的統(tǒng)計次數(shù)
DWORD NumArbitrationLostInt; // CAN通訊中仲裁丟失中斷的統(tǒng)計次數(shù)
DWORD MaxNumMsgsInRing; // CAN通訊中接收數(shù)據(jù)幀的數(shù)目
DWORD RXErrorCounter; // 讀取CAN通訊芯片中RX錯誤計數(shù)器的值
DWORD TXErrorCounter; // 讀取CAN通訊芯片中TX錯誤計數(shù)器的值
DWORD Status; // 讀取CAN通訊芯片中狀態(tài)寄存器的值
}DRIVERSTATISTICS;
2、CAN數(shù)據(jù)的接收和發(fā)送
在WinCE下,作為流式接口函數(shù)通常和文件系統(tǒng)的API函數(shù)(如CreateFile)緊密匹配的,因此在使用英創(chuàng)提供的CAN接口的API函數(shù)時,首先需要調用CreateFile(…)來獲取CAN接口設備的句柄handle,如使用CAN1通訊口,可以調用以下函數(shù):
m_hCAN=CreateFile(_T(“CAN1:”), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
在Linux下,調用的方式如下:
m_fd=open('/dev/em9x60_can1',O_RDWR | O_NOBLOCK );
在創(chuàng)建CAN設備得到有效的handle之后,就可以調用can_api.h中定義的相應函數(shù)來啟動CAN設備接口。
BOOL CAN_StartChip (HANDLE hDevice);
在進行CAN數(shù)據(jù)通訊之前,需要設置和CAN通訊相關的一些參數(shù),包括CAN通訊的波特率設置以及對接收過濾器的設置。
BOOL CAN_SetBaudRate(HANDLE hDevice, BYTE *index);
用于設置CAN通訊的波特率,波特率的設置范圍包括:10kbps~1Mbps。具體的定義請參見can_api.h文件中的注釋說明。
通過配置接收過濾器,CAN通訊接口可以實現(xiàn)只接收標識符也接收過濾器預設值相一致的報文。接收過濾器由接收碼寄存器ACRn和接收屏蔽碼寄存器AMRn來定義的,還可以選擇兩種不同的過濾器模式,單過濾器模式或者雙過濾器模式。關于ACR、AMR中各位的定義,請參見SJA1000的數(shù)據(jù)手冊,這里就不再贅述。在英創(chuàng)提供的API函數(shù)中,用戶可以調用以下函數(shù)來實現(xiàn)接收過濾器的設置:
BOOL CAN_SetGlobalAcceptanceFilter( HANDLE hDevice, BYTE *AcceptanceFilter, BYTE size)
對于CAN通訊數(shù)據(jù)接收線程可以采用兩種方式:一種可以采用定時查詢,即定時調用函數(shù)CAN_GetNextReceivedFrame( …)檢測是否有接收到CAN報文數(shù)據(jù);一種可以利用操作系統(tǒng)的消息機制,采用事件響應的方式,一旦硬件接收的數(shù)據(jù)報文,底層的驅動接收程序會自動讀取報文,同時發(fā)送一個接收事件。作為應用程序的接收線程在等待到該事件后,調用CAN_GetNextReceivedFrame(…)即可進行CAN數(shù)據(jù)報文的讀取。需要注意的是函數(shù)CAN_GetNextReceivedFrame每執(zhí)行一次,只是讀取了一幀CAN數(shù)據(jù)報文,如果在應用程序中需要將最新的數(shù)據(jù)全部讀出,只需反復調用該函數(shù),直到該函數(shù)的返回值為FALSE。
接收線程部分代碼:
DWORD CEM9000_CAN::ReadThreadFunc( LPVOID lparam )
{
CEM9000_CAN *ceCAN = (CEM9000_CAN*)lparam;
BOOL bResult;
while( 1 )
{
if(WaitForSingleObject(ceCAN->m_hReadCloseEvent,0 )==WAIT_OBJECT_0 )
{
break;
}
// 等待接收事件觸發(fā),使用以下代碼
WaitForSingleObject( ceCAN->m_hRxEvent, INFINITE );
// 若采用定時查詢,則調用Sleep(..)即可,Sleep的時間由應用程序確定
// Sleep( 50 );
ceCAN->m_nRxCounter = 0;
for( ; ; )
{
// 讀取已接收的所有數(shù)據(jù)幀
bResult=CAN_GetNextReceivedFrame(ceCAN->m_hCAN,&ceCAN->RxMFrame[ceCAN->m_nRxCounter] );
if( !bResult )
{
break;
}
ceCAN->m_nRxCounter++;
}
if(ceCAN->m_nRxCounter>0 )
{
// 調用回調函數(shù),進行必要的數(shù)據(jù)處理
ceCAN->OnRead( ceCAN->m_pCANOwner );
}
}
return 0;
}
CAN數(shù)據(jù)報文的發(fā)送比較簡單,應用程序直接調用函數(shù)CAN_SendFrame(…)即可,該函數(shù)的功能只是將需要發(fā)送的數(shù)據(jù)填入驅動的發(fā)送數(shù)據(jù)緩沖區(qū),真正的數(shù)據(jù)發(fā)送是由驅動程序中的發(fā)送線程自動完成的。若用戶需要查看數(shù)據(jù)是否發(fā)送成功,可以通過檢查驅動的相關統(tǒng)計數(shù)據(jù)DriversStatistics來判斷,其中NumTxSuccessful為CAN數(shù)據(jù)幀成功發(fā)送統(tǒng)計數(shù),每成功發(fā)送一次CAN數(shù)據(jù)幀,該計數(shù)值自動加1。
3、CAN通訊的出錯處理
在can_api.h文件對于CAN通訊所返回的錯誤代碼分別定義如下:
錯誤代碼 |
定義 |
CANCONTROLLER_NORMAL | 表明CAN通訊工作正常 |
CANCONTROLLER_WARNING_LIMIT_REACHED | 表明出錯,至少接收或發(fā)送錯誤計數(shù)器中的一個已達到或超過了由錯誤報警寄存器(EWLR)定義的報警限,缺省為96 |
CANCONTROLLER_ERROR_PASSIVE | 表明SJA1000達到錯誤消極狀態(tài),也就是說至少一個錯誤計數(shù)器超過規(guī)定值127 |
CANCONTROLLER_BUS_OFF | 表明該接口脫離總線 |
CANCONTROLLER_OVERRUN | 數(shù)據(jù)溢出錯誤 |
RING_BUFFER_FULL | 表明接收或發(fā)送緩沖區(qū)滿 |
錯誤代碼可通過API函數(shù)CAN_GetError(HANDLE hDevice, DWORD *ErrorPtr)來獲取。一般來說出現(xiàn)前面兩個錯誤:CANCONTROLLER_WARNING_LIMIT_REACHED和CANCONTROLLER_ERROR_PASSIVE,CAN通訊口還可恢復,一旦CAN接口成功接收或發(fā)送一幀數(shù)據(jù),CAN接口又可回到正常工作狀態(tài)。而對于出現(xiàn)其余的三項錯誤,我們建議在應用程序最好是做復位CAN接口的操作,即通過函數(shù)調用先關閉CAN口然后再重新初始化該接口。
在英創(chuàng)公司提供的應用光盤中有具體CAN接口的測試代碼,可供客戶參考測試。
-
Linux
+關注
關注
87文章
11326瀏覽量
209961 -
嵌入式主板
+關注
關注
7文章
6086瀏覽量
35476
發(fā)布評論請先 登錄
相關推薦
評論