⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 can.c

📁 AT90CAN128的CAN通信源码测试成功
💻 C
字号:
/******************************************************************** 
*  函数库说明:CAN总线驱动函数库                                    * 
*  版本说明:  1.0 Bate                                             * 
*  作者:      andylee                                              * 
*  日期:      2006年7月                                            * 
*  平台:      mega16  16M                                          * 
*  说明:      为上层提供CAN控制器的基本读写函数,数据发送、接受函数* 
********************************************************************/ 
#include "can.h"
#include "delay.h"

//#define DEBUG
#define TransBuffer TransmitMessage
/*********************
* 全局变量定义       *
*********************/
//unsigned char CanMode[14];
unsigned char TransmitMessage[13];
unsigned char RxBuffer[13];
#ifdef DEBUG
unsigned char temp1;
#endif

/********************************************************** ********** 
*  函数说明:CAN控制器引脚初始化                                    * 
*  输入:                                                           * 
*  输出:无                                                         * 
********************************************************************/
void sja_port_init(void)
{ 
 //CAN数据线设置
   PORTC=0x00;
   DDRC=0xff;
   PORTD=0b11000000;          //INT引脚输入不上拉
   DDRD =0b11111000;
 //CAN 控制引脚设置
  CAN_DDR|=(1<<WR)|(1<<RD)|(1<<ALE)|(1<<CS);
  WR_H;
  RD_H;
  ALE_L;
  CS_H;
}

/******************************************************************** 
*  函数说明:模拟CAN收发时序,写一个字节到CAN控制器                 * 
*  输入:data,address                                               * 
*  输出:无                                                         * 
********************************************************************/
void sja_write_data(unsigned char addr,unsigned char data)
{
 RD_H;
 DDRC=0xFF; //总线设置为输出
// ALE_L;
 PORTC=addr; 
 ALE_H;
 NOP();
 ALE_L;    //下降沿地址锁存
 NOP();
 
 PORTC=data;
 CS_L;
 WR_L;
 NOP();
 WR_H;     //上升沿数据写入
 NOP();
// ALE_H;
 CS_H;
}

/******************************************************************** 
*  函数说明:模拟CAN收发时序,从CAN控制器读一个字节                 * 
*  输入:address                                                    * 
*  输出:data                                                       * 
********************************************************************/
unsigned char sja_read_data(unsigned char addr)
{
 unsigned char data;
 WR_H;
 DDRC=0xFF; //总线设置为输出
 
 ALE_L;
 PORTC=addr;
 ALE_H;
 NOP();
 ALE_L;    //地址锁存
 NOP();
 
 PORTC=0xFF;  
 DDRC=0x00;   //总线设置为输入,内部上拉
 CS_L;
 RD_L;
 NOP();
 RD_H;
 NOP();
 data=PINC;
 CS_H;
 return data;
}

/******************************************************************** 
*  函数说明:初始化SJA1000的相关寄存器:设置工作模式,波特率,验收码* 
*  输入:无                                                         * 
*  输出:无                                                         * 
********************************************************************/
void sja_init(void)                
{
    unsigned char temp;
    unsigned int k ; 
	
    CLI();                 
    sja_write_data(MODE,0x09);            //单个验收滤波,复位模式
	
    sja_read_data(IR);                  //读取CAN的中断标识,除接受中断外的所有中断复位
	
    while(!( sja_read_data(MODE)&0x01))   //检测SJA1000是否达到复位工作模式
    {
       sja_write_data(MODE,0x09);         //进入复位工作模式
    }   
    delay_nus(5);                         //延时约5us
    sja_write_data(CDR,REG_CDR_DATA);     //PeliCAN 模式,旁路输入比较器,禁能CLOCKOUT引脚
    delay_nus(5);                         //延时约5us
	
    sja_write_data(BTR0,BTR0_Rate_250k);           //同步跳转宽度4;时钟4分频,波特率250Kb/s
    sja_write_data(BTR1,BTR1_Rate_250k);           //采样3次;时间段1,2=10,5    

    sja_write_data(OCR,REG_OCR_DATA);    //输出控制,推拉结构,正逻辑
    
    sja_write_data(RXERR,0x00);          //收发错误寄存器清零
    sja_write_data(TXERR,0x00);
    sja_write_data(ECC,0x00);            //错误代码捕捉寄存器清零 

    sja_write_data(RBSA,0x00);            //缓存器起始地址寄存器设置为0
    
    sja_write_data(ACR0,ACR0_ID);         //验收屏蔽
    sja_write_data(ACR1,ACR1_ID);
    sja_write_data(ACR2,ACR2_ID);
    sja_write_data(ACR3,ACR3_ID);

    sja_write_data(AMR0,AMR0_ID);           
    sja_write_data(AMR1,AMR1_ID);
    sja_write_data(AMR2,AMR2_ID);
    sja_write_data(AMR3,AMR3_ID);

    sja_write_data(IER,REG_IER_DATA);     //开放接收中断
	
    sja_write_data(CMR,COS_CMD);          //清除数据溢出
	delay_nus(10);
	sja_write_data(CMR,RRB_CMD);          //释放接收缓冲器
	
    do
    {
       //sja_write_data(MODE,0x04);       //设置SJA1000 工作模式;zijiance
	   sja_write_data(MODE,0x08);         //设置SJA1000 工作模式
    }
    while((sja_read_data(MODE)&0x01));   //确认复位标志是否被删除    
	                  
    SEI();
}

