基于51单片机SJA1000 CAN通讯实现(C语言程序) |
您所在的位置:网站首页 › can通讯芯片和主芯片引脚图 › 基于51单片机SJA1000 CAN通讯实现(C语言程序) |
经过一个星期的艰苦奋斗,终于将两个SJA1000通过51单片机成功通讯了!采用的是Pelican工作模式,扩展帧数据格式,验收滤波器是采用单滤波扩展帧模式。 发送和接收代码都全部相同样! 一 实物图
二 串口输出调试信息
三 以下是全部程序代码:包括1 main.c、2 uart.h、3 uart.c、4 sja1000.h、5 sja1000.c。 1main.c #include "reg51.h" #include "uart.h" #include "string.h" #include "sja1000.h" sbit KEY=P2^5; void main(void) { unsigned char init,state,num,i=0; UART_Init(); if(SJA_Interface_Test()) { UART_Send_String("\r\nSJA TO CPU Right!\r\n"); } else { UART_Send_String("\r\nSJA TO CPU Error!\r\n"); } init=SJA_Init(); if(init==0) { UART_Send_String("\r\nSJA Init OK!\r\n"); } else { UART_Send_String("\r\nSJA Init Error!\r\n"); UART_Send_Byte(init); } while(1) { if(KEY==0) { DelayMs(10); if(KEY==0) { CAN_Send_Str("ILoveY\r\n"); Display(num); if(num++==14) num=0; } DelayMs(200); } SJA_BCANAdr = REG_STATUS; state=*SJA_BCANAdr; if((state&0x40)==0x40) { UART_Send_String("\r\nSJA Error count overflow!!\r\n"); SJA_Init(); } if((state&0x20)==0x20) UART_Send_String("SJA1000 CAN BUS is transmiting!\r\n"); } } 2uart.h #ifndef __UART_H__ #define __UART_H__ #include "stdio.h" #include "reg51.h" #define reclength 8 extern bit recfinish; extern unsigned char recbuf[reclength]; void UART_Init(void); void UART_Send_Byte(unsigned char ch); void UART_Send_String(unsigned char *str); void Display( char num); void DelayMs(unsigned char t); #endif 3uart.c #include "uart.h" unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; unsigned char reccount=0; bit recstart=0; bit recfinish=0; unsigned char recbuf[reclength]; void UART_Init(void) { SCON=0X50; TMOD|=0X20; TH1=0XFD; TL1=0XFD; TR1=1; EA=1; ES=1; } void UART_Send_Byte(unsigned char ch) { SBUF=ch; while(!TI);//等到发送完成中断标志位置1 TI=0; } void UART_Send_String(unsigned char *str) { while(*str) { UART_Send_Byte(*str); str++; } } void UART_ISR(void) interrupt 4 { //unsigned char temp; if(RI) { if(recstart==0) { recstart=1; reccount=0; recfinish=0; } if(recstart) { recbuf[reccount++]=SBUF; if((reccount==reclength)||(recbuf[reccount-1]=='z')) { recfinish=1; reccount=0; recstart=0; } } } RI=0; } /*------------------------------------------------ uS延时函数,含有输入参数 unsigned char t,无返回值 unsigned char 是定义无符号字符变量,其值的范围是 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时 长度如下 T=tx2+5 uS ------------------------------------------------*/ void DelayUs2x(unsigned char t) { while(--t); } /*------------------------------------------------ mS延时函数,含有输入参数 unsigned char t,无返回值 unsigned char 是定义无符号字符变量,其值的范围是 0~255 这里使用晶振12M,精确延时请使用汇编 ------------------------------------------------*/ void DelayMs(unsigned char t) { while(t--) { //大致延时1mS DelayUs2x(245); DelayUs2x(245); } } //共阳数码管显示 调试的时候用到 ,本程序最终没有用到。 void Display( char num) { P1=table[num]; } 4sja1000.h #ifndef __SJA1000_H__ #define __SJA1000_H__ #include "string.h" #include "uart.h" #define SJA_BaseAdr 0XFE00 //定义SJA RAM基址 //P2口为地址线高八位 P0口为地址线低八位 // CS接P2.0 地址线 1111 1110 0000 0000 即为0XFE00 // CS接P2.7 地址线 0111 1111 0000 0000 0x7F00 #define REG_CONTROL SJA_BaseAdr+0x00 //内部控制寄存器 #define REG_COMMAND SJA_BaseAdr+0x01 //命令寄存器 只写 #define REG_STATUS SJA_BaseAdr+0x02 //状态寄存器 只读 #define REG_INTERRUPT SJA_BaseAdr+0x03 //中断寄存器 只读 #define REG_INTENABLE SJA_BaseAdr+0x04 //中断使能寄存器 可读可写 #define REG_RESVER0 SJA_BaseAdr+0x05 //保留0 #define REG_BTR0 SJA_BaseAdr+0x06 //总线定时寄存器0 复位模式读写 //定义了波特率预设值BRP 和同步跳转宽度SJW 的值 #define REG_BTR1 SJA_BaseAdr+0x07 //总线定时寄存器1 复位模式读写 //总线定时寄存器1 定义了每个位周期的长度采样点的位置和在每个采样点的采样数目 #define REG_OCR SJA_BaseAdr+0x08 //输出控制寄存器 复位模式读写 //输出控制寄存器实现了由软件控制不同输出驱动配置的建立 #define REG_TEST SJA_BaseAdr+0x09 //测试寄存器 #define REG_RESVER1 SJA_BaseAdr+0x0A //保留1 #define REG_ARBITRATE SJA_BaseAdr+0x0B //仲裁丢失捕捉 只读 #define REG_ERRCATCH SJA_BaseAdr+0x0C //错误代码捕捉 只读 #define REG_ERRLIMIT SJA_BaseAdr+0x0D //错误报警限额 工作模式只读 复位模式可读写 #define REG_RXERR SJA_BaseAdr+0x0E //接收错误计数器工作模式只读 复位模式可读写 #define REG_TXERR SJA_BaseAdr+0x0F //发送错误计数器工作模式只读 复位模式可读写 #define REG_ACR0 SJA_BaseAdr+0x10 //验收代码寄存器 #define REG_ACR1 SJA_BaseAdr+0x11 //验收代码寄存器 #define REG_ACR2 SJA_BaseAdr+0x12 //验收代码寄存器 #define REG_ACR3 SJA_BaseAdr+0x13 //验收代码寄存器 #define REG_AMR0 SJA_BaseAdr+0x14 //验收屏蔽寄存器 #define REG_AMR1 SJA_BaseAdr+0x15 //验收屏蔽寄存器 #define REG_AMR2 SJA_BaseAdr+0x16 //验收屏蔽寄存器 #define REG_AMR3 SJA_BaseAdr+0x17 //验收屏蔽寄存器 // 发送缓冲区寄存器 (发送缓冲区长13字节,在CAN地址是16-28即0x10-0x1c) #define REG_TXBuffer1 SJA_BaseAdr+0x10 //发送缓冲区1 #define REG_TXBuffer2 SJA_BaseAdr+0x11 //发送缓冲区2 #define REG_TXBuffer3 SJA_BaseAdr+0x12 //发送缓冲区3 #define REG_TXBuffer4 SJA_BaseAdr+0x13 //发送缓冲区4 #define REG_TXBuffer5 SJA_BaseAdr+0x14 //发送缓冲区5 #define REG_TXBuffer6 SJA_BaseAdr+0x15 //发送缓冲区6 #define REG_TXBuffer7 SJA_BaseAdr+0x16 //发送缓冲区7 #define REG_TXBuffer8 SJA_BaseAdr+0x17 //发送缓冲区8 #define REG_TXBuffer9 SJA_BaseAdr+0x18 //发送缓冲区9 #define REG_TXBuffer10 SJA_BaseAdr+0x19 //发送缓冲区10 #define REG_TXBuffer11 SJA_BaseAdr+0x1A //发送缓冲区11 #define REG_TXBuffer12 SJA_BaseAdr+0x1B //发送缓冲区12 #define REG_TXBuffer13 SJA_BaseAdr+0x1C //发送缓冲区13 // 接收缓冲区寄存器 (接收缓冲区长13字节,在CAN地址是16-28即0x10-0x1c) #define REG_RXBuffer1 SJA_BaseAdr+0x10 //接收缓冲区1 #define REG_RXBuffer2 SJA_BaseAdr+0x11 //接收缓冲区2 #define REG_RXBuffer3 SJA_BaseAdr+0x12 //接收缓冲区3 #define REG_RXBuffer4 SJA_BaseAdr+0x13 //接收缓冲区4 #define REG_RXBuffer5 SJA_BaseAdr+0x14 //接收缓冲区5 #define REG_RXBuffer6 SJA_BaseAdr+0x15 //接收缓冲区6 #define REG_RXBuffer7 SJA_BaseAdr+0x16 //接收缓冲区7 #define REG_RXBuffer8 SJA_BaseAdr+0x17 //接收缓冲区8 #define REG_RXBuffer9 SJA_BaseAdr+0x18 //接收缓冲区9 #define REG_RXBuffer10 SJA_BaseAdr+0x19 //接收缓冲区10 #define REG_RXBuffer11 SJA_BaseAdr+0x1A //接收缓冲区11 #define REG_RXBuffer12 SJA_BaseAdr+0x1B //接收缓冲区12 #define REG_RXBuffer13 SJA_BaseAdr+0x1C //接收缓冲区13 #define REG_RXCOUNT SJA_BaseAdr+0x1D //RX报文计数器 只读 RX信息计数器(RMC)反应RXFIFO中可用的信息数目 #define REG_RBSA SJA_BaseAdr+0x1E //RX缓冲器起始地址寄存器(RBSA)可读写 复位模式只写 //反映了当前可用来存储位于接收缓冲器窗口中的信息的内部RAM地址 #define REG_CDR SJA_BaseAdr+0x1F //时钟分频寄存器 //时钟分频寄存器为微控制器控制CLKOUT 的频率以及屏蔽CLKOUT 引脚而且它还控制着TX1上 //的专用接收中断脉冲接收比较通道和BasicCAN 模式与PeliCAN 模式的选择 /* 功能说明: CAN控制器SJA1000通讯波特率.SJA1000的晶振为必须为16MHZ*/ #define BTR0_Rate_20k 0x53 //20KBPS的预设值 #define BTR1_Rate_20k 0x2F //20KBPS的预设值 #define BTR0_Rate_40k 0x87 //40KBPS的预设值 #define BTR1_Rate_40k 0xFF //40KBPS的预设值 #define BTR0_Rate_50k 0x47 //50KBPS的预设值 #define BTR1_Rate_50k 0x2F //50KBPS的预设值 #define BTR0_Rate_80k 0x83 //80KBPS的预设值 #define BTR1_Rate_80k 0xFF //80KBPS的预设值 #define BTR0_Rate_100k 0x43 //100KBPS的预设值 #define BTR1_Rate_100k 0x2f //100KBPS的预设值 #define BTR0_Rate_125k 0x03 //125KBPS的预设值 #define BTR1_Rate_125k 0x1c //125KBPS的预设值 #define BTR0_Rate_200k 0x81 //200KBPS的预设值 #define BTR1_Rate_200k 0xFA //200KBPS的预设值 #define BTR0_Rate_250k 0x01 //250KBPS的预设值 #define BTR1_Rate_250k 0x1c //250KBPS的预设值 #define BTR0_Rate_400k 0x43 //400KBPS的预设值 #define BTR1_Rate_400k 0x11 //400KBPS的预设值 #define BTR0_Rate_500k 0x81 //500KBPS的预设值 #define BTR1_Rate_500k 0x23 //500KBPS的预设值 #define BTR0_Rate_666k 0x41 //666KBPS的预设值 #define BTR1_Rate_666k 0x12 //666KBPS的预设值 #define BTR0_Rate_800k 0x41 //800KBPS的预设值 #define BTR1_Rate_800k 0x11 //800KBPS的预设值 #define BTR0_Rate_1000k 0x40 //1000KBPS的预设值 #define BTR1_Rate_1000k 0x23 //1000KBPS的预设值 //BPS //功能说明: CAN控制器SJA1000通讯波特率.SJA1000的晶振为必须为24MHZ*/ #define BTR0_Rate_10k 0xEF //20KBPS的预设值 #define BTR1_Rate_10k 0xFF //20KBPS的预设值 #define ByteRate_10k 10 #define ByteRate_20k 20 #define ByteRate_40k 40 #define ByteRate_50k 50 #define ByteRate_80k 80 #define ByteRate_100k 100 #define ByteRate_125k 125 #define ByteRate_200k 200 #define ByteRate_250k 250 #define ByteRate_400k 400 #define ByteRate_500k 500 #define ByteRate_800k 800 #define ByteRate_1000k 1000 //命令字 #define TR_CMD 0X01 //CMR.0发送请求位 #define AT_CMD 0X02 //CMR.1中止发送位 #define RRB_CMD 0X04 //CMR.2释放接收缓冲器 #define COS_CMD 0X08 //CMR.3清除数据溢出 #define SRR_CMD 0X10 //CMR.4自接收模式 #define GTS_CMD 0X10 //????CMR.5.CMR7保留位 //错误字 #define CAN_INTERFACE_OK 0 //CAN总线接口OK #define CAN_BUS_OK 0 //CAN总线OK #define CAN_INTERFACE_ERR 0XFF //CAN总线接口错误 #define CAN_ENTERSET_ERR 0XFE //CAN总线初始化错误 #define CAN_QUITSET_ERR 0XFD //CAN总线退出复位模式错误 #define CAN_INITOBJECT_ERR 0XFC //CAN总线初始化对象错误 #define CAN_INITBTR_ERR 0XFB //? #define CAN_INITOUTCTL_ERR 0XFA //?? #define CAN_INTCLKDIV_ERR 0XF9 //?? #define CAN_BUS_ERR 0XF8 //CAN总线错误 #define ID28_21 0X0A; #define ID20_13 0X4A; #define ID12_5 0X6B; #define ID4_0 0XE8; //低三位不影响设为0 //定义扩展模式数据帧ID //Basic CAN模式标准帧格式 :帧信息,TX识别码1-2,TX数据字节1-8 //Pelican模式扩展帧格式 :帧信息,TX识别码1-4,TX数据字节1-8 extern unsigned char xdata *SJA_BCANAdr; bit SJA_Interface_Test(void); bit Set_OutClock(unsigned char outclock);//只能用于复位模式 bit SET_ACR(unsigned char BCAN_ACR0,unsigned char BCAN_ACR1,unsigned char BCAN_ACR2,unsigned char BCAN_ACR3); bit SET_AMR(unsigned char BCAN_AMR0,unsigned char BCAN_AMR1,unsigned char BCAN_AMR2,unsigned char BCAN_AMR3); bit Set_Bandrate(unsigned char bandrate);//只能用于复位模式 bit Set_ContrREG(unsigned char CMD);//设置控制(模式)寄存器 bit Enter_RST_Mode(void); bit Quit_RST_Mode(void); bit CAN_CMD_PRG(unsigned char cmd);//命令请求 bit Set_IntEnable(unsigned char CMD); unsigned char CAN_Write(unsigned char *SendDataBuf); void CAN_Send_onebyte(unsigned char CAN_TX_data); unsigned char SJA_Init(void); void CAN_Send_Str(unsigned char *str); #endif 5.sja1000.c #include "sja1000.h" sbit LED=P1^0; unsigned char xdata *SJA_BCANAdr; unsigned char RevceData[8]; //C语言指针说明以 * 为分隔符, //“*” 前面的存储类型修饰—指针所指向的对象数据的存储位置; //“*” 后面的存储类型修饰—指针本身所分配的存储位置。 // //unsigned char xdata *P说明指针指向的对象是一个处于Xdata的元素,比如数组. //xdata unsigned char *p表明指针本身位于Xdata,至于指向什么类型的地址,自由变换. //所以unsigned char xdata *p; 和xdata unsigned char *p 不一样。说明的是2回事。 //而:xdata unsigned char *p; 和 unsigned char * xdata p; 完全一样。 //因为C写法中允许“最前面的存储类型修饰符修饰最后面的对象。” /***************************************************************** 函数功能:检测SJA1000与CPU数据接口是否正确连接 入口参数: 返回参数:1正确 0错误 说明: ******************************************************************/ bit SJA_Interface_Test(void) { SJA_BCANAdr=REG_TEST; *SJA_BCANAdr=0xAA; if(*SJA_BCANAdr==0XAA) return 1; else return 0; } /***************************************************************** 函数功能:设置分频系数 工作模式 入口参数: 返回参数:1设置成功 0失败 说明:此处设置为PeliCAN模式,终止CAN输入比较器(复位模式),关闭时钟输出 ******************************************************************/ bit Set_OutClock(unsigned char outclock) { SJA_BCANAdr=REG_CDR ; *SJA_BCANAdr=outclock; if(*SJA_BCANAdr==outclock) return 1; else return 0; } /***************************************************************** 函数功能:设置验收验收代码寄存器和接收屏蔽码寄存器 只有在复位模式下才能访问该寄存器 入口参数:各个寄存器的写入值 返回参数:1设置成功 0 设置失败 说明:设置CAN节点的通讯对象,允许接收的报文,是由AMR和ACR共同决定的. PeliCAN工作模式下滤波模式分为: 1.单滤波器模式 模式寄存器(MOD.3=1) 这种滤波模式可以定义一个4字节长虑波器 。虑波器字节和信息字节之位的对应关系取决于当前接收帧的格式。 标准帧:11位标识符、RTR位、数据场前连个字节参与滤波。对于参与滤波的数据,所有AMR为0的位所对应的ACR位 和参与滤波数据的对应位必须相同才算验收通过。如果由于置位RTR位而没有数据字节,或因为设置相应的数据长度代码 而没有或只有一个数据字节,报文也会被接收。ACR1和AMR1的低四位是不用的,此时可将AMR1.3-AMR1.0设为1,定为不影响 扩展帧:29位标识符和RTR位参与滤波。此时ACR3和AMR3的最低两位是不用的。将AMR3.1、AMR3.0置1,定为不影响。 2.双滤波器模式 模式寄存器(MOD.3=0)至少有一个滤波器验收通过,数据才能正常接收。 接收标准帧:第一个滤波器由ACR0、ACR1、AMR0、AMR1及ACR3、AMR3的低四位组成。11位标识符、RTR位和数据场的第一个字节参与滤波 在RTR位置位1或数据长度代码是0,表示没有数据字节存在时,只要从开始到RTR位的部分都表示接收。信息就可以通过滤波器1 第二个滤波器由ACR2、AMR2及ACR3、AMR3的高四位组成。11位标识符和RTR位参与滤波。 如果没有数据字节向滤波器请求过滤,AMR1和AMR3的低四位必须被置1,表示不影响。此时两个滤波器的识别工作都是验证 包括RTR在内的整个标准识别码。 接收扩展帧:定义的两个滤波器是相同的 第一个滤波器由ACR0、ACR1和AMR0、AMR1构成 第二个滤波器由ACR2、ACR3和AMR2、AMR3构成 两个滤波器都只比较扩展识别码的前两个字节即29位识别码中的搞16位 ******************************************************************/ bit SET_ACR(unsigned char BCAN_ACR0,unsigned char BCAN_ACR1,unsigned char BCAN_ACR2,unsigned char BCAN_ACR3) { SJA_BCANAdr=REG_ACR0; *SJA_BCANAdr=BCAN_ACR0; SJA_BCANAdr=REG_ACR1; *SJA_BCANAdr=BCAN_ACR1; SJA_BCANAdr=REG_ACR2; *SJA_BCANAdr=BCAN_ACR2; SJA_BCANAdr=REG_ACR3; *SJA_BCANAdr=BCAN_ACR3; if(*SJA_BCANAdr!=BCAN_ACR3) return 0; return 1; } bit SET_AMR(unsigned char BCAN_AMR0,unsigned char BCAN_AMR1,unsigned char BCAN_AMR2,unsigned char BCAN_AMR3) { SJA_BCANAdr=REG_AMR0; *SJA_BCANAdr=BCAN_AMR0; SJA_BCANAdr=REG_AMR1; *SJA_BCANAdr=BCAN_AMR1; SJA_BCANAdr=REG_AMR2; *SJA_BCANAdr=BCAN_AMR2; SJA_BCANAdr=REG_AMR3; *SJA_BCANAdr=BCAN_AMR3; if(*SJA_BCANAdr!=BCAN_AMR3) return 0; return 1; } /***************************************************************** 函数功能:设置CAN总线通信波特率 入口参数:波特率 返回参数:1设置成功 0设置失败 说明:该子程序只能用于复位模式 因为总线定时器BTRO-BTR1只有在复位模式下才能读写操作,工作模式只读 ******************************************************************/ bit Set_Bandrate(unsigned char bandrate) { unsigned char BR_Num= bandrate,BTR0_num,BTR1_num; switch (BR_Num) { case ByteRate_10k: BTR0_num=BTR0_Rate_10k; BTR1_num=BTR0_Rate_10k; break; case ByteRate_20k: BTR0_num=BTR0_Rate_20k; BTR1_num=BTR0_Rate_20k; break; case ByteRate_40k: BTR0_num=BTR0_Rate_20k; BTR1_num=BTR0_Rate_20k; break; case ByteRate_50k: BTR0_num=BTR0_Rate_50k; BTR1_num=BTR0_Rate_50k; break; case ByteRate_80k: BTR0_num=BTR0_Rate_80k; BTR1_num=BTR0_Rate_80k; break; case ByteRate_100k: BTR0_num=BTR0_Rate_100k; BTR1_num=BTR0_Rate_100k; break; case ByteRate_125k: BTR0_num=BTR0_Rate_125k; BTR1_num=BTR0_Rate_125k; break; case ByteRate_200k: BTR0_num=BTR0_Rate_200k; BTR1_num=BTR0_Rate_200k; break; case ByteRate_250k: BTR0_num=BTR0_Rate_250k; BTR1_num=BTR0_Rate_250k; break; case ByteRate_400k: BTR0_num=BTR0_Rate_400k; BTR1_num=BTR0_Rate_400k; break; case ByteRate_500k: BTR0_num=BTR0_Rate_500k; BTR1_num=BTR0_Rate_500k; break; case ByteRate_1000k: BTR0_num=BTR0_Rate_1000k; BTR1_num=BTR0_Rate_1000k; break; default :return 0;break; } SJA_BCANAdr=REG_BTR0; *SJA_BCANAdr=BTR0_num; if(*SJA_BCANAdr!=BTR0_num) return 0; SJA_BCANAdr=REG_BTR1; *SJA_BCANAdr=BTR1_num; if(*SJA_BCANAdr!=BTR1_num) return 0; return 1; } /***************************************************************** 函数功能:设置控制(模式)寄存器 入口参数:写入的命令 返回参数: 说明:模式寄存器的内容是用来改变CAN 控制器的行为 ******************************************************************/ bit Set_ContrREG(unsigned char CMD) { SJA_BCANAdr = REG_CONTROL;//控制寄存器 *SJA_BCANAdr=CMD; if(*SJA_BCANAdr==CMD) return 1; else return 0; } /***************************************************************** 函数功能:设置复位请求和单滤波工作模式 入口参数: 返回参数: 说明: ******************************************************************/ bit Enter_RST_Mode(void) { SJA_BCANAdr = REG_CONTROL;//控制寄存器 *SJA_BCANAdr=0x09; //置位复位请求 和单滤波模式 if((*SJA_BCANAdr&0x01) == 1) return 1; else return 0; }/***************************************************************** 函数功能: 入口参数: 返回参数: 说明: ******************************************************************/ bit Quit_RST_Mode(void) { SJA_BCANAdr=REG_CONTROL; //退出 复位模式 *SJA_BCANAdr=*SJA_BCANAdr&0xfe; if((*SJA_BCANAdr&0X01)==0) return 1; else return 0; } /***************************************************************** 函数功能:发送命令请求,并返回请求结果 入口参数: 返回参数:0请求成功 1请求失败 说明: ******************************************************************/ bit CAN_CMD_PRG(unsigned char cmd) { SJA_BCANAdr=REG_COMMAND; //访问地址指向命令寄存器 *SJA_BCANAdr=cmd; //启动命令字 switch(cmd) { case TR_CMD: //发送请求 return 1; break; case SRR_CMD: //CMR.4自接收模式 return 1; break; case AT_CMD: //CMR.1中止发送位 SJA_BCANAdr = REG_STATUS; //访问地址指向状态寄存器 if((*SJA_BCANAdr & 0x20)==0) //判断是否正在发送 (0正在发送 1等待空闲) return 1; else return 0; break; case RRB_CMD: // CMR.2释放接收缓冲器 SJA_BCANAdr = REG_STATUS; //访问地址指向状态寄存器 if((*SJA_BCANAdr & 0x01)==1) //判断接收缓冲器是否为空 (0为空 1不为空) return 0;//若不为空 则释放接收缓冲器失败 else return 1; break; case COS_CMD: //CMR.3清除数据溢出 SJA_BCANAdr = REG_STATUS; if((*SJA_BCANAdr & 0x02)==0)//判断清除溢出是否成功 return 1; else return 0; break; default: return 0; break; } } /***************************************************************** 函数功能:设置中断使能寄存器 入口参数: 返回参数: 说明: ******************************************************************/ bit Set_IntEnable(unsigned char CMD) { SJA_BCANAdr=REG_INTENABLE; //SJA_BaseAdr+0x00 控制寄存器 *SJA_BCANAdr=CMD; if (*SJA_BCANAdr == CMD) return 1; else return 0; } unsigned char CAN_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_RXBuffer1; //访问地址指向发送缓冲区1,修改成头文件 memcpy(SJA_BCANAdr,SendDataBuf,4); //将SendDataBuf起始地址的的4个字节数据拷贝到 SJA_BCANAdr 发送缓冲区中 CAN_CMD_PRG(TR_CMD); //请求发送 return 0; } //CAN发送一个字节 void CAN_Send_onebyte(unsigned char CAN_TX_data) { unsigned char temptt; loop: SJA_BCANAdr = REG_STATUS; temptt=*SJA_BCANAdr; //temptt=Read_SJA1000(REG_STATUS); if((temptt&0x04)==0x00) goto loop;//循环检测等待 //可以向发送缓冲器写数据 SJA_BCANAdr = REG_RXBuffer1; *SJA_BCANAdr=0x01; SJA_BCANAdr = REG_RXBuffer2; *SJA_BCANAdr=0x28; SJA_BCANAdr = REG_RXBuffer3; *SJA_BCANAdr=0x00; SJA_BCANAdr = REG_RXBuffer4; *SJA_BCANAdr=CAN_TX_data; //数据发送请求 CAN_CMD_PRG(TR_CMD); } void CAN_Send_Str(unsigned char *str) { unsigned char temptt,length; loop: SJA_BCANAdr = REG_STATUS; temptt=*SJA_BCANAdr; //temptt=Read_SJA1000(REG_STATUS); if((temptt&0x04)==0x00) goto loop;//循环检测等待 //可以向发送缓冲器写数据 length=strlen(str); SJA_BCANAdr = REG_TXBuffer1; *SJA_BCANAdr=0x80|length; //设置发送信息帧位扩展数据帧 和发送的数据字节长度 SJA_BCANAdr = REG_TXBuffer2; *SJA_BCANAdr=ID28_21; SJA_BCANAdr = REG_TXBuffer3; *SJA_BCANAdr=ID20_13; SJA_BCANAdr = REG_TXBuffer4; *SJA_BCANAdr=ID12_5; SJA_BCANAdr =REG_TXBuffer5; *SJA_BCANAdr=ID4_0; SJA_BCANAdr = REG_TXBuffer6; memcpy(SJA_BCANAdr,str,length); //数据发送请求 CAN_CMD_PRG(TR_CMD); } /***************************************************************** 函数功能:SJA1000初始化 入口参数: 返回参数: 说明: ******************************************************************/ unsigned char SJA_Init(void) { bit s; EA=0;//关总中断 if (!Enter_RST_Mode()) return 1; //设置模式(控制)寄存器 置位复位请求位 和验收滤波模式位(单滤波模式) if (!SJA_Interface_Test()) return 2; //!!!!!我觉得此处逻辑上应先测试SJA1000再进行复位操作 //0XC8=1100 0000 最高位CDR.7(CANmode位)=1=Pelican模式(=0=BasicCAN模式) //置位CDR.6 可以中止CAN 输入比较器 CDR.3置位关闭external CLKOUT CD2-CD0 设置时钟分频 //设置为PeliCAN模式,终止CAN输入比较器(复位模式),关闭时钟输出 if (!Set_OutClock(0XC8)) return 3; //设置滤波器滤波条件 SET_ACR(0x0A,0x4A,0x6B,0x78); s=SET_AMR(0x00,0x00,0x00,0x03); if (s==0) return 4; if (!Set_Bandrate(ByteRate_1000k)) return 5;//设置通信波特率 if (!Set_IntEnable(0x1D)) return 6; SJA_BCANAdr=REG_OCR ; //输出控制寄存器 *SJA_BCANAdr=0x1a; //设置为正常输出模式 if(!Quit_RST_Mode()) return 7; EA=1; PX0=1;//外部中断0定义为高优先级中断 EX0=1;//开启外部中断 IT0=0;//外部中断0触发方式选择位 此处设置为低电平触发 return 0; } void Int0_ISR() interrupt 0 { unsigned char tt,length; SJA_BCANAdr=REG_INTERRUPT;//中断寄存器 if((*SJA_BCANAdr)&0x01) //产生了接收中断 { UART_Send_String("SJA1000 Has recieved data!\r\n"); SJA_BCANAdr=REG_RXBuffer1;//CAN地址16 TX帧信息 低四位DLC.3-DLC.0数据长度代码为 tt=*SJA_BCANAdr; length=tt&0x0F;//获取数据长度代码 if ((tt&0x40)!=0x40) //最高位为帧格式位=0数据帧 =1 为远程帧 { SJA_BCANAdr=REG_RXBuffer6; //宏定义的变量不能memcpy(RevceData,REG_RXBuffer4,8); memcpy(RevceData,SJA_BCANAdr,length);//功能:由src所指内存区域复制count个字节到dest所指内存区域 //测试用的主要是把接收到的数据在发出去,验证数据的正确 //以下代码是发送到串 UART_Send_String(RevceData); } CAN_CMD_PRG(RRB_CMD); //释放SJA1000接收缓冲区,****已经修改 } } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |