各位大神能帮忙分析下代码不?关于C8051F040的CAN通信。

2020-01-26 13:07发布

//////////////////////////此为接收函数///////////////////////
两个板子之间相互通信。
自测试通信OK。

#include<c8051f040.h>
#include<can.h>
#include <intrins.h>
#define uchar unsigned char                 //宏定义   0-255
#define uint unsigned int               //宏定义   0-65535
uchar ch;                    //串口接收变量      
bit flag;           //串口接收标志       
uchar status;                                                                                //状态
void PORT_Init();
void external_osc();
sbit switch1=P7^6;
sbit LED=P6^6;
bit RX_flag;
bit TX_flag;
bit eror_flag;
void clear_msg_objects();
void start_CAN();
void init_msg_object_TX (uchar MsgNum,uint id);
void init_msg_object_RX (uchar MsgNum,uchar id);  
void transmit_message(uchar MsgNum);
void receive_data(uchar MsgNum);
uchar JJJ;
uint CAN_TX[8]={0,0,0,0,0,0,0,0};
uint CAN_RX[8]={0,0,0,0,0,0,0,0};
void delayms(uint x)
{
   uint t;
   while(x--)
   {
         for(t=0;t<110;t++);
   }
}

void UART0_Init()
{
    SFRPAGE   = UART0_PAGE;
    SCON0     = 0x50;                                                  //允许uart0,8位UART,可变波特率,UART接收允许,使能波特率二分频功能
}
void TIMER1_Init()
{
    SFRPAGE   = TIMER01_PAGE;
    TCON      = 0X50;                                     //定时器1允许
        TMOD      = 0x21;                                                     //自动重装载8位定时计数器
    CKCON     = 0X18;                                     //定时器1使用系统时钟
        TH1       = 0xFD;
        TL1       = 0xFD;
        TR1=1;
}
void PORT_Init()
{
   SFRPAGE=CONFIG_PAGE;
   P6MDOUT=0Xff;
   P7MDOUT=0Xff;
   XBR3|=0X80;
   XBR2= 0X40;                             //该处可设定弱上拉使能
   XBR0= 0x05;
}
void external_osc(void)
{
   uchar n;
   SFRPAGE=CONFIG_PAGE;
   OSCXCN|=0X77;
   for(n=0;n<255;n++);
   while((OSCXCN&0x80)==0);
   CLKSEL|=0x01;
}
//-----------------------------------------------------------------------------
// 函数名:void clear_msg_objects(void)
// 功  能:清除消息对象
// 描  述:   
//-----------------------------------------------------------------------------
void clear_msg_objects(void)
{
  uchar i, IDL=4,j;
  unsigned short data_temp=0x0101;
  SFRPAGE=CAN0_PAGE;
  CANINIT=1;
  CAN0ADR=IF1CMDMSK;           //命令掩码寄存器
  CAN0DATL=0Xf3;           //写数据                    
  for(i=1;i<=8;i++)                   //i表示消息对象
  {
    CAN0ADR=IF1MSK1;
    CAN0DATA=0X0000;
    CAN0DATA=0X0000;                           //需要修改  IDE过滤
    CAN0ADR=IF1ARB2;
    CAN0DATH=0Xa0;  
    CAN0DATL=IDL;
    IDL += 4;
    CAN0DATA=0X0088;               //IF1MSGC

    CAN0ADR=IF1CMDRQST;
    while((CAN0DATH & 0X80) == 1);
    CAN0DATL=i;
  }
  IDL=0x04;
  for(;i<=16;i++)
  {                       
    CAN0ADR=IF1MSK1;
    CAN0DATA=0XFFFF;
    CAN0DATA=0X1FFF;                       //需要修改  IDE过滤
    CAN0ADR=IF1ARB2;
    CAN0DATH=0XA0;  
    CAN0DATL=IDL;
    IDL += 4;
    CAN0DATA=0X1080;                       //可设定newdata引发intpnd

    CAN0ADR=IF1CMDRQST;
    while((CAN0DATH & 0X80) == 1);
    CAN0DATL=i;
  }
  CANINIT=0;
  CAN0ADR=IF1CMDMSK;
  CAN0DATL=0X87;                         //87  控制位等不改
  for(i=1;i<=8;i++)
  {
    CAN0ADR=IF1DATA1;  
    for(j=1;j<=4;j++)
        {
      CAN0DATA=data_temp;
      data_temp+=257;
    }
    CAN0ADR=IF1CMDRQST;
    CAN0DATL=i;           //这里发送
  }      
}
void init_msg_object_TX (uchar MsgNum,uint id)
{
    uint tempreg;
    SFRPAGE = CAN0_PAGE;
    CAN0ADR = IF1CMDMSK;         //指向命令掩码寄存器
    CAN0DATA = 0x00b3;                           //设为写,改变所有的消息对象除了标识掩码位,将数据字节0-7发送到消息对象
    /*   IF1 Command Mask Registers  =0x00b3
    WR/RD=1,Mask=1,Arb=1,Control=1,ClrIntPnd=0,TxRqst=0,DataA=1,DataB=1,一次发送8字节数据*/
    CAN0ADR = IF1ARB1;           //指向IF1仲裁寄存器1  
    CAN0DATA = 0x0000;                   //ID15-0:0000;将仲裁ID设为最高优先级
    /*IF1 Arbitration Registers1 =0x0000,即ID15-0=0*/
    tempreg=id<<2;//标准id为ID28-ID18,所以要左移2位
    tempreg&=0x1fff;
    tempreg|=0xa000;
    CAN0DATA = tempreg; ////自动增加地址到IF1仲裁寄存器2
    /*IF1 Arbitration Registers2=101(id)00b
    MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=1,为发送*/
    CAN0DATA = 0x0088;             //IF1消息控制寄存器:DLC = 1,禁止远程桢
         /*IF1 Message Control Registers=0x0088
    NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,RxIE=0,RmtEn=0,TxRqst=0
    EoB=1,DLC3-0=1000,即数据长度为8*/
    CAN0ADR = IF1CMDRQST;       //指向IF1命令请求寄存器  
    CAN0DATL = MsgNum;   
    /*IF1 Command Request Registers=MsgNum,将以上配置写入MsgNum号消息*/
}
void init_msg_object_RX (char MsgNum,uchar id)
{
    uint temp;
    SFRPAGE = CAN0_PAGE;
    CAN0ADR = IF2CMDMSK;
    CAN0DATA = 0x00bb;            
    /*   IF2 Command Mask Registers  =0x00bb
    WR/RD=1,Mask=0,Arb=1,Control=1,ClrIntPnd=1,TxRqst=0,DataA=1,DataB=1,一次发送8字节数据*/
    CAN0ADR = IF2ARB1;        //指向IF2仲裁寄存器   
    CAN0DATA = 0x0000;
    /*IF2 Arbitration Registers1 =0x0000,即ID15-0=0*/            
    temp=id<<2;//标准id为ID28-ID18,所以要左移2位
    temp&=0x1fff;
    temp|=0x8000;
    CAN0DATA = temp;
    /*IF2 Arbitration Registers2=100(id)00b
    MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=0,为接收*/
    CAN0DATA = 0x0488;
    /*IF2 Message Control Registers=0x0488
    NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,RxIE=1,接收中断使能;RmtEn=0,TxRqst=0
    EoB=1,DLC3-0=1000,即数据长度为8*/
    CAN0ADR = IF2CMDRQST;        
    CAN0DATL = MsgNum;           
      /*IF2 Command Request Registers=MsgNum,将以上配置写入MsgNum号消息*/
}
void start_CAN(){
  SFRPAGE=CAN0_PAGE;
//  CAN0CN|=0X00C1;   // 开测试和bt设置
//  CAN0CN&=0XFFd7;   //自动重发开启  错误中断禁止
  CAN0CN|=0X0041;          //使能CCE和INIT位
//  CAN0ADR=CANTSTR;
//  CAN0DATL|=0X10;
  CAN0ADR=BITREG;
  CAN0DATA=0X2640;
  CAN0ADR = IF1CMDMSK;                                                        //指向命令掩码寄存器1
  CAN0DATA = 0x0087;                                                                //写:
//设置CAN RAM为写,写数据字节,                                                                                                        //设置发送请求位
                                                                                                        //将发送0---3发送到消息对象
                                                                                                        //将发送4---7发送到消息对象
  CAN0ADR = IF2CMDMSK;                                                        //指向命令掩码寄存器2(设置接收,读CAN_RAM,读数据字节)
  CAN0DATL = 0x1f;                                                                //设置为接受
                                                                                                        //掩码位不变
                                                                                                        //仲裁位不变
                                                                                                        //发送控制位到IFx消息缓冲寄存器
                                                                                                        //清除消息对象中断挂起位
                                                                                                        //清除消息对象中的NewData位
                                                                                                        //将数据字节0---3字节发送到消息缓冲寄存器中
                                                                                                        //将数据字节4---7字节发送到消息缓冲寄存器中

  CAN0CN|=0X0006;
  CAN0CN&=0XFFBE;
}
void transmit_message(uchar MsgNum)
{
//   uchar i;
   SFRPAGE=CAN0_PAGE;         //指向CAN0页面
   CAN0ADR=IF1CMDMSK;         //向IF1命令屏蔽寄存器写入命令
   CAN0DATL=0X0083;
   CAN0ADR=IF1ARB2;           //指向IF1仲裁寄存器2
   CAN0DATH|=0x80;
   CAN0ADR=IF1DATA1;          //指向数据场的第一个字节
/*   for(i=0;i<4;i++)
   {
    CAN0DATA=CAN_TX[i];      //将4字节数据写入发送缓冲器
   }*/
   CAN0DATL=0x22;
   CAN0ADR=IF1CMDRQST;
   CAN0DATL=MsgNum;          //将报文对象编号写入,则数据发送到对应的报文对象中
}
void receive_data(uchar MsgNum)
{
// uchar i;
  SFRPAGE=CAN0_PAGE;          //指向CAN0页面
  CAN0ADR=IF2CMDMSK;          //向IF2命令屏蔽寄存器写命令
  CAN0DATA=0x003F;
  CAN0ADR=IF2CMDRQST;        //将报文对象编号写入命令请求寄存器,对应地接收
  CAN0DATL=MsgNum;           //得到数据就从报文RAM中移到数据缓冲器中
  CAN0ADR=IF2DATA1;          //指向数据场的第一个字节
/* for(i=0;i<4;i++)                 //读取4个字节数据
  {
     CAN_RX[i]=CAN0DATA;
  }        */
  JJJ=CAN0DATL;
}  
void main()
{
  WDTCN = 0xde;
  WDTCN = 0xad;
  SFRPAGE = CONFIG_PAGE;
  PORT_Init();
  external_osc();
  clear_msg_objects();
  init_msg_object_TX(0x02,5);                //广播发送
  start_CAN();
  init_msg_object_RX(0x02,7);
//  while(switch1==1);
  UART0_Init();                                  //串口初始化
  TIMER1_Init();                             //定时器1初始化
  RX_flag=0;
  TX_flag=0;
  eror_flag=0;
  EIE2 = 0x20;//允许can0中断
  EIP2 |= 0x20;
  ES0=1;
  EA = 1;
  while(1)  
  {
            receive_data(0x02);
          if(RX_flag==1)
          {
                   RX_flag=0;
                 LED=!LED;
                 delayms(500);
          }
  }
}
void inter_CAN(void) interrupt 19
{
    SFRPAGE  = CAN0_PAGE;
    status = CAN0STA;       //读状态寄存器
    if ((status&0x10) != 0)                                                   //Rxok位为1,则是由于接收引起的中断
    {                                          
        CAN0STA = (CAN0STA&0xEF)|0x07;              //复位Txok,设置LEC无变化
                RX_flag=1;                       //接受中断标志位置位
//      receive_data ();                    // Up to now, we have only one RX message
    }
    if ((status&0x08) != 0)                                  //Txok位为1,则是由于发送引起的中断
    {                                    
         CAN0STA = (CAN0STA&0xF7)|0x07;           //复位Txok,设置LEC无变化
                 TX_flag=1;                                                                //发送完成标志置位
    }
    if (((status&0x07) != 0)&&((status&0x07) != 7))          //错误中断,改变LEC
    {                                          
        CAN0STA = CAN0STA|0x07;                  //设置LEC无变化
                eror_flag=1;
    }
}
void UART0_ISR(void) interrupt 4               
{       
        if(RI0)
        {       
                ch=SBUF0;
                if(ch==0xaa)
                {
                   flag=1;       
                }
                RI0=0;
        }
        if(flag==1)
        {
                flag=0;
                SBUF0=JJJ;
                while(TI0==0);
                TI0=0;       
        }
}








