经过一个星期的艰苦奋斗,终于将两个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接收缓冲区,****已经修改
 }
}


关键字:51单片机  SJA1000  CAN通讯 引用地址:基于51单片机SJA1000 CAN通讯实现

上一篇:基于C8051F040单片机的CAN总线通信
下一篇:STC89C52+SJA1000自收发程序记录

推荐阅读

#ifndef PCF8563_CFG_H#define PCF8563_CFG_H////////////////////////////////////////////////////////////////////////////////////////------------使用包含的头文件#include "i2c_task.h"#ifdef USE_MCU_STM32 #include "delay_task.h"#endif//---寄存器定义#define PCF8563_REG_STATUS1 0x00#define PCF8563_REG_STATUS2 0x01#defi...
5G给消费者带来的最直观的感受就是速度的大幅提升,视频通话、下载、观影等体验将大大提升。而对于商家而言,5G意味着诸多新的商机。视频直播市场开始爆发从当前来看,5G支撑下视频的商机则最为显著。“从目前来看,无人驾驶还有些远,老百姓可以通过视频把5G带起来。”华为老兵戴辉指出。当前,主要有两种视频形式,一种是短视频,另一种是视频直播。在我...
据外媒报道,当地时间9月8日,德国汽车供应商采埃孚(ZF Friedrichshafen)与美国硅谷初创公司Aeva宣布,两家公司正在合作研发一款用于自动驾驶汽车的关键传感器。图片来源:采埃孚激光雷达传感器利用激光测量距离,以帮助自动驾驶汽车获取有关前方道路状况的3D图像。现在,有数十家公司正致力于降低此类传感器的成本,以实现大规模量产。而Aeva公司的传...
  串励电动机  单相串励电动机俗称串励电机或通用(UniversalMotor国外叫法),因电枢绕组和励磁绕组串联在一起工作而得名。单相串励电动机属于交、直流两用电动机,它既可以使用交流电源工作,也可以使用直流电源工作。  单相串励电机是一种目前已经应用非常广泛的电机,它的优点是由于它转速高、起动力矩大、体积小、重量轻、不容易堵转、适用电压...

史海拾趣

问答坊 | AI 解惑

示波器测量中的“热地”和“冷地”.

无线电中的一篇文章,介绍了示波器使用中要注意的一个问题…

查看全部问答∨

二极管应该归到有源器件呢,还是无源器件呢?

二极管应该归到有源器件呢,还是无源器件呢?-%-282556-%-…

查看全部问答∨

AVR中CPI指令是如何影响进位标志位C的?

程序如下BRLO(line 36)指令是根据进位标志C跳转的,它前面的CPI指令是如何影响到进位标志位C和零标志位Z来影响程序 流程的?r1初始值为0 avr034C:        ldi        YL, 0x5F      &nb ...…

查看全部问答∨

有没有哪位兄弟有监测串口,却不占串口的程序

有没有哪位兄弟有 portmon  FOR wince程序,或类似的监测串口,却不占串口的程序? 用于捕捉程序发给串口及其返回的数据…

查看全部问答∨

驱动中如何区分U盘和移动硬盘

做了一个usb过滤驱动挂在磁盘驱动器类下,想问一下 应该怎样区分是移动硬盘还是U盘?…

查看全部问答∨

请问 是否有 WinCE环境下的 MPEG4编码开源代码?

哪位大侠能提供一下, 另外xvid开源码需要安装direct9.0 SDK 不知是否能用于WINce环境开发!谢谢…

查看全部问答∨

那么这两种写法又有啥区别呢

那么这两个有啥区别呢?reg 【15:0】datareg  data【15:0】…

查看全部问答∨

【TI技术文章】:TI KeyStone架构支持L2及传输处理

无线技术的持续演进发展、全球无线用户的激增,以及市场对更强大数据承载能力的需求,全面催生了各种新标准的不断涌现,如宽带码分多址- 高速分组接入 (WCDMA-HSPA)、WCDMA-HSPA+ 以及长期演进技术 (LTE) 等。基于无线服务网络的数据使用呈指数级 ...…

查看全部问答∨

谁能帮忙看看这段VHDL代码有什么问题

library IEEE;use IEEE.STD_LOGIC_1164.ALL; entity period_1ms is port (  CLKIN : in std_logic;  CLR : in std_logic;  LOAD : in std_logic;       DATA : in std_logic_vector( ...…

查看全部问答∨

LM3S811的PWM

其PWM有个故障输入脚,到底是从哪个脚输入的…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved