2011年(96)
分类:
2011-05-30 17:21:07
摘 要:先容了CAN总线控制器SJA1000芯片,并给出用C51语言编写SJA1000总线控制器的初始化程序,方便使用者学习和把握。
关键词:SJA1000;CAN总线;C51;寄存器
0 引 言
随着自动化底层设备通讯的需要,使现场总线技术得到了迅速的发展,各厂家都纷纷推出自己的总线控制器。SJA1000 就是Philips公司推出的一种高性能的CAN总线控制器,它得到了广泛的应用,但是有关SJA1000初始化的文章比较少见,先容的程序也不完全,这给使用者增加了难度。为了方便使用者把握和使用CAN总线,本文作者成功地运用C51语言初始化SJA1000为核心的CAN总线控制器,缩短了程序开发周期,进步了工作效率。
1 SJA1000的新功能与内部结构
1.1 SJA1000的主要新功能
SJA1000是Philips公司早期CAN总线控制器PCA82C200的替换品,功能更强大,与PCA82C200相比,具有很多优点,详见文献[4].
1.2 SJA1000的内部寄存器
SJA1000的寄存器和管脚配置答应它使用于各种各样的集成的或分立的CAN 收发器,这使不同微控制器之间的接口能够被灵活运用。若要正确、灵活的运用SJA1000,就必须了解内部寄存器的地址、功能和作用。SJA1000内部寄存器的结构如表1所示(具体每一位的作用,请参阅文献[2]).
1.3 SJA1000与89C52的连线原理
为了连接到主控制器,SJA1000提供一个复用的地址/数据总线和附加的读/写控制信号,见图1.SJA1000能被看作外围存储器并为主控制器映射I/O设备。为了保证系统的同步,本电路使用了一个24 MHz的晶振作为SJA1000的振荡器,用它的7号引脚(CLKOUT)作为89C52的时钟脉冲。本文中SJA1000的片选由微控制器的P2.7口控制,其内部寄存器的地址由P0口和P2口共同来决定,P0口为低8位,P2口为高8位。
图1 原理接线图
表1 SJA1000内部主要寄存器
CAN地址 | 段 | 名 称 | 表示符号 |
0 | 控 制 | 模式寄存器 | MOD |
1 | 命令寄存器 | CMR | |
2 | 状态寄存器 | SR | |
3 | 中断寄存器 | IR | |
4 | 验收代码寄存器 | ACR | |
5 | 验收屏蔽 | AMR | |
6 | 总线定时0 | BTR0 | |
7 | 总线定时1 | BTR1 | |
8 | 输出控制 | OCR | |
9 | 测试 | TR | |
10 | 发 送 缓 冲 器 | 识别码(10-3) |
略三个方面对嵌进式Linux内核进行研究,并提出相应的进步实时性的方法。
3.1 微定时器
在分时系统中,定时器触发时钟中断,每个时钟中断是一次进程调度时机,Linux中每个时钟中断触发3个函数协同工作,共同完成进程调度过程,它们是:
(1)shedule()进程调度函数,根据当前调度策略从停当队列中选择下一个将被执行的进程;
(2)do_timer(),该函数是时钟中断服务程序的主要组成部分,被调用频率就是时钟中断频率;
(3)ret_from_sys_call()系统调用返回函数,当一个系统调用或中断完成时,该函数被调用处理一些扫尾工作。
可以看出,定时器频率直接影响到系统响应速度和上下文切换的系统开销。Linux的定时器提供10ms的调度粒度,对于很多实时系统来说,通常需要微秒级的定时器,故此调度粒度不满足系统响应速度要求。
在这方面,我们的解决办法是在硬件上提供一个细粒度定时器。但是,在这种情况下,不能再采用单模定时器,应选择多模定时器。原因如下:1、定时器频率太小,将极大地增加系统消耗,不论是否有事件产生调度需要,CPU总是频繁地被中断。2、一个实时系统并不要求系统在每一个微秒都产生中断,而是在任何一个微秒都能答应发生中断。因此在这种情况下,定时器的时钟频率不必固定,仅需设置为下一个事件要发生的时间,即一次模式。单模定时器只能使用于周期性较强的实时操纵系统中。
为平衡系统功能,应该采用具有一次模式和周期模式混合的细粒度定时器。在引进细粒度定时器后,我们在Linux系统中增加对定时器模式和粒度的控制函数,根据不同的实时应用的响应时间需要,选择不同定时器模式和粒度。从任务响应时间的角度出发,即可控制内核抢占时间(KPT).
3.2 双内核可抢占式体系结构
嵌进式实时操纵系统微内核是一般操纵系统的子集,担负着任务治理、任务控制、任务间的通讯,任务的同步与互斥、资源治理等诸多功能。在设计Linux内核体系结构时,我们采用双内核结构,见图1.其中,使用实时内核来运行实时任务,Linux内核来运行非实时任务。如,利用实时内核运行一个实时任务来完成数据采集,另一个实时任务完成控制输出功能;同时利用Linux内核上运行的图形界面来进行数据显示。
如图1,为解决Linux实现硬实时的最大障碍,使Linux内核为完全被抢占的采用混合内核方案,我们在嵌进式系统对Linux系统进行了如下修改:
(1)添加一个实时内核。由它治理中断,提供一些必要的功能,如底层服务创建、中断服务程序,并且为底层服务、ISR和Linux进程间的通讯排队。其中实时核优先级较高,而Linux核的优先级较低。
(2)对Linux内核进行修改和定制。首先,对Linux进行定制,即“瘦身”。嵌进式系统是以完成应用功能为目的,我们可以根据实际需要定制Linux.以设计一个数据采集器为例,其功能是对现场数据进行采集,并传送到上位机,而且要求各个数据采集器之间实现多点通讯。首先,根据该数据采集器的功能定
制Linux如下:在进程治理方面,由于数据采集和传送,即多点通讯均属于实时任务,为此我们设计进程调度时,采用可抢占式优先级调度,而且使采集和传送任务的优先级高于多点通讯;在设备方面,往掉声显卡等无关设备的功能支持,保持串口、并口等相关设备的支持;在存储治理方面,往掉虚拟存储功能;在文件系统方面,采用单一文件支持,无须多文件格式;在网络方面,无须服务器功能,只须保持数据的上传功能和采集器之间的对等通讯功能。其次,对已“瘦身”的Linux内核进行修改,主要有三方面:第一,在Linux内核中影响实时性能的地方增加控制点,使内核在控制点可以被抢占,减少内核抢占延迟;第二,将执行时间较长的系统调用划分为几个甚至十几个较小的块执行,使实时任务能随时中断非实时任务;第三,根据实际需要,增加部分功能。图1 双内核结构
在设计中,我们对实时要求强的应用编写成实时任务在实时内核上直接运行,而其它任务在Linux 内核运行。Linux内核由于优先级较低,可以随时被实时任务抢占。而所有的任务是运行在实时内核还是Linux内核均由实时内核来决定。在运行每一个任务时,首先判定任务的来源,如来自优先级较高的实时势件,则判定为实时任务,直接在实时内核中运行。如该任务是非实时任务,则交与Linux内核运行。这部分在下一节具体讨论。由于,嵌进式系统中的实时任务都是通过计算机接口进进系统的,因而,可以在硬件上固定每一个任务或任务子集的优先级,如通过 8259中断器来设计事件的优先级,当8259产生一个中断时,系统只是简单地在事件表中报告这一事件的发生,然后立即将对CPU的控制权交给实时内核,由其通过软件方法判定事件的属性及优先级,进而使之在相应的内核中执行,而不象一般Linux核心那样往查中断向量表并执行相应的中断服务程序。
可抢占式内核体系结构的设计中引进这种双内核设计方案,取得了较高的硬实时性能和丰富的系统调用支持。
3.3 实时系统调度策略
CAN_DEV can_chan_dev;
STATUS CanDrv(void){
完成驱动的一些初始化;
intconnect(); /*连接所选的IRQ与中断处理函数*/
sysIntEnablePIC(); /*486DX答应中断*/
drv_num=iosDrvInstall(CanOpen,NULL,CanOpen,CanClose,CanRead,CanWrite,CanIoctl);/*将设备驱动例程装进设备列表中*/
}
/*iosDrvInstall()将设备的CAN驱动例程加进设备驱动列表中,7个参数为7个驱动例程的进进点(entry point),假如没有某个例程,则传递NULL。*/
STATUS CanDevCreate(){
完成一些设备初始化
iosDevAdd (Can_chan_dev.pCANHDR,“can0”,drv_num);/*将设备放进设备驱动列表中*/
}
int CanOpen(CAN_DEV *pCan_Dev,UBYTE *remainder,int flags){
CAN卡硬件复位
CAN卡关中断
CAN卡进进软件复位模式
设置CAN卡工作寄存器,如接收码寄存器和屏蔽码寄存器等
CAN卡开中断和进进操纵模式
Return((int)pCan_Dev); /*留意必须返回设备描述结构指针*/
}
int CanRead(int CAN_DEV_ID,UBYTE * buf,int nBytes){
等待信号量(该信号量由中断处理例程开释)
从接收缓冲区读取数据
开释接收缓冲
返回接收数据数目
}
int CanWrite(int CAN_DEV_ID,UBYTE* buf,int nbyte){
查询发送缓冲是否可用
向发送缓冲区写数据
命令发送
查询发送完成标志
返回发送数据数目
}
void interrupt_handle_routin(int arg){
处理中断事件
发送(开释)信号量
}
限于篇幅,其它函数略。
5 CAN驱动调试
硬件驱动的调试是件十分麻烦的事,经验十分重要。这里扼要先容几个帮助调试的函数。
①可以调用iosDrvShow()、iosDevShow()及iosFdShow()查看相关内容,判定并将驱动及设备中进相应列表。
②使用logMsg()现实相关内容,以定位错误。
初期调试,示波器和信号灯是非常有用的,可以确定硬件的工作状况,从而有助于发现程序中的错误。
6 小结
笔者采用两种方式完成了CAN卡驱动。相对于第一种(笔者亦完成),第二种方式——VxWorks的I/O系统将设备程序作为内核过程实现,大大减少了系统的开销,实时性和可靠性有了很大的进步,并且为用户提供了同一的接口,使用十分方便。
开发驱动程序,辅助工具是非常有用的。Windows下的开发工具就比较多,而在 VxWorks下开发驱动的工具相对较少。Windriver是一款不错的开发工具,可以开发VxWorks下的驱动程序(也可以开发其它操纵系统下的驱动程序)。正确、熟练地使用这些辅助工具,会使开发工作事半功倍。
(
给主人留下些什么吧!~~
|