英創(chuàng)ARM9系列嵌入式主板,如EM9000、EM9260均帶有(或可選)CAN總線接口,英創(chuàng)公司不僅提供了硬件平臺支持,還提供了CAN總線通訊驅(qū)動程序。本文主要介紹在基于Windows CE平臺的ARM9系列英創(chuàng)嵌入式主板下進(jìn)行C#(Microsoft Visual Stdio.Net 2005)CAN總線應(yīng)用程序開發(fā)時會常常用到的一些功能函數(shù)以及開發(fā)方法。
在英創(chuàng)嵌入式主板上進(jìn)行CAN編程的思路是:
(1)使用Win32的CreateFile方法(類似于傳統(tǒng)操作串口的模式)來獲得操作CAN總線端口的Handle。
(2)使用英創(chuàng)公司提供的CAN總線驅(qū)動程序動態(tài)鏈接庫CAN_API_DLL.dll實現(xiàn)一系列的CAN通訊操作,
包括:CAN_StartChip、CAN_SetBaudRate、CAN_SetGlobalAcceptanceFilter、CAN_GetNextReceivedFrame、CAN_SendFrame、CAN_StartChip等方法。
(3)使用Win32的CloseHandle方法關(guān)閉CAN操作的Handle。
在使用C#編程操作CAN通訊之前,首先要明確:很多底層操作的函數(shù)(如CreateFile函數(shù)),Visual Studio 2005.NET的API庫中并沒有提供,這個時候,我們就要在C#開發(fā)中調(diào)用Win32的函數(shù)來進(jìn)行相應(yīng)的操作。一大批Win32底層操作的函數(shù)都存在于cordll.dll動態(tài)鏈接庫中。
調(diào)用Win32的申明:
using System.Runtime.InteropServices;
要使用的兩個Win32函數(shù)申明如下:
[DllImport(’coredll.dll’)]
public static extern uint CreateFile(
string FileName, //file name
uint DesiredAccess, //access mode
uint ShareMode, //share mode
uint SecurityAttributes,// Security Attributes
uint CreationDisposition, //how to create
uint FlagsAndAttributes, //file attributes
int hTemplateFile //handle to template file
);
[DllImport(’coredll.dll’)]
static extern int CloseHandle(uint hDevice);
同樣,英創(chuàng)公司提供的驅(qū)動程序動態(tài)鏈接庫函數(shù)也需要進(jìn)行申明如下:
// 功能描述:讀取CAN設(shè)備接收數(shù)據(jù)包。
// 輸入?yún)?shù)hDevice: 已創(chuàng)建CAN流式設(shè)備的句柄。
// 輸出參數(shù)pRxFrameBuffer: 用于讀取CAN設(shè)備接收到的數(shù)據(jù)包。
// 返回值= TRUE: 從CAN設(shè)備接收到數(shù)據(jù),并將接收到的數(shù)據(jù)包讀入pRxFrameBuffer。
// = FALSE: CAN設(shè)備沒有接收數(shù)據(jù)。
[DllImport(’CAN_API_DLL.dll’, EntryPoint = ’?CAN_GetNextReceivedFrame@@YAHPAXPATMessageFrame@@@Z’)]
public static extern bool CAN_GetNextReceivedFrame(uint hDevice, byte[] RxFrameBuffer );
// 功能描述:通過CAN設(shè)備發(fā)送數(shù)據(jù)包。
// 輸入?yún)?shù)hDevice: 已創(chuàng)建CAN流式設(shè)備的句柄。。
// pTxFrameBuffer: 準(zhǔn)備通過CAN設(shè)備發(fā)送的數(shù)據(jù)包。
// 返回值= TRUE: 從CAN設(shè)備發(fā)送數(shù)據(jù)成功。
// = FALSE: 從CAN設(shè)備發(fā)送數(shù)據(jù)失敗。
[DllImport(’CAN_API_DLL.dll’, EntryPoint = ’?CAN_SendFrame@@YAHPAXPATMessageFrame@@@Z’)]
//public static extern bool CAN_SendFrame(uint hDevice, MessageFrame[] TxFrameBuffer);
public static extern bool CAN_SendFrame(uint hDevice, byte[] TxFrameBuffer);
// 功能描述:設(shè)置CAN設(shè)備通訊的波特率。
// 輸入?yún)?shù)hDevice: 已創(chuàng)建CAN流式設(shè)備的句柄。
// Index=CAN_TIMING_10K : 10Kbps
// CAN_TIMING_20K : 20Kbps
// CAN_TIMING_50K : 50bps
// CAN_TIMING_100K : 100bps
// CAN_TIMING_125K : 125Kbps
// CAN_TIMING_250K : 250Kbps
// CAN_TIMING_500K : 500bps
// CAN_TIMING_1000K: 1Mbps
// 返回值= TRUE: 波特率設(shè)置成功。
// = FALSE: 波特率設(shè)置失敗。
[DllImport(’CAN_API_DLL.dll’, EntryPoint = ’?CAN_SetBaudRate@@YAHPAXPAE@Z’)]
public static extern bool CAN_SetBaudRate(uint hDevice, byte[] index);
// 功能描述:設(shè)置CAN設(shè)備通訊接收過濾器配置。
// 輸入?yún)?shù)hDevice: 已創(chuàng)建CAN流式設(shè)備的句柄。
//AcceptanceFilter: 根據(jù)通訊報文格式定義過濾器的配置,定義為個字節(jié)的過濾器,其中前個字節(jié)用于定義過濾器的接收碼,
// 后個字節(jié)用于定義過濾器的接收屏蔽碼,最后一個字節(jié)用于定義選擇單/雙濾波模式。
// size: 定義的過濾器的大小。
// 返回值= TRUE: 配置設(shè)置成功。
// = FALSE: 配置設(shè)置失敗。
[DllImport(’CAN_API_DLL.dll’, EntryPoint = ’?CAN_SetGlobalAcceptanceFilter@@YAHPAXPAEE@Z’)]
public static extern bool CAN_SetGlobalAcceptanceFilter(uint hDevice, byte[] AcceptanceFilter, byte size);
// 功能描述:啟動CAN設(shè)備端口。
// 輸入?yún)?shù)hDevice: 已創(chuàng)建CAN流式設(shè)備的句柄。
// 返回值= NULL: 啟動CAN設(shè)備端口失敗。
// != NULL: 啟動CAN設(shè)備端口返回的句柄。
[DllImport(’CAN_API_DLL.dll’, EntryPoint = ’?CAN_StartChip@@YAHPAX@Z’)]
public static extern bool CAN_StartChip(uint hDevice);
// 功能描述:停止CAN設(shè)備端口。
// 輸入?yún)?shù)hDevice: 已創(chuàng)建CAN流式設(shè)備的句柄。
// 返回值= TRUE: 停止CAN設(shè)備端口成功。
// = FALSE: 停止CAN設(shè)備端口失敗。
[DllImport(’CAN_API_DLL.dll’, EntryPoint = ’?CAN_StopChip@@YAHPAX@Z’)]
public static extern bool CAN_StopChip(uint hDevice);
一、啟動CAN接口
啟動CAN接口一般只需要按順序進(jìn)行如下四個函數(shù)的調(diào)用:
CANhandle = CreateFile(strPort, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); //注意:strPort是一個字符串,定義CAN端口的名稱,如“CAN1:”或“CAN2:”
CAN_StartChip(CANhandle); //如下三個函數(shù)的定義請見上文注釋
CAN_SetBaudRate(CANhandle, BaudrateSerialno);
CAN_SetGlobalAcceptanceFilter(CANhandle, ACCFilter, 9);
注意:ACCFilter是一個長度為9的字符串?dāng)?shù)組,請在調(diào)用之前安裝相關(guān)設(shè)置進(jìn)行初始化。
二、數(shù)據(jù)發(fā)送
啟動CAN接口后,就可進(jìn)行CAN通訊了。CAN的數(shù)據(jù)幀分標(biāo)準(zhǔn)幀和擴(kuò)展幀兩種,其區(qū)別如下圖所示:
根據(jù)如上格式將發(fā)送的幀打包成byte數(shù)組后,即可通過如下函數(shù)進(jìn)行發(fā)送:
bResult = CAN_SendFrame(CANhandle, TxBuf); //bResult是bool變量判斷發(fā)送成功與否,TxBuff就是打包后的幀byte數(shù)組。
三、數(shù)據(jù)接收
可以通過在程序里設(shè)置一個Timer或直接啟動一個線程來監(jiān)視是否有CAN數(shù)據(jù)幀發(fā)送進(jìn)來,并進(jìn)行接收。在Timer啟動的事件函數(shù)或線程函數(shù)中使用如下函數(shù)接收數(shù)據(jù):
bResult = CAN_GetNextReceivedFrame(CANhandle, RxBuf); //bResult是bool變量判斷收到數(shù)據(jù)與否,TxBuff就是收到后的幀byte數(shù)組。
需要注意的是函數(shù)CAN_GetNextReceivedFrame每執(zhí)行一次,只是讀取了一幀CAN數(shù)據(jù)報文,而收到的數(shù)據(jù)可能往往有不止一幀,客戶應(yīng)當(dāng)在應(yīng)用程序中將最新的數(shù)據(jù)全部讀出,這個時候需要反復(fù)調(diào)用該函數(shù),直到該函數(shù)的返回值為false。
建議在接收幀的時候?qū)?shù)據(jù)先放到一個自定義的buffer中,然后在應(yīng)用程序的其它部分進(jìn)行處理,可以定義兩個全局變量:一個int類型存儲一次接收到幀的數(shù)量(如int mycount),一個較長的byte數(shù)組(或二維數(shù)組)作為自定義buffer存儲接收到的幀(如byte[,] myBuffer = new byte [20,13]。接收部分的示例代碼如下:
byte[] RxBuf = new byte[13];
byte dlen;
bool bresult = true;
mycount = 0;
while (bresult)
{
bresult = CAN_GetNextReceivedFrame(CANhandle, RxBuf);
if (bresult == false) return;
for (int j = 0; j < 13; j++)
{
myBuffer[mycount, j] = RxBuf[j];
}
Mycount ++;
}
收到數(shù)據(jù)后,可以通過判斷FrameInfo位的高位確定是標(biāo)準(zhǔn)幀還是擴(kuò)展幀,并獲得數(shù)據(jù)體的長度,進(jìn)而將數(shù)據(jù)分離出來進(jìn)行處理。
四、關(guān)閉CAN接口
關(guān)閉CAN接口一般只需要按順序進(jìn)行如下二個函數(shù)的調(diào)用即可實現(xiàn):
CAN_StopChip(CANhandle);
CloseHandle(CANhandle);
成都英創(chuàng)信息技術(shù)有限公司 028-8618 0660