CAN总线SJA1000测试程序
//********************************************************************
//SJA1000测试程序
//在8位单片机P89LPC922上测试通过
//串口转CAN:内部时钟7.373MHz,串口115200,can口20k
//协议:1、8位数据为1帧,是数据转发,双向
// 2、DB,01,目的地址,XX,XX,XX,0D,0A 改目的地址
// 3、DB,02,验收码 ,XX,XX,XX,0D,0A 改验收码
// 4、DB,03,验收屏蔽,XX,XX,XX,0D,0A 改验收屏蔽
// 5、DB,04,BTR0,BTR1,XX,XX,0D,0A 改波特率
//编写日期:2010.06.18
//********************************************************************
#include<reg932.h> //单片机头文件
#include"sja.h"
unsigned char RBuf[8]; //接收区
unsigned char CBuf[8]; //发送区
unsigned char CL; //计数
unsigned char num; //
unsigned char Inp; //串口接收计数
unsigned char Num2; //串口延时计数
bit Fir=0; //数据头标志,1-头
unsigned char ACN=0x00; //验收码
unsigned char AMN=0x00; //验收屏蔽
unsigned char TBN=0x00; //目标地址
unsigned char BTR0N=0x4E; //波特率,20k
unsigned char BTR1N=0x2F;
//--------------------------------------------------------------------
//io_init:初始化IO子程序
//--------------------------------------------------------------------
void io_init(void)
{
P0M1=0x00; //P0准双向
P0M2=0x00;
P1M1=0x00; //P1准双向
P1M2=0x00;
P3M1=0x00; //P3准双向
P3M2=0x00;
}
//-------------------------------------------------------------------
//TIMER_init:初始化定时器
//-------------------------------------------------------------------
void TIMER_init(void)
{
TMOD=0x11; //定时器0和1配置为模式1
TAMOD=0x00;
// ET0=1; //允许定时器0中断
TH1=0xB7; //5ms,根据波特率和单片机计算出
TL1=0xFF;
ET1=1; //允许定时器1中断
TR1=1; //打开定时器1
}
//--------------------------------------------------
//UART_init:初始化UART
//--------------------------------------------------
void UART_init(void)
{
SCON=0x50; //串口模式1,接收使能
SSTAT=0x00; //组合中断使能,停止位产生中断
BRGCON=0x00; //关闭BRG
BRGR0=0x30; //设置波特率为115200
BRGR1=0x00;
BRGCON=0x03; //允许BRG
ES=1; //允许串口中断
}
//------------------------------------------------------------------
//main:主函数
//------------------------------------------------------------------
void main(void)
{
io_init(); //端口初始化
TIMER_init(); //定时器0初始化
UART_init();
SJA_init(ACN,AMN,BTR0N,BTR1N);
IT1=1; //外部中断1下降沿有效
EX1=1; //外部中断1有效
IP0H=0x16; //定时器0中断和外部中断1优先级设高3
IP0=0x0E; //通信中断优先级设高2
IP1H=0; //定时器1中断优先级设高1
IP1=0; //键盘中断优先级设高0
EA=1;
while(1); //
}
//-------------------------------------------------------------------
//Timer1Int:定时中断子程序,通信间隔判断,5ms
//-------------------------------------------------------------------
void Timer1Int(void) interrupt 3
{
TH1=0xB7; //5ms,根据波特率和单片机计算出
TL1=0xFF;
Num2++; //超时计数
if(Num2>4)Fir=0;
}
//-------------------------------------------------------------------
//ComInt:通信中断子程序,接收串口数据,发送到CAN口
//-------------------------------------------------------------------
void ComInt() interrupt 4
{
unsigned char IND; //临时量
unsigned char i; //循环量
if(RI) //有输入数据,执行以下程序,发送中断不响应
{
IND=SBUF; //读入数据
RI=0;
Num2=0;
if(!Fir)
{
Fir=1; //新数据
Inp=0; //清零
RBuf[Inp]=IND;
}
else
{ //数据
Inp++; //数据位置加1
RBuf[Inp]=IND; //保存数据
if(Inp==7)
{
Fir=0; //8位数据
if(RBuf[0]==0xDB&&RBuf[6]==0x0D&&RBuf[7]==0x0A) //命令处理
{
if(RBuf[1]==0x01) TBN=RBuf[2]; //改目的地址
if(RBuf[1]==0x02) ACN=RBuf[2]; //改验收码
if(RBuf[1]==0x03) AMN=RBuf[2]; //改验收屏蔽
if(RBuf[1]==0x04) //改波特率
{
BTR0N=RBuf[2];
BTR1N=RBuf[3];
}
SJA_init(ACN,AMN,BTR0N,BTR1N); //重新初始化
}
else //发送数据
{
SJA_write(TransBuffer1,TBN); //目的地址
SJA_write(TransBuffer2,0x08);
for(i=0;i<8;i++) //写发送缓冲区
{
SJA_write(TransBuffer3+i,RBuf[i]);
}
SJA_write(CMR,0x01); //发送
}
}
}
}
}
//-------------------------------------------------------------------
//Int1Int:外部中断子程序,接收CAN总线数据并发送到串口
//-------------------------------------------------------------------
void Int1Int(void) interrupt 2
{
unsigned char tmp; //临时量
tmp=SJA_read(IR); //读中断寄存器
tmp&=0x01;
if(tmp==0x01) //判断是接收中断
{
for(tmp=0;tmp<8;tmp++)
{
CBuf[tmp]=SJA_read(RxBuffer3+tmp); //读缓冲器数据
SBUF = CBuf[tmp]; //发送数据到串口
while(TI==0);
TI = 0;
}
SJA_write(CMR,0x04); //清缓冲器,等下次数据来
}
}
/*CAN 总线SJA1000寄存器地址定义(用的是PeliCAN 模式,扩展帧EFF 模式)*/
#include<reg932.h> //单片机头文件
#include"sja.h" //
//-----------------------------------------------------------------
//SJA1000读
//参数:寄存器地址addr
//返回:读取到数据
//-----------------------------------------------------------------
unsigned char SJA_read(unsigned char addr)
{
unsigned char dat;
ALE=1;
P0=addr;
ALE=0;
P0=0xFF;
CS=0;
RD=0;
dat=P0;
RD=1;
CS=1;
return dat;
}
//-----------------------------------------------------------------
//SJA1000写
//参数:寄存器地址addr,待写入数据dat
//返回:无
//-----------------------------------------------------------------
void SJA_write(unsigned char addr,unsigned char dat)
{
ALE=1;
P0=addr;
ALE=0;
CS=0;
WR=0;
P0=dat;
WR=1;
CS=1;
}
//-----------------------------------------------------------------
//SJA1000初始化
//参数:验收代码AC,验收屏蔽AM,波特率参数BTO\BT1
//返回:无
//-----------------------------------------------------------------
void SJA_init(unsigned char AC,unsigned char AM,unsigned char BT0,unsigned char BT1)
{
unsigned int i;
unsigned char c;
RESET=0;
ALE=0;
WR=1;
RD=1;
CS=1;
INT=1;
for(i=0;i<8000;i++);
RESET=1;
SJA_write(CDR,0x40); //时钟分频寄存器,默认0x40(BasicCAN) PeliCAN 模式0xC0
c=SJA_read(IR); //中断寄存器
SJA_write(CR,0x61); //进入复位模式
SJA_write(OCR,0xFA); //输出控制寄存器,默认0xfa
SJA_write(BTR0,BT0); //波特率设置 20kHz
SJA_write(BTR1,BT1); //BTRO=0x0E,SJW=1,BTR1=0x2F,SAM=0单倍
SJA_write(ACR,AC); //验收代码寄存器
SJA_write(AMR,AM); //验收屏蔽寄存器
SJA_write(CR,0x06); //进入工作模式,使能发送、接收中断
}
//SJA1000测试,BasicCAN模式
//模拟时序选intel模式
//sja.h
#ifndef __SJA_H__
#define __SJA_H__
#define CR 0x00 // 控制寄存器地址
#define CMR 0x01 // 命令寄存器地址
#define SR 0x02 // 状态寄存器地址
#define IR 0x03 // 中断寄存器地址
#define ACR 0x04 // 验收码寄存器地址
#define AMR 0x05 // 验收屏蔽寄存器地址
#define BTR0 0x06 // 总线定时寄存器0地址
#define BTR1 0x07 // 总线定时寄存器1地址
#define OCR 0x08 // 输出控制寄存器地址
#define TR 0x09 // 测试寄存器地址
#define TransBuffer1 0x0a // 发送缓冲器
#define TransBuffer2 0x0b
#define TransBuffer3 0x0c
#define TransBuffer4 0x0d
#define TransBuffer5 0x0e
#define TransBuffer6 0x0f
#define TransBuffer7 0x10
#define TransBuffer8 0x11
#define TransBuffer9 0x12
#define TransBuffer10 0x13
#define RxBuffer1 0x14 // 接收缓冲器
#define RxBuffer2 0x15
#define RxBuffer3 0x16
#define RxBuffer4 0x17
#define RxBuffer5 0x18
#define RxBuffer6 0x19
#define RxBuffer7 0x1a
#define RxBuffer8 0x1b
#define RxBuffer9 0x1c
#define RxBuffer10 0x1d
#define CDR 0x1f // 时钟频分寄存器
//管脚定义:PO数据
sbit RESET=P1^3; //复位
sbit INT=P1^4; //中断
sbit ALE=P3^0; //写地址使能
sbit RD=P1^6; //写数据
sbit WR=P1^7; //读数据
sbit CS=P3^1; //片选
unsigned char SJA_read(unsigned char addr); //SJA读
void SJA_write(unsigned char addr,unsigned char dat); //SJA写
void SJA_init(unsigned char AC,unsigned char AM,unsigned char BT0,unsigned char BT1); //SJA初始化
#endif