当前位置:文档之家› CAN总线的实现-SJA1000实例

CAN总线的实现-SJA1000实例

一、

以下是我做的CAN节点的测试程序, 实现两个节点传送数据,程序主要分三部分SJA1000 的初始化,接收数据,发送数据.

/****************************************************

**函数原型:bit Sja_1000_Init(void)

**功能:初始化SJA10000

**入口参数: 无

**返回值:

0:初始化成功

1:复位失败

2: 测试sja1000失败

3:设置失败

4:设置验收滤波器失败

5:设置波特率失败

*****************************************************/

unsigned char Sja_1000_Init(void)

{

bit s;

EA=0;

s=BCAN_ENTER_RETMODEL();

if (s==1) return 1;

s=BCAN_CREATE_COMMUNATION();

if (s==1) return 2;

s=BCAN_SET_OUTCLK(0xc0);//Pelican

if (s==1) return 3;

s=BCAN_SET_OBJECT(0xFF,0x4E,0x16,0x00,0xff,0x00,0x00,0x00);

if (s==1) return 4;

s=BCAN_SET_BANDRATE(CAN_BPS_1M);

if (s==1) return 5;

SJA_BCANAdr=REG_OCR ;

*SJA_BCANAdr=0x1a;

SJA_BCANAdr=REG_IER;

*SJA_BCANAdr=0x03;

s=BCAN_SET_CONTROL(0x08);

if (s==1) return 6;

EA=1;

return 0;

}

}

/********************************************************************

*函数原型: bit BCAN_SET_OUTCLK( unsigned char Clock_Out) *

*参数说明: *

* Clock_Out:存放时钟分频寄存器(CDR)的参数设置*

*返回值: *

* 0 ;设置成功*

* 1 ;设置失败*

*说明:设置SJA1000的时钟分频。该子程序只能用于复位模式

*******************************************************************/ bit BCAN_SET_OUTCLK(unsigned char Clock_Out)

{

SJA_BCANAdr=REG_CDR;

*SJA_BCANAdr=Clock_Out;

if(*SJA_BCANAdr != Clock_Out)

return 1;

else

return 0;

}

/******************************************************************** *函数原型: bit BCAN_SET_OBJECT(unsigned char BCAN_ACR0,BCAN_ACR 1,BCAN_ACR2,BCAN_ACR3, BCAN_AMR0, BCAN_AMR1, BCAN_AMR2, BCAN_AMR3 )

*参数说明: *

* BCAN_ACR(0-3):存放验收代码寄存器(ACR)的参数设置*

* BCAN_AMR(0-3):存放接收屏蔽寄存器(AMR)的参数设置*

*返回值: *

* 0 ;设置成功*

* 1 ;设置失败*

*说明:设置CAN节点的通讯对象,允许接收的报文,是由AMR和ACR共同决定的. *

********************************************************************/ bit BCAN_SET_OBJECT(unsigned char BCAN_ACR0,BCAN_ACR1,BCAN_AC R2,BCAN_ACR3,BCAN_AMR0,BCAN_AMR1,BCAN_AMR2,BCAN_AMR3) {

SJA_BCANAdr=REG_TxBuffer1;

*SJA_BCANAdr=BCAN_ACR0; //写入参数

SJA_BCANAdr=REG_TxBuffer2;

*SJA_BCANAdr=BCAN_ACR1;

SJA_BCANAdr=REG_TxBuffer3;

*SJA_BCANAdr=BCAN_ACR2;

SJA_BCANAdr=REG_TxBuffer4;

*SJA_BCANAdr=BCAN_ACR3;

//校验写入值

if(*SJA_BCANAdr != BCAN_ACR3) return 1;

SJA_BCANAdr=REG_TxBuffer5;

*SJA_BCANAdr=BCAN_AMR0; //写入参数

SJA_BCANAdr=REG_TxBuffer6;

*SJA_BCANAdr=BCAN_AMR1;

SJA_BCANAdr=REG_TxBuffer7;

*SJA_BCANAdr=BCAN_AMR2;

SJA_BCANAdr=REG_TxBuffer8;

*SJA_BCANAdr=BCAN_AMR3;

//校验写入值

if(*SJA_BCANAdr != BCAN_AMR3) return 1;

return 0;

}

