单片机can通讯编程_单片机如何编程读取can总线 - CSDN
  • 经过一个星期的艰苦奋斗,终于将两个SJA1000通过51单片机成功通讯了!采用的是Pelican工作模式,扩展帧数据格式,验收滤波器是采用单滤波扩展帧模式。 发送和接收代码都全部相同样! 一 实物图 二 串口输出...

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

    展开全文
  • 如果您使用的单片机不带CAN总线,那么本篇文章对您不适用(编程环境是Keil5) 使用stm32系列单片机开发CAN的朋友们和以下内容契合度更高 第一步:简单的了解CAN (如果在真正初次使用CAN前就把它很深入地剖解,那...

    为了您的学习更有效率,别再做无头苍蝇,虽然没有捷径但有前人的学习经验可以借鉴

    如果您使用的单片机不带CAN总线,那么本篇文章对您不适用(编程环境是Keil5)

    使用stm32系列单片机开发CAN的朋友们和以下内容契合度更高

    第一步:简单的了解CAN

    (如果在真正初次使用CAN前就把它很深入地剖解,那你是真的闲。建议编程的时候才深剖)

    ①CAN是一种通信协议(举例485,422,232,IIC,SPI它们也是一种通信协议),它就像各种单片机的uart口一样是存在于单片机内部的一个设备(也叫单片机的外设)

    由于CAN比较高级,它只存在一些较高级的单片机中(叫做CAN总线),一些低端单片机需要接CAN控制器及电平转换器才能使用CAN通信。有自带CAN总线的单片机控制CAN通信实际上也是操作单片机内部的寄存器来实现。

    ②电路设计:

     

    ③数据传输协议:

     

    CAN 控制器根据CAN_L和CAN_H上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。

    显性电平对应逻辑:0

    CAN_H和CAN_L之差为2V左右。

    隐性电平对应逻辑:1

    CAN_H和CAN_L之差为0V。

    ④对初学者第一步,知道以上内容就够了!接下来直接打开Keil5建立编程环境,再打开相关CAN数据手册(开发手册),按照第二步(下面的步骤),边写程序边找手册上的资料。

     

    第二步:带上CAN数据手册,编程走起!

    ①根据自己使用的单片机,在该单片机的芯片开发手册/参考手册上找出所有带CAN标题的书签,定位好资料位置。然后打开编程环境,建立工程,把单片机的底层代码文件包含进来

    ②封装CAN初始化函数(这个基本不用解释为什么,大多数外设运用都要初始化唤醒功能)

    1. 初始化硬件需求的单片机引脚(不同单片机对引脚初始化有不同的规则有些低端的8位单片机甚至不需要引脚初始化),使能相关的时钟信号(可能包括系统时钟、引脚时钟、外设CAN的时钟,也是根据自己用的单片机型号而定)
    2. 按要求配置位时序寄存器CAN_BTR(关于工作模式、波特率设置)
    3. 按要求配置主状态寄存器CAN_MCR(设置通信相关控制位)

     

    ③按需求配置筛选器(鄙人认为是为了保证数据的正确率相当于滤波器保证信号稳定)

    1、配置主筛选器寄存器CAN_FMR(设置FINIT为1筛选器进入初始化模式)

    2、配置筛选器激活寄存器CAN_FA1R,激活其中一个筛选器。

    3、配置筛选器尺度寄存器CAN_FS1R,设置筛选尺度。

    4、配置筛选器模式寄存器CAN_FM1R,设置筛选器工作模式,有如下四种

     

    5、配置筛选器FIFO分配寄存器CN_FFA1R(设置通过筛选器的数据存储到哪个FIFO存储器),注意每个筛选器的在寄存器设置位不一样,如FFA1位,设置的是筛选器1。

    6、配置主筛选器寄存器CAN_FMR(设置FINIT为0筛选器结束初始化模式)

    ④如果需要CAN收发中断,则要配置中断使能寄存器CAN_IER。并写中断服务函数。对应地,也要根据单片机的不同做相应的单片机中断初始化。

    ⑤封装发送数据函数

    是以数据帧的格式发送一串n多位的二进制数来达到发送0-8个字节数据的目的。

    数据帧又分为几个部分如下

    1)帧起始。表示数据帧开始的段。

    2)仲裁段。表示该帧优先级的段。

    3)控制段。表示数据的字节数及保留位的段。

    4)数据段。数据的内容,一帧可发送0~8个字节的数据。

    5)CRC段。检查帧的传输错误的段。

    6)ACK段。表示确认正常接收的段。

    7)帧结束。表示数据帧结束的段。

     

    数据帧分为标准格式拓展格式两种区别如下图:

     

    那么发送数据的数据内容和格式我们知道了,下面就是发送方法了

    首先数据帧的数据都是在对应的寄存器里的,我们查手册可以知道,然后以下步骤

    1. 检查发送状态寄存器CAN_TSR相应位看看有没有空数据的邮箱(有三个缓存数据的 邮箱)
    2. 判断数据帧中的IDE看看是不是拓展格式,然后根据情况发送对应数据到CAN发送 FIFO邮箱标识符寄存器(CAN_TIxR)(x=0/1),再配置CAN发送FIFO邮箱数据长度和时 间戳寄存器(CAN_TDTxR) (x=0/1)记录数据长度字节大小等,再用对应算法把数据帧的数 据段的数据传到CAN发送邮箱数据寄存器(CAN_TDLxR/CAN_TDHxR) (x=0~2),最后邮箱 标识符寄存器(CAN_TIxR)的TXRQ置1表示请求发送数据
    3. 检查发送状态寄存器CAN_TSR相应位,等待发送成功。

     

    ⑥封装接收数据

    同样是操作相关寄存器,如下顺序

    1. 检查FIFO x CAN寄存器CAN_RFxR(x=0/1),读取相应状态,看看是否有数据接收
    2. 判断数据帧中的IDE看看是不是拓展格式,然后根据情况发送对应数据到CAN接收 FIFO邮箱标识符寄存器(CAN_RIxR)(x=0/1) ,和发送差不多,同样要配置再配置CAN 接收FIFO邮箱数据长度和时 间戳寄存器(CAN_RDTxR) (x=0/1)记录数据长度字节大 小等,再用对应算法把数据帧的数 据段的数据传到CAN发送邮箱数据寄存器 (CAN_RDLxR/CAN_RDHxR) (x=0~2)。
    3. 把CAN接收FIFO寄存器(CAN_RF0R/CAN_RF1R)的RFOM0/RFOM1位置1,表示释 放指定的FIFO的输出邮箱,如果三个邮箱都有数据无法读下一条数据。
      1. 本博客笔记视频记录在本人b站空间https://www.bilibili.com/video/av61852069

     

    展开全文
  • CAN发送源代码
  • 基于51单片机CAN通讯源代码,方便进行再开发,非常适合初学者
  • STM32-CAN通讯编程

    2019-03-12 16:38:35
    一、can通信介绍 1、基本概念:CAN 是Controller Area Network 的缩写(以下称为CAN),是ISO国际标准化的串行通信协议。在汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制...

    一、can通信介绍

    1、基本概念:CAN 是Controller Area Network 的缩写(以下称为CAN),是ISO国际标准化的串行通信协议。在汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。
    2、CAN总线物理特性:CAN bus两根信号线分别叫CANH 和CANL,如果CANH电平 大于 CANL 为 Dominant (显性电平) 其实表示的是信号 0 ;如果CANH电平 等于 CANL 为 Recessive (隐形电平) 其实表示的是信号 1。
    芯片5V供电时输出0时CANH 和 CANL输出电压大致为 3.5V和1.5V,当输出为1时 两根线就是浮地的高阻状态,通过外界的端接电阻将电压拉到相等大致为2.5V
    在这里插入图片描述
    3、协议标准:CAN协议经过ISO标准化后有两个标准:IS011898标准和IS011519-2标准。其中IS011898是针对通信速率为125Kbps-1Mbps的高速通信标准,而IS011519-2是针对通信速率为125Kbps以下的低速通信标准。
    4、参数:通信速率最高可达1Mbps,通信距离最远可达10KM,传输距离与速率的一般关系如下:
    在这里插入图片描述
    5、对比:CAN通信相比于串口通信、SPI通信、IIC通信,功能和高干扰能力要更强一些;与485总线有些类似,都是2线制的差分形式;但相比而言,CAN总线的数据通信具有更好的可靠性、实时性和灵活性。CAN已经形成国际标准,并已被公认为几种最有前途的现场总线之一。
    在这里插入图片描述

    二、CAN通讯编程

    1、目的:本次实验主要实现MCU(stm32F103)与BMS的CAN通讯功能,然后根据BMS的通讯协议文档解析当前BMS的状态。
    2、编程思路:参考STM32的CAN例程基础上,1)根据BMS通讯要求更改初始化参数;2)CAN接收后进行BMS状态解析。
    3、编程实现
    (1)CAN总线波特率设置
    CAN通讯的一个位可分为 4 段:同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)、相位缓冲段2(PBS2);STM32把传播时间段和相位缓冲段1(STM32称之为时间段1)合并了,所以STM32的CAN一个位只有3段:同步段(SYNC_SEG)、时间段1(BS1)和时间段2(BS2)。
    通过设定位时序,多个单元可同时采样,也可任意设定采样点。比如设置TS1=9、TS2=8,SYNC_SEG=1和BRP=8,在APB1频率为36Mhz的条件下,即可得到CAN通信的波特率=36000/[(9+8+1)*8]=250Kbps。

    	    CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    	    CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    	    CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    	    CAN_InitStructure.CAN_NART=ENABLE;         //禁止报文自动传送
    	    CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    	    CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    	    CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    	    CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    	    CAN_InitStructure.CAN_BS1=CAN_BS1_9tq;      //时间段1为9个时间单位
    	    CAN_InitStructure.CAN_BS2=CAN_BS2_8tq;      //时间段2为8个时间单位
    	    CAN_InitStructure.CAN_Prescaler=8;        //时间单位长度为8 
            CAN_Init(CAN1,&CAN_InitStructure);         
    

    (2)滤波器和屏蔽
    参考:https://blog.csdn.net/jixiangrurui/article/details/39370027
    (3)接收:采用中断方式

    void USB_LP_CAN1_RX0_IRQHandler(void)
    {
    	  		CanRxMsg RxMessage;
    			double i=0;
    	   		 CAN_Receive(CAN1, 0, &RxMessage);
    			if(RxMessage.ExtId==xxxx){
    			///解析代码
    }
    

    三、结果与总结
    1、实验结果
    BMS电池数据测量值如下,与预期相同
    在这里插入图片描述
    2、总结:
    (1)调试方法:按照单STM32回环测试–>双STM32功能测试–>STM32与BMS通讯测试
    (2)滤波器和屏蔽配置时,可以先不进行屏蔽,在接收中断中进行筛选;功能调通后,后续再根据需求进行设置。

    展开全文
  • //-----------------------函数声明,变量定义-------------------------------------------------------- #include <reg52.h> sbit int0 = P3^2; //-----------------------定义寻址的基址---------...
     

     //-----------------------函数声明,变量定义--------------------------------------------------------   

    #include <reg52.h>   
    sbit  int0 = P3^2;   
    //-----------------------定义寻址的基址--------------------------------------------------------   
    #define base_Adr 0x00      
    //-----------------------定义总线定时寄存器的值--------------------------------------------------------   
    #define SJA_BTR0 0x00                                  //该值需要用户根据实际需要的波特率进行计算   
    #define SJA_BTR1 0x16                                  //具体计算见文章说明   
    //-----------------------设置接收报文类型(标示符)--------------------------------------------------------   
                                                          //该值需要用户根据实际需要重新配置   
    #define SJA_ACR 0x00                                  //验收代码寄存器的值   
    #define SJA_AMR 0x16                                  //验收屏蔽寄存器的值   
    //-----------------------设置输出始终类型--------------------------------------------------------   
                                                          //该值需要用户根据实际需要重新配置   
    #define SJA_OCR 0x00                                  //输出控制寄存器的值   
    #define SJA_CDR 0x16                                  //始终分频寄存器的值   
    //-----------------------设置SJA中断,1为开中断--------------------------------------------------------   
    #define SJA_OIE 0                                    //溢出中断   
    #define SJA_EIE 0                                    //错误中断   
    #define SJA_TIE 0                                    //发送中断   
    #define SJA_RIE 0                                    //接收中断   
    //-----------------------定义地址指针,指向基址--------------------------------------------------------   
    unsigned char xdata *SJA_base_Adr = base_Adr;   
    //-----------------------定义硬件故障标志位--------------------------------------------------------   
    bit bdata    connect_OK=0;                            //connect_OK=1设备连接正常   
                                                          //connect_OK=0设备连接故障   
    //-----------------------定义硬件故障标志位--------------------------------------------------------   
    bit bdata    SJA_workmode=1;                          //SJA_workmode=1SJA工作在工作模式   
                                                          //SJA_workmode=0工作在复位模式   
    //-----------------------定义SJA1000读写缓冲区的数据结构--------------------------------------------------------   
    struct BASICCAN_BUFstruct{   
                   unsigned char FrameID_H;   
                   unsigned char FrameLENTH ;   
                   unsigned char FrameKIND  ;   
                   unsigned char FrameID_L3 ;   
                   unsigned char Frame_Data[8];   
                   }BASICCAN_FRAME,receive_BUF,send_BUF;   
    //BASICCAN_BUFstruct send_BUF;   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别 SJA1000基本操作   
    // 函数名称 CANREG_write   
    // 入口函数 SJAREG_ADR,setting   
    // 出口函数 无   
    // 函数功能 写SJA1000的寄存器   
    //------------------------------------------------------------------------------------------------------   
    void CANREG_write(unsigned char SJAREG_ADR, unsigned char setting)   
               {   
                        *(SJA_base_Adr+SJAREG_ADR)=setting;   
                }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别 SJA1000基本操作   
    // 函数名称 CANREG_write   
    // 入口函数 SJAREG_ADR   
    // 出口函数 SJAREG_data   
    // 函数功能 读SJA1000的寄存器   
    //------------------------------------------------------------------------------------------------------   
    unsigned char CANREG_read(unsigned char SJAREG_ADR)   
    {   
    unsigned char SJAREG_data;   
    SJAREG_data=*(SJA_base_Adr+SJAREG_ADR);   
    return(SJAREG_data);   
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   SJAconnect_judge   
    // 入口函数   无   
    // 出口函数   无   
    // 全局变量   connect_OK   
    // 操作寄存器 测试寄存器(地址09)   
    // 函数功能   判断SJA1000与控制器连接是否正常   
    //------------------------------------------------------------------------------------------------------   
    void SJAconnect_judge(void)   
    {   
       CANREG_write(0x09,0xAA);                //写AA到测试寄存器(地址09)   
       if(CANREG_read(0x09)==0xAA)   
        {   
         connect_OK=1;                         //连接正常    
         }   
        else    
        {   
        connect_OK=0;                         //连接故障   
        }     
    }   
       
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   setting_SJA_resetmode   
    // 入口函数   无   
    // 出口函数   无   
    // 全局变量   SJA_workmode   
    // 操作寄存器 控制寄存器(地址00)   
    // 函数功能   设置SJA工作在复位模式   
    //------------------------------------------------------------------------------------------------------   
    void setting_SJA_resetmode(void)   
    {   
    unsigned char CONTROL_REGdata;     
    CONTROL_REGdata=CANREG_read(0x00);   
    CONTROL_REGdata=CONTROL_REGdata|0x01;   
         CANREG_write(0x00,CONTROL_REGdata);   
         if((CANREG_read(0x00)&0x01)==1)    
            {   
             SJA_workmode=0;                        //置复位模式成功   
            }   
         else    
           {   
            SJA_workmode=1;                         //置复位模式失败   
            }     
    }   
       
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   setting_SJA_resetmode   
    // 入口函数   无   
    // 出口函数   无   
    // 全局变量   SJA_workmode   
    // 操作寄存器 控制寄存器(地址00)   
    // 函数功能   设置SJA工作在正常工作模式   
    //------------------------------------------------------------------------------------------------------   
    void setting_SJA_workingmode(void)   
    {   
    unsigned char CONTROL_REGdata;     
    CONTROL_REGdata=CANREG_read(0x00);   
    CONTROL_REGdata=CONTROL_REGdata&0xFE;   
         CANREG_write(0x00,CONTROL_REGdata);   
         if((CANREG_read(0x00)&0x01)==0)    
            {   
             SJA_workmode=1;                        //置工作模式成功   
            }   
         else    
           {   
            SJA_workmode=0;                         //置工作模式失败   
            }     
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   setting_SJA_rate   
    // 入口函数   SJA_BTR0,SJA_BTR1   
    // 出口函数   setting_success   
    // 操作寄存器 总线定时寄存器BTR1(地址07)和BTR0(地址06)   
    // 函数功能   设置SJA波特率   
    // 特殊要求   只能在复位工作模式下设置   
    //------------------------------------------------------------------------------------------------------   
    bit setting_SJA_rate(void)   
    {   
    bit setting_success;     
    while(SJA_workmode)   
          {   
          setting_SJA_resetmode();                   //设置SJA工作在复位模式   
          }   
         CANREG_write(0x06,SJA_BTR0);   
         CANREG_write(0x07,SJA_BTR1);   
         if((CANREG_read(0x06)==SJA_BTR0)&(CANREG_read(0x07)==SJA_BTR1))   
            {   
             setting_success=1;                        //波特率设置成功   
            }   
         else    
           {   
            setting_success=0;                         //波特率设置失败   
            }     
    return(setting_success);   
    }   
       
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   setting_SJA_dataselect   
    // 入口函数   SJA_ACR,SJA_AMR   
    // 出口函数   setting_success   
    // 操作寄存器 验收代码寄存器ACR(地址04)和验收屏蔽寄存器AMR(地址05)   
    // 函数功能   设置SJA接收数据类型   
    // 特殊要求   只能在复位工作模式下设置   
    //------------------------------------------------------------------------------------------------------   
    bit setting_SJA_dataselect(void)   
    {   
    bit setting_success;     
    while(SJA_workmode)   
          {   
          setting_SJA_resetmode();                   //设置SJA工作在复位模式   
          }   
         CANREG_write(0x04,SJA_ACR);   
         CANREG_write(0x05,SJA_AMR);   
         if((CANREG_read(0x04)==SJA_ACR)&(CANREG_read(0x05)==SJA_AMR))   
            {   
             setting_success=1;                        //滤波器设置成功   
            }   
         else    
           {   
            setting_success=0;                         //滤波器设置失败   
            }     
    return(setting_success);   
    }   
       
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   setting_SJA_CLK   
    // 入口函数   SJA_OCR,SJA_CDR   
    // 出口函数   setting_success   
    // 操作寄存器 输出控制寄存器OCR(地址08)和时钟分频寄存器CDR(地址31)   
    // 函数功能   设置SJA输出始终类型   
    // 特殊要求   只能在复位工作模式下设置   
    //------------------------------------------------------------------------------------------------------   
    bit setting_SJA_CLK(void)   
    {   
    bit setting_success;     
    while(SJA_workmode)   
          {   
          setting_SJA_resetmode();                   //设置SJA工作在复位模式   
          }   
         CANREG_write(0x08,SJA_OCR);   
         CANREG_write(31,SJA_CDR);   
         if((CANREG_read(0x08)==SJA_OCR)&(CANREG_read(31)==SJA_CDR))   
            {   
             setting_success=1;                        //滤波器设置成功   
            }   
         else    
           {   
            setting_success=0;                         //滤波器设置失败   
            }     
    return(setting_success);   
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   setting_SJA_interrupt   
    // 入口函数   SJA_OIE,SJA_EIE,SJA_TIE,SJA_RIE   
    // 出口函数   setting_success   
    // 操作寄存器 控制寄存器(00)   
    // 函数功能   设置SJA中断类型和中断状态   
    // 特殊要求   只能在复位工作模式下设置   
    //------------------------------------------------------------------------------------------------------   
    bit setting_SJA_interrupt(void)   
    {   
    bit setting_success;     
    unsigned char CONT_buf,temp=0;   
    while(SJA_workmode)   
          {   
          setting_SJA_resetmode();                   //设置SJA工作在复位模式   
          }   
         CONT_buf=CANREG_read(0x00);   
         temp=SJA_OIE;   
         temp=temp<<4;   
         temp=temp|SJA_EIE;   
         temp=temp<<3;   
         temp=temp|SJA_TIE;   
         temp=temp<<2;   
         temp=temp|SJA_RIE;   
         temp=temp<<1;   
         CONT_buf=(temp&0x1E)|(CONT_buf&0x01);   
         CANREG_write(0x00,CONT_buf);   
         if(CANREG_read(0x00)==CONT_buf)   
            {   
             setting_success=1;                        //滤波器设置成功   
            }   
         else    
           {   
            setting_success=0;                         //滤波器设置失败   
            }     
    return(setting_success);   
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   Write_SJAsendBUF   
    // 入口函数   无   
    // 出口函数   setting_success   
    // 操作寄存器 发送缓存器(10-19)状态寄存器02   
    // 函数功能   写发送缓存器   
    // 特殊要求   只能在工作模式下写   
    //------------------------------------------------------------------------------------------------------   
    bit Write_SJAsendBUF(void)   
    {   
    bit setting_success=0;     
    unsigned char i;   
    while(SJA_workmode==0)   
          {   
          setting_SJA_workingmode();                   //设置SJA在工作模式   
          }   
    if((CANREG_read(0x02)&0x10)==0)   
       {   
       if((CANREG_read(0x02)&0x04)!=0)   
        {   
        CANREG_write(0x10,send_BUF.FrameID_H);   
        CANREG_write(0x11,(send_BUF.FrameLENTH<<4)||(send_BUF.FrameKIND<<3)||(send_BUF.FrameID_L3));   
        if(send_BUF.FrameKIND==0)   
          {for(i=0;i<send_BUF.FrameLENTH,i<8;i++)   
            CANREG_write(0x12+i,send_BUF.Frame_Data[i]);   
            }   
        setting_success=1;                        //发送寄存器写成功   
          }   
        }   
    return(setting_success);   
    }   
       
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   SJA1000基本操作   
    // 函数名称   Write_SJAsendBUF   
    // 入口函数   无   
    // 出口函数   setting_success   
    // 操作寄存器 接收缓存器(20-29)状态寄存器02   
    // 函数功能   写发送缓存器   
    // 特殊要求   只能在工作模式下写   
    //------------------------------------------------------------------------------------------------------   
    bit read_SJAreceiveBUF(void)   
    {   
    bit setting_success=0;     
    unsigned char i;   
    while(SJA_workmode==0)   
          {   
          setting_SJA_workingmode();                   //设置SJA在工作模式   
          }   
    if((CANREG_read(0x02)&0x01)!=0)   
       {   
       if((CANREG_read(0x02)&0x10)==0)   
        {   
        receive_BUF.FrameID_H=CANREG_read(0x20);   
        receive_BUF.FrameLENTH=((CANREG_read(0x21)&0xF0)>>4);   
        receive_BUF.FrameKIND=((CANREG_read(0x21)&0x08)>>3);   
        receive_BUF.FrameID_L3=(CANREG_read(0x21)&0x07);   
        if(receive_BUF.FrameKIND==0)   
          {for(i=0;i<receive_BUF.FrameLENTH,i<8;i++)   
            receive_BUF.Frame_Data[i]=CANREG_read(0x22+i);   
          }   
        setting_success=1;                        //接收寄存器读成功   
          }   
        }   
    return(setting_success);   
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   供调用子程序   
    // 函数名称   SJA1000_init   
    // 入口函数   无   
    // 出口函数   无   
    // 操作寄存器  1)控制寄存器(地址00)   
    //             2)收代码寄存器ACR(地址04)   
    //             3)验收屏蔽寄存器AMR(地址05)      
    //             4)总线定时寄存器BTR0(地址06)   
    //             5)总线定时寄存器BTR1(地址07)   
    //             6)输出控制寄存器OCR(地址08)   
    //             7)测试寄存器(地址09)   
    //             8)和时钟分频寄存器CDR(地址31)   
    // 函数功能   SJA1000初始化设置   
    // 特殊要求   在复位模式进行,初始化结束进入工作状态   
    //------------------------------------------------------------------------------------------------------   
    void SJA1000_init(void)   
    {   
       
    while(connect_OK==0)                
      {   
      SJAconnect_judge();             //检测设备连接   
      }   
    while(SJA_workmode)   
      {   
      setting_SJA_resetmode();         //置SJA1000为复位工作模式   
      }   
    while(setting_SJA_rate()==0)   
      {   
      setting_SJA_rate();               //设置总线波特率   
      }   
    while(setting_SJA_dataselect()==0)   
      {   
      setting_SJA_dataselect();          //设置SJA接收数据的格式(标示位)   
      }   
    while(setting_SJA_CLK()==0)   
      {   
      setting_SJA_CLK();                 //设置SJA输出始终的形式   
      }   
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   中断处理函数   
    // 函数名称   send_interrupt   
    // 入口函数   无   
    // 出口函数   无   
    // 操作寄存器    
    // 函数功能   接收中断处理函数   
    //------------------------------------------------------------------------------------------------------   
    send_interrupt()   
    {   
       
    }   
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   发送中断处理函数   
    // 函数名称   receive_interrupt   
    // 入口函数      
    // 出口函数      
    // 操作寄存器    
    // 函数功能    发送中断处理函数   
    //------------------------------------------------------------------------------------------------------   
    receive_interrupt()   
    {   
       
    }   
       
    //------------------------------------------------------------------------------------------------------   
    // 函数类别   中断函数   
    // 函数名称   SJA_INTR   
    // 入口函数   无   
    // 出口函数   无   
    // 操作寄存器 中断寄存器(地址03)   
    // 函数功能   中断分析,判断是什么中断,调用相应的中断处理函数   
    //------------------------------------------------------------------------------------------------------   
    void SJA_INTR() interrupt 0 using 1 //CanBus接口芯片产生中断(INTR0)   
    {   
      unsigned char sta;   
      unsigned char temp;   
      EX0 = 0;   
      sta = CANREG_read(3);            //读中断寄存器   
      temp = sta & 0x20;   
      if(temp == 0x20)   
        SJA1000_init();    
      temp = sta & 0x04;   
      if(temp == 0x04)   
        SJA1000_init();                 //消极错误中断,错误报警中断,均导致重启   
      temp = sta & 0x02;   
      if(temp == 0x02)                  //发送中断处理   
        {   
        send_interrupt();   
        }   
      temp = sta & 0x01;   
      if(temp == 0x01)                   //接收中断,接收数据   
      {   
       receive_interrupt();   
      }     
      EX0 = 1;   
    }   
    main()   
    {   
    }   
              本程序是基于51单片机的CAN(sja1000)通信协议的操作程序,利用51单片机的中断来操作,每个函数都有详细的注释,希望能帮助到初学者,在main函数中没有任何函数调用,自己可以根据需要进行调用。

    转载于:https://www.cnblogs.com/wanghuaijun/p/6272319.html

    展开全文
  • CAN总线学习系列之七——CAN总线软件编程 在编写CAN总线通讯程序时,主要编写函数由初始化函数,发送函数和接收函数组成。 其中发送函数一般写为主动发送函数,接收函数一般采用中断接收。下面就简单介绍一下三个...
  • 1、CAN简介 CAN 是 Controller Area Network 的缩写,是 ISO 国际标准化的串行通信协议。它是由研发和生产汽车电子产品著称的德国 BOSCH公司开发的,并最终成为国际标准(ISO11519),是国际上应用最广泛的现场总线...
  • 主要是调用API函数(API的操作请参考相关说明文档)对下位机进行操作,下位机采集的数据再返回回上位机显示,显示部分使用了TeeChart控件,后面我会再次写博客介绍该控件的使用,这篇文章主要讲解如何编写CAN通讯的...
  • 关于stm32 can通讯的一些总结 1.相对而言,我使用只是一主一从,两个终端的通信。所以两边都是加上终端电阻120欧,另外stm32的can通讯相对工业和汽车上使用的can通讯比较简单。stm32的库函数可以解决大多数问题。 2....
  • 一、一个FIFO最多可存储几组CAN数据? 手册里介绍了RX FIFO的寄存器数据结构,0x90-0xDC保留用作存储FIFO引擎,它里面的结构和上面0x80~0x90完全一样吗?也是16个字节吗?好像没有说明。根据大小计算0xDC-0x90=0x4C...
  • 51单片机串口通讯UART

    2018-12-25 20:47:51
    1、串行通信的的基本知识 在实际的工业生产,或者生活中,计算机的CPU要与外部的设备之间进行信息的交流,数据的交换,所有的这些信息交换均可称为通信。 通信的方式有两种,分别为串行通信和并行通信。...
  • CAN通讯总结-基于STM32

    2018-06-29 15:10:03
    CAN模式 一.工作模式 通过CAN_MCR寄存器控制INRQ和SLEEP 1.初始化INRQ=1 SLEEP=0 软件初始化应该在硬件 2.正常INRQ=0 SLEEP=0 在初始化完成后,软件应该让硬件进入正常模式,以便正常接收和发送报文 3.睡眠...
  •     ... 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。...
  • 我们进修串口通讯次要是要完成单片机和电脑之间的信息交互,可以用电脑掌握单片机的一些信息,可以把单片机的一些信息情况发给电脑上的软件。下面我们就做一个复杂的例程,完成单片机串口调试助手发送的数据,在我们...
  • STM32F103的CAN总线例程

    2020-07-28 23:33:02
    该例程STM32F103VBT6单片机关于CAN总线通信,本例程已经调试成功,用户在使用的过程中,请自行下载ST公司的固件库。
  • 起因:在使用stm32单片机can通讯时,参考手册的介绍与寄存器封装有差别,不好理解怎么去设置寄存器。在参考一些代码时,对怎么去设置过滤器还是难以理解。 解决:  在寄存器封装库中,我们发现CAN过滤器设置...
  • cubemx实现CAN通讯

    2018-10-18 15:04:11
    首先要安装cubemx跟Keil5两个编程软件 然后打开cubemx软件,新建一个工程项目: 输入CPU型号: 在右下角双击CPU具体型号 稍等片刻会打开如下对话框: 首先要配置系统的调试方式:我们选择SW方式 ...
  • 很多时候,工业控制或者产品设计方面受...单片机与人机界面触摸屏通讯的最简单,最有效的 2种方法,其实就是分为2种通讯协议,即工业标准的 Modbus RTU协议和工程师自己定义的 自由协议。 本实例采用其中一款人机界
  • 单片机4051与触摸屏的通信程序,应用于工业现场控制
1 2 3 4 5 ... 20
收藏数 1,132
精华内容 452
关键字:

单片机can通讯编程