/******************************************************************** 
*  函数说明:SJA1000中断发送服务程序,若有待发送报文则及时发送      * 
*  输入:无                                                         * 
*  输出:无                                                         * 
********************************************************************/
void sja_tx_service(void)
{
unsigned char Length;
unsigned char FF,i;
   if(flag.mess_wait==TRUE)
      {
	   led_on;
	   flag.mess_wait=FALSE;            //清报文待发送标志
	   FF=TransmitMessage[0]&0x80;          //取贞格式
	   Length=TransmitMessage[0]&0x0f;       //取数据长度代码
	
	   if(Length=0x08)
	      {
	        Length = 0x80;
	      }
	
	   sja_write_data(TXEFF,TransmitMessage[0]);           //写TX贞报文
       sja_write_data(TXID0,TransmitMessage[1]);           //写TX标识码1  
	   sja_write_data(TXID1,TransmitMessage[2]);         
	   if(FF)                                              //FF=0:标准CAN格式
	       {                                               //FF=1:扩展CAN格式
	          sja_write_data(TXID2,TransmitMessage[3]);
	          sja_write_data(TXID3,TransmitMessage[4]);
	       }   
	   for (i=0;i<Length;i++)
	      { 
	          if(FF)
	              sja_write_data(TXDATA0+i,TransmitMessage[5+i]);
	          else 
	              sja_write_data(TXDATA0+i,TransmitMessage[3+i]); 
	      }   
	   led_off; 
	  //置位发送请求
	  //sja_write_data(CMR,0x10);          //发送请求命令:zijieshou     
      sja_write_data(CMR,0x01);          //发送请求命令当错误时可重发                    
	  }
}

/******************************************************************** 
*  函数说明:SJA1000发送服务程序                                    * 
*  输入:RAM中以TransmitMessage开始的CAN的发送报文                  * 
*  输出:无                                                         * 
********************************************************************/
void sja_tx(unsigned char *TransmitMessage)
{
  unsigned char Length;
  unsigned char FF,i,state;
  
  unsigned char sreg;
  sreg=SREG;                               //保存全局中断标志
  CLI();
  
  state=sja_read_data(SR);     //读状态寄存器
  while(state&(1<<4));         //正在接受则等待
//  while(state&(1<<3));       //上次发送未完成则等待
  if(state&(1<<2))            //判断发送缓冲是否释放
  {
    led_on;
    FF=TransmitMessage[0]&0x80;          //取贞格式
	Length=TransmitMessage[0]&0x0f;       //取数据长度代码
	#ifdef DEBUG
	  rprintfCRLF(); 
	  rprintfStr("begin transmit..."); 
	  rprintfCRLF(); 	   
	#endif
	if(Length>8)
	{
	 Length = 8;
	}
	sja_write_data(TXEFF,TransmitMessage[0]);           //写TX贞报文
    sja_write_data(TXID0,TransmitMessage[1]);           //写TX标识码1  
    sja_write_data(TXID1,TransmitMessage[2]);         
	if(FF)                                         //FF=0:标准CAN格式
	{                                            //FF=1:扩展CAN格式
	sja_write_data(TXID2,TransmitMessage[3]);
	sja_write_data(TXID3,TransmitMessage[4]);
	}   
	for (i=0;i<Length;i++)
	{ 
	  if(FF)
	    sja_write_data(21+i,TransmitMessage[5+i]);
	  else 
	    sja_write_data(19+i,TransmitMessage[3+i]); 
	}    
	//置位发送请求
	//sja_write_data(CMR,0x10);          //发送请求命令 
	sja_write_data(CMR,0x01);          //发送请求命令当错误时可重发 
	led_off;        
	#ifdef DEBUG
	  rprintfStr("transmit over"); 
	  rprintfCRLF(); 
	  rprintfCRLF(); 	   
	#endif              
  }
  else                                    //发送缓冲被锁,将数据存入RAM缓存
  {
    flag.mess_wait=TRUE;
  }
  
  SREG=sreg;                
  SEI();
}