/////////////////////////////////////此为发送函数////////////////////////
#include<c8051f040.h>
#include<can.h>
#include <intrins.h>
#define uchar unsigned char                 //宏定义   0-255
#define uint unsigned int               //宏定义   0-65535
uchar status;                                                                                //状态
void PORT_Init();
void external_osc();
sbit switch1=P5^0;
sbit LED=P6^6;
bit RX_flag;
bit TX_flag;
bit eror_flag;
void clear_msg_objects();
void start_CAN();
void init_msg_object_TX (uchar MsgNum,uint id);
void init_msg_object_RX (uchar MsgNum,uchar id);  
void transmit_message(uchar MsgNum);
void receive_data(uchar MsgNum);
uint CAN_TX[8]={0,0,0,0,0,0,0,0};
uint CAN_RX[8]={0,0,0,0,0,0,0,0};
void delayms(uint x)
{
   uint t;
   while(x--)
   {
         for(t=0;t<110;t++);
   }
}
void PORT_Init()
{
   SFRPAGE=CONFIG_PAGE;
   P6MDOUT=0Xff;
   P7MDOUT=0Xff;
   XBR3|=0X80;
   XBR2=0X40;                             //该处可设定弱上拉使能
}
void external_osc(void)
{
   uchar n;
   SFRPAGE=CONFIG_PAGE;
   OSCXCN|=0X77;
   for(n=0;n<255;n++);
   while((OSCXCN&0x80)==0);
   CLKSEL|=0x01;
}
//-----------------------------------------------------------------------------
// 函数名:void clear_msg_objects(void)
// 功  能:清除消息对象
// 描  述:   
//-----------------------------------------------------------------------------
void clear_msg_objects(void)
{
  uchar i, IDL=4,j;
  unsigned short data_temp=0x0101;
  SFRPAGE=CAN0_PAGE;
  CANINIT=1;
  CAN0ADR=IF1CMDMSK;           //命令掩码寄存器
  CAN0DATL=0Xf3;           //写数据                    
  for(i=1;i<=8;i++)                   //i表示消息对象
  {
    CAN0ADR=IF1MSK1;
    CAN0DATA=0X0000;
    CAN0DATA=0X0000;                           //需要修改  IDE过滤
    CAN0ADR=IF1ARB2;
    CAN0DATH=0Xa0;  
    CAN0DATL=IDL;
    IDL += 4;
    CAN0DATA=0X0088;               //IF1MSGC

    CAN0ADR=IF1CMDRQST;
    while((CAN0DATH & 0X80) == 1);
    CAN0DATL=i;
  }
  IDL=0x04;
  for(;i<=16;i++)
  {                       
    CAN0ADR=IF1MSK1;
    CAN0DATA=0XFFFF;
    CAN0DATA=0X1FFF;                       //需要修改  IDE过滤
    CAN0ADR=IF1ARB2;
    CAN0DATH=0XA0;  
    CAN0DATL=IDL;
    IDL += 4;
    CAN0DATA=0X1080;                       //可设定newdata引发intpnd

    CAN0ADR=IF1CMDRQST;
    while((CAN0DATH & 0X80) == 1);
    CAN0DATL=i;
  }
  CANINIT=0;
  CAN0ADR=IF1CMDMSK;
  CAN0DATL=0X87;                         //87  控制位等不改
  for(i=1;i<=8;i++)
  {
    CAN0ADR=IF1DATA1;  
    for(j=1;j<=4;j++)
        {
      CAN0DATA=data_temp;
      data_temp+=257;
    }
    CAN0ADR=IF1CMDRQST;
    CAN0DATL=i;           //这里发送
  }      
}
void init_msg_object_TX (uchar MsgNum,uint id)
{
    uint tempreg;
    SFRPAGE = CAN0_PAGE;
    CAN0ADR = IF1CMDMSK;         //指向命令掩码寄存器
    CAN0DATA = 0x00b3;                           //设为写,改变所有的消息对象除了标识掩码位,将数据字节0-7发送到消息对象
    /*   IF1 Command Mask Registers  =0x00b3
    WR/RD=1,Mask=1,Arb=1,Control=1,ClrIntPnd=0,TxRqst=0,DataA=1,DataB=1,一次发送8字节数据*/
    CAN0ADR = IF1ARB1;           //指向IF1仲裁寄存器1  
    CAN0DATA = 0x0000;                   //ID15-0:0000;将仲裁ID设为最高优先级
    /*IF1 Arbitration Registers1 =0x0000,即ID15-0=0*/
    tempreg=id<<2;//标准id为ID28-ID18,所以要左移2位
    tempreg&=0x1fff;
    tempreg|=0xa000;
    CAN0DATA = tempreg; ////自动增加地址到IF1仲裁寄存器2
    /*IF1 Arbitration Registers2=101(id)00b
    MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=1,为发送*/
    CAN0DATA = 0x0088;             //IF1消息控制寄存器:DLC = 1,禁止远程桢
         /*IF1 Message Control Registers=0x0088
    NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,RxIE=0,RmtEn=0,TxRqst=0
    EoB=1,DLC3-0=1000,即数据长度为8*/
    CAN0ADR = IF1CMDRQST;       //指向IF1命令请求寄存器  
    CAN0DATL = MsgNum;   
    /*IF1 Command Request Registers=MsgNum,将以上配置写入MsgNum号消息*/
}
void init_msg_object_RX (char MsgNum,uchar id)
{
    uint temp;
    SFRPAGE = CAN0_PAGE;
    CAN0ADR = IF2CMDMSK;
    CAN0DATA = 0x00bb;            
    /*   IF2 Command Mask Registers  =0x00bb
    WR/RD=1,Mask=0,Arb=1,Control=1,ClrIntPnd=1,TxRqst=0,DataA=1,DataB=1,一次发送8字节数据*/
    CAN0ADR = IF2ARB1;        //指向IF2仲裁寄存器   
    CAN0DATA = 0x0000;
    /*IF2 Arbitration Registers1 =0x0000,即ID15-0=0*/            
    temp=id<<2;//标准id为ID28-ID18,所以要左移2位
    temp&=0x1fff;
    temp|=0x8000;
    CAN0DATA = temp;
    /*IF2 Arbitration Registers2=100(id)00b
    MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=0,为接收*/
    CAN0DATA = 0x0488;
    /*IF2 Message Control Registers=0x0488
    NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,RxIE=1,接收中断使能;RmtEn=0,TxRqst=0
    EoB=1,DLC3-0=1000,即数据长度为8*/
    CAN0ADR = IF2CMDRQST;        
    CAN0DATL = MsgNum;           
      /*IF2 Command Request Registers=MsgNum,将以上配置写入MsgNum号消息*/
}
void start_CAN(){
  SFRPAGE=CAN0_PAGE;
//  CAN0CN|=0X00C1;   // 开测试和bt设置
//  CAN0CN&=0XFFd7;   //自动重发开启  错误中断禁止
  CAN0CN|=0X0041;          //使能CCE和INIT位
//  CAN0ADR=CANTSTR;
//  CAN0DATL|=0X10;
  CAN0ADR=BITREG;
  CAN0DATA=0X2640;
  CAN0ADR = IF1CMDMSK;                                                        //指向命令掩码寄存器1
  CAN0DATA = 0x0087;                                                                //写:
//设置CAN RAM为写,写数据字节,                                                                                                        //设置发送请求位
                                                                                                        //将发送0---3发送到消息对象
                                                                                                        //将发送4---7发送到消息对象
  CAN0ADR = IF2CMDMSK;                                                        //指向命令掩码寄存器2(设置接收,读CAN_RAM,读数据字节)
  CAN0DATL = 0x1f;                                                                //设置为接受
                                                                                                        //掩码位不变
                                                                                                        //仲裁位不变
                                                                                                        //发送控制位到IFx消息缓冲寄存器
                                                                                                        //清除消息对象中断挂起位
                                                                                                        //清除消息对象中的NewData位
                                                                                                        //将数据字节0---3字节发送到消息缓冲寄存器中
                                                                                                        //将数据字节4---7字节发送到消息缓冲寄存器中

  CAN0CN|=0X0006;
  CAN0CN&=0XFFBE;
}
void transmit_message(uchar MsgNum)
{
//   uchar i;
   SFRPAGE=CAN0_PAGE;         //指向CAN0页面
   CAN0ADR=IF1CMDMSK;         //向IF1命令屏蔽寄存器写入命令
   CAN0DATL=0X0083;
   CAN0ADR=IF1ARB2;           //指向IF1仲裁寄存器2
   CAN0DATH|=0x80;
   CAN0ADR=IF1DATA1;          //指向数据场的第一个字节
/*   for(i=0;i<4;i++)
   {
    CAN0DATA=CAN_TX[i];      //将4字节数据写入发送缓冲器
   }*/
   CAN0DATL=0x22;
   CAN0ADR=IF1CMDRQST;
   CAN0DATL=MsgNum;          //将报文对象编号写入,则数据发送到对应的报文对象中
}
void receive_data(uchar MsgNum)
{
  uchar i;
  SFRPAGE=CAN0_PAGE;          //指向CAN0页面
  CAN0ADR=IF2CMDMSK;          //向IF2命令屏蔽寄存器写命令
  CAN0DATA=0x003F;
  CAN0ADR=IF2CMDRQST;        //将报文对象编号写入命令请求寄存器,对应地接收
  CAN0DATL=MsgNum;           //得到数据就从报文RAM中移到数据缓冲器中
  CAN0ADR=IF2DATA1;          //指向数据场的第一个字节
  for(i=0;i<4;i++)                 //读取4个字节数据
  {
     CAN_RX[i]=CAN0DATA;
  }
}  
void main()
{
  WDTCN = 0xde;
  WDTCN = 0xad;

  PORT_Init();
  external_osc();
  clear_msg_objects();
  init_msg_object_TX(0x02,5);                //广播发送
  start_CAN();
//  init_msg_object_rx(0x01,1);
  while(switch1==1);
  RX_flag=0;
  TX_flag=0;
  eror_flag=0;
  EIE2 = 0x20;//允许can0中断
//  EIP2 |= 0x20;
  EA = 1;
  while(1)  
  {
            transmit_message(0x02);
          if(TX_flag==1)
          {
                   TX_flag=0;
                 LED=!LED;
                 delayms(500);
          }
  }
}
void inter_CAN(void) interrupt 19
{
    SFRPAGE  = CAN0_PAGE;
    status = CAN0STA;       //读状态寄存器
    if ((status&0x10) != 0)                                                   //Rxok位为1,则是由于接收引起的中断
    {                                          
        CAN0STA = (CAN0STA&0xEF)|0x07;              //复位Txok,设置LEC无变化
                RX_flag=1;                       //接受中断标志位置位
//      receive_data ();                    // Up to now, we have only one RX message
    }
    if ((status&0x08) != 0)                                  //Txok位为1,则是由于发送引起的中断
    {                                    
         CAN0STA = (CAN0STA&0xF7)|0x07;           //复位Txok,设置LEC无变化
                 TX_flag=1;                                                                //发送完成标志置位
    }
    if (((status&0x07) != 0)&&((status&0x07) != 7))          //错误中断,改变LEC
    {                                          
        CAN0STA = CAN0STA|0x07;                  //设置LEC无变化
                eror_flag=1;
    }
}

0条回答

一周热门 更多>