WindowsCE.Net下CAN卡的驱动程序设计
摘要:主要讨论在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通信的实例。
javascript:window.open(this.src);" style="cursor:pointer;"/>
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操作系统的内核下层,javascript:window.open(this.src);" style="cursor:pointer;"/>位于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口