用户可从英创开发光盘中或联系英创工程师获得CAN例程源码。参考例程使用英创已经封装好的.h及.cpp库文件可以使开发更方便。
注册表设置项说明
CAN驱动设置参数位于注册表[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\CAN1]及[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\CAN2]下
主要配置参数项:
TxTimeout :发送超时时间,单位ms。
BusErrorReport :错误帧上报标记,0:不上报,1:上报错误帧
设置程序可以连接英创工程师获得。
CAN打开及关闭
打开关闭采用标准的流式设备驱动接口CreateFile及CloseHandle,设备名为”CAN1:”及”CAN2:”
调用示例如下:
//打开CAN1
HANDLE hCan;
hCan = CreateFile( L”CAN1:”, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
//关闭CAN
CloseHandle(hCan);
CAN波特率设置
参考CAN例程,对驱动的DeviceIoCon trol操作已封装在SetBaud函数中。
BOOL SetBaud(HANDLE hCan, DWORD dwBaud)
参数hCan:CreateFile打开CAN返回的设备句柄
参数dwBaud:波特率,单位bps
返回值:TRUE 设置成功,FALSE 设置失败
调用示例如下:
//设置波特率250bps CAN
SetBaud(m_hCan, 250000);
CAN过滤设置
调用方法
参考CAN例程,对驱动的DeviceIoCon trol操作已封装在SetFilter函数中。
BOOL SetFilter(HANDLE hCan, PCAN_FILTER pFilter, DWORD num)
参数hCan:CreateFile打开CAN返回的设备句柄
参数pFilter:过滤器结构体数组指针
参数num:过滤器结构体数组长度,最大为4
返回值:TRUE 设置成功,FALSE 设置失败
注:此函数如果重复调用,生效的为最后一次调用设置值。
CAN_FILTER过滤器结构体定义
typedefstruct_can_filter
{
CAN_ID can_id;
CAN_ID can_mask;
} CAN_FILTER, *PCAN_FILTER
过滤器由id和mask组成,设置的过滤器组数最大4个。CAN包能满足其中一组过滤器以下条件才能接收
CAN包id & 过滤器mask = 过滤器id
即,2进制中,过滤MASK为1的对应位需和过滤ID值一致,示例表
调用示例如下
//设置一组寄存器
CAN_FILTER Filter[4];
memzero(Filter,sizeof(CAN_FILTER));
Filter[0].can_id.id = 5;
Filter[0].can_mask.id = 22;
SetFilter(m_hCan, Filter, 1);
CAN发送/接收
发送接收同样采用标准的流式设备驱动接口ReadFile及WriteFile
调用方法
参考CAN例程,封装好的函数定义。
int WriteCAN(HANDLE hCan, PCAN_FRAME pFrame, DWORD num){
DWORD dwLen;
if(!WriteFile( hCan, (char*)pFrame, num*sizeof(CAN_FRAME), &dwLen, 0 ))return0;
returndwLen/sizeof(CAN_FRAME);
}
int ReadCAN(HANDLE hCan, PCAN_FRAME pFrame, DWORD num){
DWORD dwLen;
if(!ReadFile( hCan, (char*)pFrame, num*sizeof(CAN_FRAME), &dwLen, 0 ))return0;
returndwLen/sizeof(CAN_FRAME);
}
参数hCan:CreateFile打开CAN返回的设备句柄
参数pFrame:帧结构体数组指针
参数num:帧结构体数组长度,默认值1,可空
返回值:发送/接收的数据包个数
注:发送函数为阻塞函数,超时时间可以在注册表中设置,默认1000ms。
发送失败后,应用程序应当自行判断是否需要重新发送。
接收函数应当单独开一个接收线程,并配合WaitCANEvent函数使用,参考下一节。
CAN_FRAME数据帧结构体定义
typedefstruct{
unsignedintid:29;
unsignedinterror:1;
unsignedintremote:1;
unsignedintextended:1;
}CAN_ID;
typedefstruct_can_frame
{
CAN_ID can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
BYTE can_dlc; /* frame payload length in byte (0 ..CAN_MAX_DLEN) */
BYTE data[CAN_MAX_DLEN];
} CAN_FRAME, *PCAN_FRAME;
调用示例如下:
DWORD dwNum;
//发送
CAN_FRAME Sendframe;
memzero(Sendframe,sizeof(CAN_FRAME));
Sendframe.can_id.id = 6;
m_Sendframe.data[0] = 0x01;
m_Sendframe.can_dlc = 1;
dwNum = WriteCAN(hCan, &Sendframe);
//接收
CAN_FRAME Revframe[MAX_ARRAY];
dwNum = ReadCAN(hCan, Revframe, MAX_ARRAY);
WaitCANEvent函数使用
如果轮询方式接收CAN包,系统负荷会过高,采用事件方式事半功
WaitCANEvent为等待CAN接收事件的阻塞函数,通过返回值可以判断是否有CAN数据接收。
BOOL WaitCANEvent( HANDLE hDevice, LPDWORD lpEvtMask, DWORD dwTimeout )
参数hDevice:CreateFile打开CAN返回的设备句柄
参数lpEvtMask:返回事件类型,新驱动目前恒为0
参数dwTimeout:超时时间
返回值:FALSE 等待超时,TRUE 有数据帧收到
接收线程调用示例
//主线程中开启接收线程
m_hRecvThread = CreateThread(0, 0, RecvTread,this, 0, NULL);
//接收线程函数定义
DWORD Ctest_can_v2Dlg::RecvTread(LPVOID lparam)
{
Ctest_can_v2Dlg* pDlg = (Ctest_can_v2Dlg*)lparam;
DWORD dwEvtMask;
int num;
CAN_FRAME rbuf[MAX_ARRAY];
while(!pDlg->m_bThreadStop)
{
if(WaitCANEvent(pDlg->m_hCan, &dwEvtMask, 200))
{
if( dwEvtMask == 0 ) // 接收到数据包
{
num = ReadCAN(pDlg->m_hCan, rbuf, MAX_ARRAY);
while( num )
{
OnRecv(pDlg, rbuf, num); //调用回调函数处理数据
num = ReadCAN(pDlg->m_hCan, rbuf, MAX_ARRAY);
}
}
else //258
{
}
}
}
return0;
}
错误帧定义
当设置注册表选项,允许接收错误帧后,CAN总线上的出错信息将以帧的形式上报上来。
错误帧的帧结构体中,值为1,可通过该值判断是接收到的数据帧还是驱动上报的错误帧。
if(Frame.can_id.error){
//错误帧
}
else{
//数据帧;
}
错误帧详细定义,请参数手册《CAN错误帧定义》。
精简掉的接口
新CAN驱动能够自动复位CAN总线,不需要再手动复位,所以之前ResetCAN,StartCAN,StopCAN精简掉了。
SetCANLoop功能实用性不大,故精简掉。
但是为了兼容老驱动,这些函数依然可以正常调用。
相关测试例程可以联系英创工程师获得。
全部0条评论
快来发表一下你的评论吧 !