/******************************************************************** ;*函数原型: bit BCAN_SET_BANDRATE(unsigned char CAN_ByteRate) * ;*返回值: *

;* 0 ;波特率设置成功*

;* 1 ;波特率设置失败*

;* *

;*说明:设置CAN控制器SJA1000通讯波特率.SJA1000的晶振必须为16MH z, *

;* 其它晶体的频率的值的波特率,需自己计算。该子程序只能用于* ;* 复位模式*

;******************************************************************/ bit BCAN_SET_BANDRATE(unsigned int CAN_ByteRate)

{

//将波特率的的预设值装入sja1000的总线定时器

SJA_BCANAdr =REG_BTR0;

*SJA_BCANAdr =CAN_ByteRate>>8; // 取CAN_ByteRate的高8位写入写入参数

//校验写入值

if(*SJA_BCANAdr !=(CAN_ByteRate>>8)) return 1;

SJA_BCANAdr=REG_BTR1;

*SJA_BCANAdr=CAN_ByteRate;

//校验写入值

if(*SJA_BCANAdr !=CAN_ByteRate) return 1;

return 0;

}

/********************************************************************

*函数原型: bit BCAN_SET_CONTROL(unsigend char CMD) *

*参数说明: 设置控制寄存器*

*******************************************************************/ bit BCAN_SET_CONTROL(unsigned char CMD)

{

unsigned char TempData;

SJA_BCANAdr=REG_CONTROL; //SJA_BaseAdr+0x00 控制寄存器

TempData= *SJA_BCANAdr;

*SJA_BCANAdr=CMD;

if (*SJA_BCANAdr == CMD)

return 0;

else

return 1;

}

/******************************************************************** *函数原型: bit BCAN_CREATE_COMMUNATION(void) *

*参数说明: 无*

*返回值: *

* 0 ; 表示SJA1000接口正常*

* 1 ; 表示SJA1000与处理器接口不正常*

*说明:该函数用于检测CAN控制器的接口是否正常*

*******************************************************************/ bit BCAN_CREATE_COMMUNATION(void)

{

SJA_BCANAdr=REG_TEST;

*SJA_BCANAdr=0xaa; //写入测试值

if(*SJA_BCANAdr == 0xaa)

return 0; //读测试正确

else

return 1;

}

/****************************************************************** *函数原型: bit BCAN_ENTER_RETMODEL(void) *

*参数说明: 无*

*返回值: *

* 0 ; 表示成功进入复位工作模式*

* 1 ; 表示不能进入复位工作模式*

* *

*说明: CAN控制器进入复位工作模式*

*******************************************************************/ bit BCAN_ENTER_RETMODEL(void) //置位复位请求

{

unsigned char TempData;

SJA_BCANAdr = REG_CONTROL;

TempData= *SJA_BCANAdr;

*SJA_BCANAdr=0x01; //置位复位请求

if((*SJA_BCANAdr&0x01) == 1)

return 0;

else

return 1;

}

/****************************************************

**函数原型:void ex0_int(void) interrupt 0 //using 1

**功能:中断接收函数

**入口参数: 无

**出口参数: RevceData[]数组

**说明: 当sja1000 收到正确的报文时,会产生int中断

*****************************************************/

void ex0_int(void) interrupt 0 //using 1

{

unsigned char tt;

SJA_BCANAdr=REG_INTERRUPT;

if((*SJA_BCANAdr)&0x01) //产生了接收中断

{

SJA_BCANAdr=REG_RxBuffer1;

tt=*SJA_BCANAdr;

if ((tt&0x40)!=0x40) //数据帧= 为远程帧

{

memcpy(REG_RxBuffer6,RevceData,8);

send_char_com(RevceData[1]);//以下代码是发送到串口

send_char_com(RevceData[2]);

send_char_com(RevceData[3]);

send_char_com(RevceData[4]);

send_char_com(RevceData[5]);

send_char_com(RevceData[6]);

send_char_com(RevceData[7]);

send_char_com(RevceData[8]);

}

BCAN_CMD_PRG(4);//释放SJA1000接收缓冲区

}

}

