基于51单片机SJA1000 CAN通讯实现

发布者:SerendipityGlow最新更新时间:2018-09-09 来源: eefocus关键字:51单片机  SJA1000  CAN通讯 手机看文章 扫描二维码
随时随地手机看文章

经过一个星期的艰苦奋斗,终于将两个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自收发程序记录

推荐阅读最新更新时间:2024-03-16 16:13

c51单片机第二课笔记
1震荡周期:就是晶振震荡一次所用的时间。也叫做时钟周期 机器周期:单片机完成一次独立的操作需要的时间。是震荡周期的12倍。 指令周期:cpu完成一次完整的操作需要的所有时间,有单周期指令,双周期指令等。 2 用循环左移,循环右移指令 实现流水灯。 int temp; temp=0xfe; P1=temp; temp=_crol_(temp,1); 有关循环指令包含在intrins.h头文件中。 3 对蜂鸣器的操作,类似与对led的操作,对相应端口输出第电平。关于蜂鸣器的数据有待补充。 4 共阴极led显示器16进制编码表 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77
[单片机]
51单片机IO口模拟串口通讯2-计数法
硬件环境:STC89C52 软件环境:IDE Keil uVision V4.10 编译器 C51 V9.0 代码如下: /********************************************** 方法2:计数法 硬件:11.0592MHz晶振,STC89C52,RXD P1.0 TXD P1.1 波特率:9600 描述:所谓计数法是指根据模拟出的波特率,每1位持续的时间的长短是通过定时器计数 溢出来置标志位,查询该标志位来实现的。 测试1:上电发送1个0x02的字符 测试2:上电先发送1个0x02的字符,然后等待接收,将收到的字符再发送出去(分别一个一个发送0x01,0x02,0x03,0x0
[单片机]
<font color='red'>51单片机</font>IO口模拟串口<font color='red'>通讯</font>2-计数法
51单片机在微机自动交换系统中稳定运行的设计
  MCS—51 单片机 在电力线载波通信中处理任务时的实时性尤为突出。由于该系统整机配置的主要服务对象是电力调度,且它的使用环境将来多为无人值守站,所以系统工作是否稳定直接影响到电力线载波机的整机性能。针对电力通信特点,在考虑稳定运行方面我们采取了以下几项措施。   1 设置上电延时复位电路   1.1 为什么要进行上电复位46   计算机在启动运行时都要进行复位。作为在控制领域中应用最广泛的单片机,复位处理更是设计中的关键。单片机内部的各个功能部件均受特殊功能寄存器控制,程序运行直接受程序计数器指挥,寄存器的复位状态决定了单片机内有关功能部件工作用的初始状态,而程序的正常运行就是从这个状态开始的。如果上电时没有做到正
[单片机]
<font color='red'>51单片机</font>在微机自动交换系统中稳定运行的设计
51单片机学习笔记:连续读写STC89C52RC内部EEPROM存储器
STC单片机的内部EEPROM是用DATAFLASH模拟出来的,不是真正的EEPROM存储器,不能用普通的方法来操作 下面是一些注意点: 1.字节写之前要先将这个字节所在扇区的其它有效数据读取到RAM暂存(这步不是必须的) 2.暂存完之后再对整个扇区(512字节)进行擦除操作,擦拭完后,整个扇区每个地址中数据都变成0xFF 3.将欲写入的N个字节数据,用字节写函数写入EEPROM 4.将暂存到RAM的其它有用的EEPROM值再用字节写函数写回EEPROM 5.STC用FLASH模拟出来的EEPROM的字节写功能只能将1变成0,而不能将0变成1, 只有扇区擦除后数据才是全1, 例如:在地址0x21f0处第1次写11010110,
[单片机]
<font color='red'>51单片机</font>学习笔记:连续读写STC89C52RC内部EEPROM存储器
基于51单片机的多功能时钟温度计 DS1302+LCD1602
本设计是由STC89C52单片机为控制核心,具有在线编程功能,低功耗;时钟电路由DS1302提供,它是一种高性能、低功耗的时钟电路,工作电压为3V~5V;所以采用DS1302作为本设计的日历芯片;显示部份使用LCD1602B液晶模块进行数字显示,1602B液晶模块可以显示2行16个字符,有8位数据总线D0—D7,和RS、R/W、EN三个控制端口,工作电压为5V,并且带有字符对比度调节和背光。该模块也可以只用D4-D7作为四位数据分两次传送,这样就可以节省MCU的I/O口资源,系统主要由晶振电路、复位电路、时钟电路部分、中央处理单元、晶显示部分组成。 电路原理图如下: 制作出来的实物图如下: Altium Designer画的
[单片机]
基于<font color='red'>51单片机</font>的多功能时钟温度计 DS1302+LCD1602
51单片机四位数码管4个LED灯4个按键实现多种功能
任务描述:用89C51单片机实现如下功能: 初始状态为数码管显示2020,四个灯灭。 1、电路有四个控制按键,四个灯,四个数码管; 2、按键1,按下,,第一个数码管开始从0-9递增,同时第一个灯亮; 3、按键2,按下,第二个数码管开始从0-9显示偶数,同时四个灯的偶数灯亮(即2、4个灯亮); 4、按键3,按下,第三个数码管从0-9显示奇数,同时四个灯的奇数灯亮(即1、3个灯亮); 5、按键4,按下,恢复到初始状态 硬件电路图 元件清单 C语言程序 #include reg51.h unsigned char tube1 ={0x5b,0x3f,0x5b,0x3f};//数码管初始状态2020 字符码 unsigned
[单片机]
<font color='red'>51单片机</font>四位数码管4个LED灯4个按键实现多种功能
MCS51单片机的定时器/计数器概念 非常好的寄存器关系图
一、MCS-51单片机的定时器/计数器概念 单片机中的定时器和计数器其实是同一个物理的电子元件,只不过计数器记录的是单片机外部发生的事情(接受的是外部脉冲),而定时器则是由单片机自身提供的一个非常稳定的计数器,这个稳定的计数器就是单片机上连接的晶振部件;MCS-51单片机的晶振经过12分频之后提供给单片机的只有1MHZ的稳定脉冲;晶振的频率是非常准确的,所以单片机的计数脉冲之间的时间间隔也是非常准确的,这个准确的时间间隔是1微秒; MCS-51单片机外接的是12MHZ的晶振(实际上是11.0592MHZ),所以,MCS-51单片机内部的工作频率(时钟脉冲频率)是12MHZ/12=1MHZ=1000000次/秒=1000000条指令
[单片机]
MCS<font color='red'>51单片机</font>的定时器/计数器概念 非常好的寄存器关系图
51单片机RS485程序源码与proteus仿真图
单片机-485-PC串口通信.jpg (106.21 KB, 下载次数: 21) 下载附件 保存到相册 2018-3-26 01:45 上传 单片机源程序如下: #include reg51.h #include intrins.h #define uchar unsigned char #define uint unsigned int sbit P12=P1^2; char code str = you are the best! nr ; main() { uint j; TMOD=0x20; TL1=0xfd;TH1=0xfd; SCON=0x50; PCON &= 0xef; TR1=1; IE=
[单片机]
<font color='red'>51单片机</font>RS485程序源码与proteus仿真图
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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