分享
 
 
 

WindowsCE.Net下CAN卡的驱动程序设计

王朝c#·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

者:徐平 蒋健 张弘 来源:单片机及嵌入式系统应用 时间:2004年12月29日 0:35 阅读203次

摘要:主要讨论在WinCE设计和开发CAN卡通信程序的方法;详细介绍CAN卡底层驱动函数的设计和实现,同时将驱动进行封装,用动态库的方式提供给用户CAN卡通信用的驱动,使用启可以方便地在自己的程序中调用,实现WinCE下的CAN卡通信。

关键词:WinCE.NET CAN 驱动

引言

近年来电力行业为了快速部署变电站,采用了建造整体变电所的方法:在生产基地将变电站的内部设备安装、调试完成,只留下与外界的接口,整体运到变电站所在地后进行安装和简单调试即可投入运行。其内部设备通过CAN总线进行通信,系统原有的监控软件基于DOS系统,维护调试比较困难,因此想要寻求更方便、友好的系统支持。经过比较,嵌入式操作系统市场上风头正劲的Windows CE .NET成为最终选择。微软的最新产品Windows CE.NET提供了端对端的开发、调试手段,可以不拆卸设备的情况下通过Telnet登录到WindowsCE上进行调试和维护,其系统本身为嵌入式市场进行重新设计,包括创建一个基于WindowsCE的定制设备所需的一切。这样就需要将原来DOS下的程序移植到WindowsCE.NET下,但是各个硬件厂商目前还没有提供CAN通信卡在Windows CE.NET下的驱动,所以开发Windows CE.NET下的CAN卡驱动成为项目推行中的关键一环。

本文主要针对研华的双口CAN卡PCM3680进行分析,介绍在WindowsCE.ENT系统下进行底层设备驱动开发的方法并提供CAN通信的实例。

1 CAN总线通信协议及CAN通信卡介绍

CAN总线是德国Bosch公司20世纪80年代初为解决现代汽车中众多的控制与测试仪器之间的数据交换而开的一种串行数据通信协议。它是一种多主总线,废除了传统的站地址编码,而代之以对通信数据块进行编码。这种方法使网络内节点个数在理论上不受限制,扩展格式中的29位的标识码便可以定义2 29个不同的数据块。

在本项目中使用的是研华的PCM3680,这是一块嵌入式PC104的双口CAN总线通信卡;CAN控制器采用Philips的独立CAN控制器SJA1000芯片;CAN收发器采用Philips的P82C250,可以同时操作两个CAN网络,提供高达1Mb/s的传输速度。PCM3680支持很宽的中断范围:中断3、4、5、6、7、9、10、11、12、15,同时1000V的光电隔离提供系统高可靠性。在CAN卡通信中,要用到CAN控制器中的很多寄存器,各个寄存器的含义和作用可以参考控制芯片的说明书。图1列出驱动程序设计中用到最主要的寄存器结构。

2 CAN卡驱动底层函数设计

本方案设计CAN驱动是放在Windows CE操作系统的内核下层,

位于OEM adaptation layer(OAL)层的一个真正的驱动,而不是在主程序中的串口操作。在Windows CE的设备管理器可以看到CAN1和CAN2两个端口,并且可以查看其工作的正常与否和对其进行配置。如:中断号和I/O地址。

2.1 CAN卡寄存器读写函数

CAN卡的通信是通过操作CAN卡上的CAN控制器进行的。在CAN控制器中有很多寄存器,如控制寄存器、命令寄存器、状态寄存器、中断寄存器等,通过读写这些寄存器中的命令状态字可以检测和控制CAN卡的行为。在Windows CE.NET下,通过调用DOK中的API函数HalTranslateBusAddress,将CAN卡分配的物理地址映射为逻辑地址。这样各个寄存器对应的就是CAN卡基地址的偏移地址,因此,对寄存器的读写就转化为对内存地址的读写。下面是CAN卡寄存器的读写函数:

*在偏移量为off的地址读取一个字节的数据inline BYTE CANR(LPCAN_HW_OPEN_INFO hCan,DWORD off)