unsigned char BCAN_DATA_WRITE(unsigned char *SendDataBuf)

{

unsigned char temp;

SJA_BCANAdr = REG_STATUS;

temp=*SJA_BCANAdr;

if ((temp&0x08)==0) return 1; //上次发送未完成

if ((temp&0x04)==0) return 2; //发送缓冲区是否锁定

if ((temp&0x10)==0x10) return 3; //判断是否正在接收

SJA_BCANAdr = REG_TxBuffer1; //访问地址指向发送缓冲区1 memcpy(SJA_BCANAdr,SendDataBuf,13);

BCAN_CMD_PRG(0x03);

return 0;

}

bit BCAN_CMD_PRG(unsigned char cmd)

{

SJA_BCANAdr=REG_COMMAND; //访问地址指向命令寄存器*SJA_BCANAdr=cmd; //启动命令字

switch(cmd)

{

case TR_CMD:

return 0;

break;

case SRR_CMD:

return 0;

break;

case AT_CMD:

SJA_BCANAdr = REG_STATUS; //访问地址指向状态寄存器

if((*SJA_BCANAdr & 0x20)==0)//判断是否正在发送

return 0;

else

return 1;

break;

case RRB_CMD:

SJA_BCANAdr = REG_STATUS; //访问地址指向状态寄存器

if((*SJA_BCANAdr & 0x01)==1)

return 1;

else

return 0;

break;

case COS_CMD:

SJA_BCANAdr = REG_STATUS;

if((*SJA_BCANAdr & 0x02)==0)//判断清除超载是否成功

return 0;

else

return 1;

break;

default:

return 1;

break;

}

}

主程序部分:

void main(void)

{

unsigned char temptt,ss;

CS=0;

Init_Cpu();

EA=0;

//initialize Sja1000

ss=Sja_1000_Init();

if (ss!=0)//初始化失败

send_string_com("init fail!");

else

EA=1; //初始化成功,开中断RECOK=0;

send_data[0]=Send_CAN_Info_ID[0];

send_data[1]=Send_CAN_Info_ID[1];

send_data[2]=Send_CAN_Info_ID[2];

send_data[3]=Send_CAN_Info_ID[3];

send_data[4]=Send_CAN_Info_ID[4];

while(1)

{

SJA_BCANAdr = REG_STATUS;

temptt=*SJA_BCANAdr;

if ((temptt&0x40)==0x40)

{

Sja_1000_Init();

send_char_com(0xee);

}

if (RECOK==1)

{

RECOK=0;

SJA_BCANAdr = REG_STATUS;

temptt=*SJA_BCANAdr;

if((temptt&0x04)==0x04) //可以向发送缓冲器写数据

{

send_data[5]=Com_RecBuff[0];

send_data[6]=Com_RecBuff[1];

send_data[7]=Com_RecBuff[2];

send_data[8]=Com_RecBuff[3];

send_data[9]=Com_RecBuff[4];

send_data[10]=Com_RecBuff[5];

send_data[11]=Com_RecBuff[6];

send_data[12]=Com_RecBuff[7];

ss=BCAN_DATA_WRITE(send_data);

if (ss==0) //发送正常

send_char_com(0x11);

else

{

send_char_com(0xFF);

send_char_com(ss);

SJA_BCANAdr= REG_ECC;

send_char_com(*SJA_BCANAdr);

}

}

}

}

}

二、can总线通讯程序(c) sja1000

●nnyt原创经典,如需更多帮助,请联系我:136********(短信联系,QQ详谈) QQ: 531706356 Email:nnyt@https://www.doczj.com/doc/0015957922.html,

●本人同时提供can实验开发板给初学者

