基于CAN总线的非智能适配卡设计
扫描二维码
随时随地手机看文章
引言 虽然目前PCI、USB等总线技术得到了快速发展,但在大量应用的测试微机及工控机中,用的最多的还是ISA (Industry Standard Architecture.工业标准体系结构)总线。ISA总线具有16位数据宽度,最高工作频率为8MHz,数据传输速率达到16MB/s,地址总线有24条,可寻址16MB的地址单元,其总线信号分为5类,分别为地址线、数据线、控制线、时钟线和电源线。 非智能型ISA总线CAN适配卡的总体结构 CAN控制器SJA1000的地址数据总线是分时复用的,通过ALE信号的下降沿可锁存总线上的地址信号;ISA总线上的地址和数据总线是单独提供的,它不能直接和SJA1000的地址数据总线相连。本设计利用地址译码电路来对地址信号线进行译码,从而为CAN适配卡分配出一定的端口地址。然后再利用74HC373芯片的数据锁存功能锁存第一次I/O操作中通过ISA数据总线传送的数据信号,以便作为访问CAN控制器SJA1000中寄存器的地址信号,最后在第二次I/O操作中完成对SJA1000中相应地址寄存器的读写操作。其适配卡的总体结构如图1所示。 | |||||
图1中,地址锁存器74HC373可看作SJA1000的地址端口,而SJA1000本身可看作SJA1000的数据端口,另外还有对SJA1000进行硬件复位的复位端口。图中的基地址译码电路以AEN作为使能信号,对A2~A9地址信号进行译码就可得到适配卡的基地址;组合AO和A1地址信号可得到各端口的偏移地址。SJA1000与ISA的通讯采用两次I/O操作的方法,第一次先往地址端口送地址,第二次再对数据端口进行访问。这里所说的地址及数据端口都是对SJAl000而言的,通过ISA总线的数据线可获得被访问的SJA1000寄存器的地址及所传送的数据。控制端口译码电路可将CPU送来的控制信号和地址信号按一定的逻辑关系进行组合,从而生成一组新的功能信号作为接口控制信号。通过SJA1000复位电路可对SAJ1000进行复位,具体操作可采用上电复位、程序复位及按键复位三种硬件复位方式。
适配卡硬件的设计 基地址译码电路设计 图2所示是一种具体的基地址译码电路。一般情况下,根据系统需要,地址译码电路可对ISA地址线的端口地址译码,并可用AO~A9来表示。基地址译码电路对A9~A2进行译码,则可作为卡上端口的基地址。 控制信号产生电路 计算机通过ISA总线对CAN控制器SJA1000进行读写的时序分别如图4和图5所示。 SJA1000正常工作前,只有通过复位引脚对其进行可靠的硬件复位,才能对SJA1000中的寄存器进行正确的读写操作。使SJA1000可靠复位的电平持续最小时间为0.1μs,PC系统复位电平持续时间可达几微秒。系统复位信号RESET在系统电源接通时为高电平,经反向器后可直接用于对SJA1000进行复位。图6所示是适配卡的复位电路,对SJA1000的复位具有开机上电复位、程序复位以及按键复位等三种方式。 适配卡的软件设计
实际上,只有在复位模式下才可以对SJA1000进行初始化,初始化主要包括工作方式的设置、接收滤波方式的设置、接收屏蔽寄存器和接收代码寄存器的设置、波特率参数设置和中断允许寄存器的设置等。完成初始化后,即可将SJA1000设置为工作状态,以进行正常的通信。发送子程序负责节点报文的发送。发送时,读取状态寄存器并对各位进行适当判断,并将待发送的数据按特定格式组合成一帧报文,送入SJA1000发送缓存区中,然后启动SJA1000发送;接收子程序则负责节点报文的接收以及其它情况的处理。在处理接收报文的过程中,还要对总线关闭、错误报警、接收溢出等情况进行处理。 CAN适配卡与计算机可采用中断方式通信。但在WIN API中不能直接控制中断,只有在操作系统底层为CAN适配卡编写虚拟设备驱动程序(VxD)才可以利用中断。这需要在虚拟设备驱动程序中将中断虚拟化,并在中断事件响应函数中编写所需代码,同时为应用程序提供访问接口。应当注意的是:计算机通过ISA总线对CAN适配卡上的SJA1000进行访问采用的是两次I/O操作,第一次往地址端口送地址,第二次对数据端口进行访问。其具体的实现代码如下: //向指定的SJA1000寄存器(地址为addr)写一个字节数据(data),CAN_BASE为基地址 void CanIRQ::writeByte(int CAN_BASE,unsigned char addr,unsigned char data) { _outp(CAN_BASE,addr); } unsigned char CanIRQ::ReadByte(int CAN_BASE,unsigned char addr) { unsigned char result; _outp(CAN_BASE,addr); } Bool CanIRQ::CanTrans(int CAN_BASE,unsigned char*pTransBuf) { status=ReadByte(CAN_BASE,SR); //SR为状态寄存器地址 for(i=0;i ptbuf++;pTransBuf++; } 结束语 |