{

return hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr[off];

*将一个字节数据写到偏移量为off的地址中inline VOID CANW(LPCAN_HW_OPEN_INFO hCan,DWORD off,BYTE val)

{

hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr[off]=val;

}

参数LPCAN_HW_OPEN_INFO定义的是CAN卡的数据结构,其中成员lpMappeBaseAddr[0]表示的是映射后基地址,lpMappedBaseAddr[1]就是基地址+1的地址,对应CAN卡的寄存器是命令寄存器。通过上述两个函数可操作CAN卡上的所有寄存器。

2.2 CAN卡初始化

CAN卡的控制器比较复杂,在通信前必须确认硬件信息正确性、初始化各寄存器。初始化函数的基本流程如图3所示。

第一步,检查端口号和硬件信息的正确性,主要是CAN卡中断号是否有效。

第二卡,设置CAN卡默认参数:

CanCardConfigInfo CAN_DEFAULT_SETTING=

{0X00,0XFF,0X03,0X1C};/*设置默认波特率为125Kbps*/

DWORD dwThreadID =0;

PHYSICAL_ADDRESS phyAddr={hwInfo->dwIOBaseAddr *16,0 };

第三卡,用WinCE API函数LocalAlloc为CAN卡驱动中用到的数据结构分配缓冲区;通过HalTranslateBusAddress和MmMapIoSpace函数映射I/O地址,提供直接访问设备的虚拟地址:

if(!HalTranslateBusAddress(Isa,0,phyAddr,0,&phyAddr))

goto _ExitInit;

hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr=

(LPBYTE)MmMapIoSpace(phyAddr,CANCARDADDRLEN,FALSE);

if(!hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr)

goto _ExitInit;

如果分配内存或映射逻辑地址失败,则退出初始化程序,CAN卡初始化失败。

第四步,初始化读写属性、共享模式、读超时时间和第二个CAN口的基地址。

第五步,创建CAN卡事件和数据接收事件:hCan->lpCanHWInfo->hCanEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

hCan->lpCanHWInfo->hRecvMsgEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

第六步,初始化中断,如果CAN卡有复位请求就退出初始化程序。设置好中断后启动数据接收线程,设置线程优先级继续线程处理;最后配置CAN卡参数,进入正常运行状态。

2.3 CAN卡信息发送

CAN卡的信息发送分为两个步骤。在对CAN卡基本信息进行检查后,首先设置发送缓冲的ID号。CAN标准模式的ID号为11位,偏移地址10中存放的是ID号的高8位,偏移地址11的高3位存放的是ID号的低3位,剩下5位分别是RTR位(远程传送请求位)和数据长度。通过CANW函数将处理后的数据写入到相应的偏移地址,设置完相应的地址数据后,通过循环将偏移地址12~19的数据采集回来存到数组中。然后,设置CAN卡的传输请求为允许并不断侦测状态寄存器的变化,当传输缓冲满标志或传输结束标志为1时通出程序,完成一次数据采集。传输缓冲区的寄存器如表1所列。

表1

ID号

10

ID.10

ID.9

ID.8

ID.7

ID.6

ID.5

ID.4

ID.3

RTR,数据长度码

11

ID.2

ID.1

ID.0

RTR

DLC.3

DLC.2

DLC.1

DLC.0

数据1~8

12~19

数据

数据

数据

数据

数据

数据

数据

数据

表2

ID号

20

ID.10

ID.9

ID.8

ID.7

ID.6

ID.5

ID.4

ID.3

RTR,数据长度码

21

ID.2

ID.1

ID.0

RTR

DLC.3

DLC.2

DLC.1

DLC.0

数据1~8

22~29

数据

数据

数据

数据

数据

数据

数据

数据

CAN消息发送函数的实现如下:

BOOL CAN_SendMessage(LPCAN_HW_OPEN_INFO hCan,LPCanCardMessageBuflpMsg)

{

BOOL bSuc=FALSE;

ASSERT(hCan && lpMsg && lpMsg->dwMessageLen <=8); /*防错处理*/

if(0= =(hCan->dwAccessCode & GENERIC_WRITE))

return FALSE;

:: EnterCriticalSection(&hCan->lpCanHWInfo->

TransmitCritSec); /*进入临界区*/

BYTE byV=static_cast<BYTE>(1pMsg->dwMsgID>>3);

CANW(hCan,10,byV); /*设置ID值高8位*/

byV=static_cast<BYTE>=((lpMsg->dwMsgID & 7)<<5);

if(lpMsg->bRTR) byV|=0x10;

byV+=static_cast<BYTE>(lpMsg->dwMessageLen);

CANW(hCan,11,byV);/*设置ID值低3位、RTR及数据长度*/

for(UINT i=0;<lpMsg->dwMessageLen;++i)

{

CANW(hCan,12+i,lpMsg->byMsg[i]);

} /*采集数据*/

CANW(hCan,1,1);/*重置传输请求*/

while(TRUE)

{byV=CANR(hCan,2);

if(byV & 0X40) /*传输缓冲区满,退出*/

{break;}

if(byV & 0X8){ /*传输结束,正确返回退出*/

bSuc = TRUE;

break;}

}

::LeaveCriticalSection(&hCan->lpCanHWInfo->TransmitCritSec); /*离开临界区*/

return bSuc;

}

2.4 CAN卡信息接收

CAN卡的信息接收是发送的逆过程,当接收缓冲区标志为1时,表示缓冲区已满可以接收数据,将数据接收到数组后释放接收缓冲区,然后对接收到的数据进行分解并存储到CAN卡信息缓冲区的结构体。接收缓冲区的寄存器结构如表2所列。

CAN消息接收函数的实现如下:

BOOL CAN_RecvRecvMessage(LPCAN_HW_OPEN_INFO

HCan,OUT LPCanCardMessageBuflpMsg)

{……

if(CANR(hCan,2)&1){ /*判断接收缓冲区是否已满*/

for(UINT i=0;i<10;++i)

recvBuf[i]=CANR(hCan,20+i);/*将数据暂存到临时缓冲区*/

CANW(hCan,1,4); /*释放接收缓冲区*/

LpMsg->dwMsgID=recvBuf[0]<<3; /*取出ID的高8位*/

BYTE byV =recvBuf[1];

LpMsg->dwMsgID+=byV >>5;/*取出ID低3位,然后和高8位合并*/

LpMsg->bRTR =byV &0x10?TRUE:/*返回RTR状态*/

LpMsg->dwMessageLen = byV &0XF; /*返回数据长度*/

……

}

else

{++hCan->lpCanHWInfo->dwErrorMsgCount;}/*没有收到数据,错误计数加1*/

::LeaveCriticalSection(&hCan->lpCanHWInfo->

ReceiveCritSec); /*离开临界区*/

Return bSuc;

}

2.5 CAN卡事件处理

CAN卡事件处理函数是CAN卡驱动程序中很重要的部分。驱动设计要求具有消息通知的功能,当事件发生时及时捕获事件并进行消息处理。

下面是事件处理函数的实现:

staric DWORD WINAPI CAN_EventHanle(LPVOID lpParam)

{

ASSERT(lpParam);

LPCAN_HW_OPEN_INFO hCan=(LPCAN_HW_OPEN_INFO)lpParam;

CanCardMessageBuf bufMsg;

while(TEUE)

{ /*循环等待CAN卡消息产生,然后进行处理*/

::WaitForSingleObject(hCan->lpCanHWInfo->hCanEvent,0XFFFFFFFF);

if(hCan->lpCanHWInfo->bKillCanThread) break; /*若CAN线程已关闭则中断*/

if(CAN_RecvMessage(hCan,&hufMsg)){ /*正确接收数据后*/

CAN_RecvBufPush(hCan,&bufMsg);} /*将数据压入缓冲*/

BYTE byV=CANR(hCan,3); /*将3号寄存器读出然后立即写入*/

CANW(hCan,3,byV);/*能够获取每次中断*/

InterruptDone(hCan->lpCanHWInfo->lpCanObj->dwSysIrqt);

} /*本次中断结束,等待下次中断*/

return 0;

}

2.6 其它函数

为了提供更多的功能和更方便地使用CAN卡进行通信,在CAN卡驱动程序中还设计了一些函数如CAN_Config用CAN卡信息配置、CAN_RecvBufPop用于处理接收缓冲区、CAN_Reset用于复位CAN卡、CheckHWInfo用于硬件信息检查等。这些函数提供了对CAN通信卡的设置、检查等功能,在这里不再详述了。

3 CAN卡驱动封装设计

CAN卡底层驱动函数虽然功能完整,但是对于用户使用比较复杂并且一般用户不需要了解底层实现的机制。为了便于使用,最后对CAN卡的驱动进行了封装,提供CanOpenFile、CanSendMsg等五个函数用于CAN总线的通信,以动态连接库(DLL)的形式提供给用户调用。封装函数及功能如下:

*CanOpenFile;初始化并打开CAN卡的一个端口。

*CanCloseFile;关闭由CanOpenFile打开的CAN卡端口。

*CanRecvMsg;接收CAN卡数据,打开CAN卡时必须具有GENERIC_READ权限。

*CanSendMsg;通过CAN卡发送数据。打开CAN卡时必须具有GENERIC_WRITE权限。

*CanIOControl;设置或获取CAN卡I/O参数支持的I/O控制包括:IOCTL_CAN_CONFIG,IOCTL_CAN_RESET,IOCTL_CAN_TIMEOUT,IOCTL_CAN_SENDREADY,IOCTL_CAN_RECVREADY。

下面是CanSendMsg函数实现的代码:

BOOL CanSendMSg(

HANDLE hCan,

LPCanCardMessageBuflpMsg)

{

if(!hCan||INVALID_HANDLE_VALUE= =hCan||

!lpMsg||lpMsg->dwMessageLen>8)return FALSE;

return CAN_SendMessage(LPCAN_HW_OPEN_INFO)

hCan,lpMsg);

该函数就是通过封装CAN卡的底层驱动函数SendMessage来实现的,这样将功能集中的五个函数更方便了用户使用。

结语

程序开发的上位机是普通的PC机,软件环境是:Windows2000 Professional、Embedded Visual C++4.0、与下位机中WinCE.NET对应的SDK,该SDK是在用Platform Builder 4.0定制WinCE时编译生成的。下位机使用的硬件是研华的嵌入式PC104主板PCM3346N,操作系统为WinCE.ENT。

本文设计开发的驱动已经在北京怀柔的变电站项目中得到成功的应用,CAN卡通信稳定,系统在WINCE.NET下运行可靠,保证了项目的顺利实施。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有