调试好的can(汇编及C语言)程序,与大家分享!
//************************************程序功能***************************************************
//节点1向CAN节点2发送数据,数据的头两个字节分别是:节点1的ID和要求节点2回复的数据长度
//节点2收到节点1的信息后,立即按照节点1的要求回复数据
//************************************************************************************************
#include
#include //SJA存储器定义头文件
#include //SJA子程序文件
#include //显示头文件
#include//字符串函数
//***************************头文件***************************************************//
void Init_Cpu(void);//初始化单片机
void Sja_1000_Init(void);//初始化SIA
//************************************************************************************
bit s;//配置sja标志
bit flag_send;//发送命令标志
unsigned char data a[5]={0x05,0x05,0x05,0x05,0x05}; //显示"5"
unsigned char b[5]={0x12,0x12,0x12,0x12,0x12};//显示"p"
unsigned char c[5]={0x01,0x01,0x01,0x01,0x01};//显示"1"
unsigned char datasend_data[10],rcv_data[10];//发送和接收数组
unsigned char bdata flag_init;//保存中断寄存器值
unsigned int count_k;//延时记数用
sbit rcv_flag=flag_init^0;//接收中断标志
sbit err_flag=flag_init^2;//错误中断标志
//***********************************************************************************//
void main(void)
{
s=0;//配置sja1000出现错误时,重新初始化
do{
Sja_1000_Init();
}while(s!=0);
Init_Cpu();//initialize mcu
flag_init=0x00;//保存中断寄存器值清零
while(1)
{
if(rcv_flag)//if there is receive interrupt
{
rcv_flag=0;//接收标志位清零
BCAN_DATA_RECEIVE(rcv_data);//接收数据
BCAN_CMD_PRG(RRB_CMD);//释放接收缓冲区
flag_send=1;//发送命令置位
}
if(flag_send)
{
flag_send=0;//发送位清零
send_data[0]=rcv_data[2];//接收到的"发送方ID10~ID3"
send_data[1]=rcv_data[3];//接收到的"发送方ID2~ID0"和要求的数据长度
send_data[2]=0x88;
send_data[3]=0x89;
BCAN_DATA_WRITE(send_data);//发送数据
BCAN_CMD_PRG(TR_CMD);//置位发送请求位
for(count_k=0;count_k<200;count_k++)
display(a);//延时显示"5"
}
if (err_flag)//错误中断
{
for(count_k=0;count_k<280;count_k++)
display(c);//错误显示"1"
err_flag=0;//错误标志位清零
Sja_1000_Init();//初始化SJA
}
display(b);//显示"p"
}
}
void ex0_int(void) interrupt 0 using 1//外部中断0
{
SJA_BCANAdr=REG_INTERRUPT;//指针指向中断寄存器
flag_init=*SJA_BCANAdr;//保持中断寄存器值
}
void Init_Cpu(void)//单片机初始化,开放外部中断0
{
PX0=1;
EX0=1;
EA=1;
}
void Sja_1000_Init(void)
{
s=BCAN_CREATE_COMMUNATION();//SJA自测
s=BCAN_ENTER_RETMODEL();//进入复位
s=BCAN_SET_BANDRATE(0x04);//设置波特率100K/S
s=BCAN_SET_OBJECT(0xaa,0x00); //设置地址ID:550
s=BCAN_SET_OUTCLK(0xaa,0x48); //设置输出方式,禁止COLOCKOUT输出
s=BCAN_QUIT_RETMODEL();//退出复位模式
SJA_BCANAdr=REG_CONTROL;//地址指针指向控制寄存器
*SJA_BCANAdr|=0x1e;//开放错误\接收\发送中断
}
******************以下为汇编程序*********************************************************************
系统can地址为550,用于can系统测试,应用T0定时器每隔1s向can总线发送一组数据:数据长度为8个字节,
首字节为05H,第二个字节为累加变量,每秒钟数值增加1,
*********************************************************************************************************
CONTROLLER_BASEEQU7E00H;SJA1000的片选地址
RCV_GOODBIT0FH;成功的接收一帧标志
SEC_FLAGBIT010H;一秒到标志
ERR_FLAGBIT011H;监测到错误标志
SAVE_INT_INFODATA032H;保存SJA1000中断寄存器的内容
SEND_DATA_BUF1DATA040H;发送缓冲区
SEND_DATA_BUF2DATA041H
SEND_DATA_BUF3DATA042H
SEND_DATA_BUF4DATA043H
SEND_DATA_BUF5DATA044H
SEND_DATA_BUF6DATA045H
SEND_DATA_BUF7DATA046H
SEND_DATA_BUF8DATA047H
SEND_DATA_BUF9DATA048H
SEND_DATA_BUF10DATA049H
RCV_DATA_BUF1DATA050H;接收缓冲区
RCV_DATA_BUF2DATA051H
RCV_DATA_BUF3DATA052H
RCV_DATA_BUF4DATA053H
RCV_DATA_BUF5DATA054H
RCV_DATA_BUF6DATA055H
RCV_DATA_BUF7DATA056H
RCV_DATA_BUF8DATA057H
RCV_DATA_BUF9DATA058H
RCV_DATA_BUF10DATA059H
ERROR_STATUSDATA07CH;错误状态表示
TEST_DATADATA07FH;测试发送数据
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;程序开始
ORG0000H
LJMPMAIN;运行主程序
ORG0003H
LJMPBCAN_INT0;中断方式访问SJA1000程序
ORG000BH
LJMPT0_INTERRUPT;定时器0中断
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ORG0100H;程序开始
MAIN:
MOVR0,#07fH
CLRA
MOV@R0,A
DJNZR0,$-1
MOV@R0,A
MOVSP,#60H;设置SP
CLRP2.0;SJA1000退出硬件复位模式
LCALLSJA1000_INT0;初始化SJA1000
LCALLT0_INIT
CLRP3.4;点亮指示灯
SETBPX0
SETBIT0
SETBEX0
SETBET0
SETBTR0
SETBEA
LOOPER:
JNBRCV_GOOD,LOOPER2;sja1000成功接收一帧,通知CPU处理
CLRRCV_GOOD
LCALLRCVDATA_PRG
LOOPER2:
JNBSEC_FLAG,LOOPER3;一秒时间到,每秒发送一次
CLRSEC_FLAG
CLRP3.5;点亮指示灯
LCALLSENDDATA_PRG
LOOPER3:
JNBERR_FLAG,LOOPER4;错误标志,错误处理
CLRERR_FLAG
LCALLERR_PRG
LOOPER4:
AJMPLOOPER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;初始化SJA1000;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SJA1000_INT0:
LCALLBCAN_CREATE_COMMUNATION ;调用SJA1000接口测试函数
MOVR7,#04
LCALLBCAN_SET_BANDRATE;设置波特率为100k
MOVR7,#0A8H;设置接收报文ID
MOVR6,#0FFH
LCALLBCAN_SET_OBJECT
MOVR7,#0AAH;设置输出控制、时钟分频;正常输出模式
MOVR6,#048H;使能内部比较器、禁止CLKOUT
LCALLBCAN_SET_OUTCLK;
LCALLBCAN_QUIT_RETMODEL;退出复位状态
MOVDPTR,#REG_CONTROL;开放SJA1000内部功能中断
MOVA,#01EH;中断开放
MOVX@DPTR,A
CLRF0
RET
;;;;;;;;;;;;;;;;;;;;;;错误信息处理;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ERR_PRG:
LCALLBCAN_ENTER_RETMODEL;进入复位模式
LCALLSJA1000_INT0 ;
MOVERROR_STATUS,#0FCH
RET
;;;;;;;;;;;;;;;;;;;;;;;接收数据处理部分;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RCVDATA_PRG:
MOVR0,# RCV_DATA_BUF1;微处理器接收首地址
LCALLBCAN_DATA_RECEIVE;调用接收数据子程序
MOVR7,#04H;释放接收缓冲区
LCALLBCAN_CMD_PRG;
RET
;;;;;;;;;;;;;;;;;;控制SJA1000向CAN总线发送数据处理部分;;;;;;;;;;;;;;;
SENDDATA_PRG:
MOVR0,#SEND_DATA_BUF1
MOV@R0,#02H
INCR0
MOV@R0,#08H
INCR0
MOV@R0,#05H
MOVA,TEST_DATA
INCR0
MOV@R0,A
MOVR0,#SEND_DATA_BUF1
LCALLBCAN_DATA_WRITE;将要发送的数据送入发送缓冲区
MOVR7,#01
LCALLBCAN_CMD_PRG
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;定时器0初始化;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
T0_INIT:
MOVA,TMOD
ANLA,#0F0H
ORLA,#01H
MOVTMOD,A;T0工作在方式1
MOVTH0,#0FCH;定时周期1MS
MOVTL0,#066H
MOV3AH,#00H
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;外部中断0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BCAN_INT0:
pushDPH
PUSHDPL
PUSHPSW;PSW,ACC入栈
PUSHACC
USING3;应用寄存器第3组
MOVDPTR,#REG_INTERRUPT;读中断寄存器
MOVXA,@DPTR;
MOVSAVE_INT_INFO,A;保存中断寄存器的内容
JNBACC.0,BCAN_INT1;接收中断
SETBRCV_GOOD;置位接收标志
BCAN_INT1:
MOVA,SAVE_INT_INFO
JNBACC.2,BCAN_INT2;错误中断
SETBERR_FLAG;置位错误标志
BCAN_INT2:
POPACC
POPPSW
POPDPL
POPDPH
RETI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;定时器0中断;;;;;;;;;;;;;;;;
T0_INTERRUPT:
pushDPH
PUSHDPL
PUSHPSW;PSW、ACC入栈
PUSHACC
USING2
MOVTH0,#80H;设置定时周期0.3S
MOVTL0,#26H
INC3AH
MOVA,3AH
CJNEA,#23H,T0_QUIT;判断1秒时间是否到
MOV3AH,#00H
INCTEST_DATA;测试发送的数据,每1秒加1
SETBSEC_FLAG;置位1秒到标志
T0_QUIT:
POPACC
POPPSW
POPDPL
POPDPH
RETI
*********************************************************************
本人同时提供can实验开发板给初学者
1CAN控制器为SJA1000,驱动器为TJA1050,电源隔离;
2提供详尽的源程序,可根据用户需求编写程序
联系我:13671387011(短信联系,QQ详谈)
QQ: 531706356