1 CAN控制器为SJA1000,驱动器为TJA1050,电源隔离;

2 提供详尽的源程序,可根据用户需求编写程序

#include //单片机头文件

#include //SJA存储器定义头文件

#include //SJA子程序文件

/*************************函数声明*******************************/

void Init_T0(void); //初始化单片机T0

void Sja_1000_Init(void); //初始化SJA

//******************************************************************* bit flag_sec; //发送命令标志

unsigned char data send_data[10],rcv_data[10];//发送和接收数组

unsigned char sec_data,second; //定时器记数变量,发送数据变量unsigned char data Tmod_data; //定时器T0工作方式变量unsigned char bdata flag_init; //中断寄存器数据保存变量sbit rcv_flag=flag_init^0; //接收中断标志

sbit err_flag=flag_init^2; //错误中断标志

sbit P2_0=P2^0;

sbit P3_4=P3^4;

sbit LED=P3^5; //指示灯

//***********************************************************

void ex0_int(void) interrupt 0 using 1 //外部中断0

{

SJA_BCANAdr=REG_INTERRUPT; //指针指向中断寄存器

flag_init=*SJA_BCANAdr; //保持中断寄存器值

}

//***********************************************************

void T0_int(void) interrupt 1 using 2 //定时器T0中断服务子程序

{

TR0=0; //关闭定时器T0

sec_data--; //秒计时变量减一

if(sec_data==0) //2.25秒时间到了吗?

{

sec_data=0x50; //重新赋值

TH0=0x80;

TL0=0x60;

flag_sec=1; //设置标志位

second++; //发送的数据加一}

TR0=1; //启动定时器T0

}

//************************************************************

void Init_T0(void) //初始化定时器0

{

Tmod_data=TMOD;

Tmod_data&=0xf0;

Tmod_data|=0x01;

TMOD=Tmod_data; //定时器T0工作方式设置TH0=0x80;

TL0=0x60; //定时器T0初值设置TR0=1; //开放定时器T0

sec_data=0x20; //记数值设置

second=0x00; //发送数据初始化清零

}

//***********************************************************

void Sja_1000_Init(void)

{

BCAN_ENTER_RETMODEL(); //进入复位

BCAN_SET_BANDRATE(0x0b); //800K

BCAN_SET_OBJECT(0xaa,0xff); //设置地址ID:557

BCAN_SET_OUTCLK(0xaa,0x48); //设置输出方式,禁止COLOCKOUT输出BCAN_QUIT_RETMODEL(); //退出复位模式

SJA_BCANAdr=REG_CONTROL; //地址指针指向控制寄存器*SJA_BCANAdr|=0x1E; //开放错误\接收\发送中断

}

//******************************************************************* void main(void)

{

P2_0=0; //SJA1000退出硬件复位模式

Sja_1000_Init(); //initialize Sja100

Init_T0(); //initialize T0

PX0=1; //外部中断0高优先级

IT0=1; //开放T0中断

EX0=1; //外部中断0开放

ET0=1; //开放外部中断0

EA=1; //开放全局中断

P3_4=0; //点亮指示灯

flag_init=0x00; //变量清零

while(1)

{

if(rcv_flag) //if there is receive interrupt

{

rcv_flag=0; //接收标志位清零

BCAN_DATA_RECEIVE(rcv_data); //接收数据

BCAN_CMD_PRG(0x04); //释放接收缓冲区}

if(flag_sec)

{

flag_sec=0; //发送位清零

send_data[0]=0xAA; //发送数据到ID为550的节点

send_data[1]=0x08; //发送数据帧,8个字节长度

send_data[2]=0x05; //第一个字节内容为数据05H

send_data[3]=second; //第二个字节内容为变量值

BCAN_DATA_WRITE(send_data); //发送数据

BCAN_CMD_PRG(0x01); //置位发送请求位

LED=~LED;

}

if(err_flag) //错误中断

{

err_flag=0; //错误标志位清零

Sja_1000_Init(); //初始化SJA

}

}

}

相关主题
文本预览
相关文档 最新文档