图1 CAN总线节点系统框图
系统硬件设计
SJA1000独立CAN控制器是PHILIPS公司PCA82C200CAN控制器的替代产品,它是在完全兼容PCA82C200的基础上,增加了一种新的工作模式PeliCAN,SJA1000完全支持具有很多新特性的CAN2.0B协议。SJA1000的工作模式通过其内部的时钟分频寄存器中的CAN模式为来选择。SJA1000可以支持多种为处理器的时序特性,如Intel模式或Motorla模式,SJA1000与微处理器的接口非常简单,微处理器以访问外部存储器的方式来访问SJA1000。
TJA1050是控制器局域网CAN协议控制器和物理总线之间的接口,TJA1050可以为总线提供不同的发送性能,为CAN控制器提供不同的接收性能。TJA1050主要有以下特征:完全符合ISO 11898标准,最高速到达1Mb/s,输入级3.3V以及5V器件兼容,至少可以连接110个节点。本设计的微处理器为89C51负责初始化SJA1000及通过控制SJA1000实现数据的接收和发送等通信任务,系统电路图如图2所示。
图2 系统电路图
CAN控制器SJA1000的数据线AD0~AD7连接到51单片机的P0口,连接到基址为0xFA00的外部存储器片选信号,当访问地址0xFA00~0xFA31时,CPU可对SJA1000执行相应的读写操作。SJA1000的、、分别与51对应的引脚相连,接51的使51可以通过中断方式访问SJA1000。
系统软件设计
本设计的系统由4个节点组成,一个节点由上位机通过并口转CAN总线的数据收发器构成,另外3个节点由图2所示的单片机CAN总线收发系统构成。单片机系统每秒发送一帧(8个字节)数据。连接上位机的CAN总线收发器有相应的上位机测试软件支持,本文主要介绍单片机CAN总线收发器的程序设计。图3是下位机软件的流程图。
图3 下位机主程序流程图
系统设计的部分代码如下:
main()
{
Sja_1000_Init(); //初始化SJA1000
Init_Cpu(); //初始化CPU
Init_T0(); //初始化定时器
flag_init=0x00;
while(1)
{
if(rcv_flag) //rcv_flag为接受标志位,有接收则单片机进行处理
{
rcv_flag=0; BCAN_DATA_RECEIVE(rcv_data);
BCAN_CMD_PRG(0X04);
disp_rec();
}
if(flag_sec) //定时中断标志为,定时时间到则发送数据帧
{ flag_sec=0; send_data[0]=0xaa; send_data[1]=0x08; send_data[2]=DA1;
send_data[3]=DA2;
send_data[4]=DA3;
send_data[5]=DA4;
send_data[6]=DA5;
send_data[7]=DA6;
send_data[8]=DA7;
send_data[9]=DA8; BCAN_DATA_WRITE(send_data); BCAN_CMD_PRG(0X01);
}
if(err_flag)
{
err_flag=0;
disp_err();
Sja_1000_Init();
}
display(a); //循环显示接受数据
SJA1000的初始化过程包括申请进入复位状态,设置总线波特率,设置输出方式,开放错误中断、接受和发送中断。在进行数据发送时数据包前两个字节0Xaa、0X08为描述符,包括11位长的ID(标志符)\1位RTR\4位描述数据长度的DLC共16 位。BCAN_DATA_RECEIVE(rcv_data),为89C51对SJA1000的读数据函数其具体函数定义:
bit BCAN_DATA_RECEIVE(unsigned char *RcvDataBuf)
{
unsigned char TempCount;
SJA_BCANAdr = REG_STATUS; //访问地址指向状态寄存器
if((*SJA_BCANAdr&0x01)==0) //判断报文是否有效
{
return 1;
}
SJA_BCANAdr = REG_RxBuffer2; //访问地址指向接收缓冲区2
if((*SJA_BCANAdr&0x10)==0) //如果是数据帧
{
TempCount=(*SJA_BCANAdr& 0x0f)+2; //计算报文中数据的个数
}
else
{
TempCount=2;
}
SJA_BCANAdr = REG_RxBuffer1; //访问地址指向接收缓冲区1
memcpy(RcvDataBuf, SJA_BCANAdr,TempCount);//读取接收缓冲区的报文
return 0;
}
此函数仅限于CAN控制器接受数据,返回值如果为0表示接受成功,如果为1表示接受失败。
BCAN_DATA_WRITE(send_data)函数是89C51对SJA1000的写数据函数其具体定义如下:
bit BCAN_DATA_WRITE(unsigned char *SendDataBuf)
{
unsigned char TempCount;
SJA_BCANAdr = REG_STATUS; //访问地址指向状态寄存器
if((*SJA_BCANAdr&0x08) == 0) //判断上次发送是否完成
{
return 1;
}
if((*SJA_BCANAdr&0x04)==0) //判断发送缓冲区是否锁定
{
return 1;
}
SJA_BCANAdr = REG_TxBuffer1; //访问地址指向发送缓冲区1
if((SendDataBuf[1]&0x10)==0) //判断RTR,从而得出是数据帧还是远程帧
{
TempCount =(SendData Buf[1]&0x0f)+2; //输入数据帧
}
else
{
TempCount =2; //远程帧
memcpy(SJA_BCANAdr,SendDataBuf,TempCount);
return 0;
}
此函数将待发送的特定帧各式的数据,送入SJA1000发送缓存区中,然后启动,函数返回0表示将数据成功的送至发送缓冲区,返回1表示上一次的数据正在发送。
系统组网相对容易只需把各个节点挂在同一条双绞线上即可,启动上位机的CAN收发器,用来监视总线数据状态。每当启动一个下位机CAN收发器,上位机的测试软件就可以每隔一秒钟收到由同一CAN收发器发送的数据帧。实验结果显示当3台下位机CAN总线同时发数时数据接收端没有数据丢失和总线冲突现象。
结 语
现场总线有着巨大的发展潜力,它将给自动控制领域的变革带来深远的影响。我们设计的CAN总线收发器具有通用性,在本系统设计的基础上只需要相应的修改数据传输协议即可应用于各个CAN总线的数传系统。
参考文献:
1. 陈立元主编. Visual Basic实现串并行通信技术. 清华大学出版社,2001
2. 张学忠,王福成主编. Visual Basic控件应用编程实例教程. 北京希望电子出版社,2002
3. 马希荣主编. Visual Basic 6.0 程序设计. 机械工业出版社,2004
4. 彭禹皓. 基于单片机和CAN控制器的嵌入式系统. 微计算机信息,2007,4-2:33-35