/******************************************************************** 
*  函数说明:SJA1000接受中断服务函数,                              * 
*  输入:无                                                         * 
*  输出:正确读取返回TURE否则返回FALSE 。                           * 
*  影响变量:接受缓冲在正确读取时被刷新                             *
********************************************************************/
void sja_rx_service(void)
{
    unsigned char number,i,ptr;
    ptr=RXEFF;           
            if((sja_read_data(RXEFF)&0x40)==0x40)  //如果RTR=1,为远程帧
    		{
                sja_write_data(CMR,0x04);          //则释放接收缓冲
    		}
            else                    		         //为0,则是数据帧
    		{
                number=(sja_read_data(RXEFF)&0x0f);//取第一个字节的低四位,即数据长度	
				if (number>0x08)
				number=0x08;			
                if ((sja_read_data(RXEFF))&0x80)         //判断是标准帧还是扩展帧
				{
                number=number+5;              //扩展帧,则帧的总长度加5(13字节)
				}
        		else
				{
                number=number+3;              //标准帧,则帧的总长度加3(11字节)
				}
                for(i=0;i<number;i++)   	  //读取数据
        		{
                    RxBuffer[i]=sja_read_data(RXEFF+i);
                	ptr++;
        		}
                sja_write_data(CMR,0x04);          //最后释放FXFIFO
    		}
}

/******************************************************************** 
*  函数说明:SJA1000查询方式接收函数,                              * 
*  输入:无                                                         * 
*  输出:无                                                         * 
********************************************************************/
void Search(void)                
{
   unsigned char SearchStatus;
   SearchStatus=sja_read_data(SR); //读取状态寄存器
#ifdef DEBUG
    rprintfStr("SR:   ");
	rprintfu08(SearchStatus);
	rprintfCRLF();
#endif   
//   if((SearchStatus & 0x83))       //是否存在总线关闭、错误状态、数据溢出、有数据位等状态
//   { 
      if(SearchStatus&(1<<7))//如果总线关闭
         {
#ifdef DEBUG
    rprintfStr("****bus shut off****");
	rprintfCRLF();
#endif
         sja_read_data(IR);              //读取中断寄存器,清除中断位
         sja_write_data(MODE,0x08); 
         }
      if(SearchStatus&0x02)//如果有数据溢出
		 {
#ifdef DEBUG
    rprintfStr("****data overflow****");
	rprintfCRLF();
#endif
         sja_write_data(CMR,0x0c);          //在命令寄存器中清除数据溢出和释放接收缓冲区
		 }
       if(sja_read_data(IR) & 0x01)//IR.0=1,接收缓冲区有数据
         {
                led_on;
#ifdef DEBUG
    rprintfStr("****receive buffer have data****");
	rprintfCRLF();
#endif
         }
//   }
}

//=============================================================================
//显示缓冲区内容
void play_buffer(unsigned char *ptr)
{
 unsigned char i;
 for (i=0;i<13;i++)
  {
    rprintfu08(*ptr);
//	rprintfStr("--");
	ptr++;
  }
   rprintfCRLF();
}

//=============================================================================
//初始化换冲区,在此监控卡上只有模拟管理系统降低充电电压的情况
void buffer_init(void)
{
    TransmitMessage[0]=0x88;		   //扩展贞,8个数据字节
	
    TransmitMessage[1]=192;	       //管理系统优先级7:    ID.28--ID.21=111-00-111
    TransmitMessage[2]=168;	       //PF=255- 235         ID.20--ID.13=01011-000 
    TransmitMessage[3]=0x00;	       //PS=252- 22          ID.12--ID.5 =10110-000    
    TransmitMessage[4]=0x08;	       //As=0x11             ID.4--ID.0  =10001-000
	
    TransmitMessage[5]=0xCC;	      //桢编号
	
    TransmitMessage[6]=0x00;	
    TransmitMessage[7]=0x01;	
    TransmitMessage[8]=0xa1;	
    TransmitMessage[9]=0xa2;	
    TransmitMessage[10]=0xa3;	
    TransmitMessage[11]=0xa4;	
    TransmitMessage[12]=0xff; 
}

void test_can(void)
{
      rprintfCRLF(); 
	  rprintfStr("***CAN BUS DEBUG:***"); 
	  rprintfCRLF(); 
	  
	  rprintfStr("content of transmit buffer ");
	  rprintfCRLF();
	  play_buffer(TransmitMessage);
	  
	  CLI();
      sja_tx(TransmitMessage);
	  SEI();
	  rprintfCRLF();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -