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

📄 can.c

📁 单片机数据通讯典型应用(光盘内容)
💻 C
字号:
//**********************预定义及数组声明**************************
#define Tx_DLC 8							//发送字节长度
#define Rx_DLC 8							//接收字节长度
unsigned char Tx_DATA[8]={0};				//存储待发送数据
unsigned char Rx_DATA[8]={0};				//存储接收到的数据
//CAN 寄存器定义
#define CANSTAT            0x01                 //状态寄存器
#define BITREG             0x03                 //位定时寄存器
//CAN IF1 接口寄存器定义
#define IF1CMDRQST         0x08                 //IF1命令请求寄存器
#define IF1CMDMSK          0x09                 //IF1命令掩码寄存器
#define IF1ARB1            0x0C                 //IF1 仲裁1寄存器
#define IF1MSGC            0x0E                 //IF1消息控制寄存器
#define IF1DATA1           0x0F                 //IF1 数据A1寄存器
//CAN IF2 接口寄存器定义
#define IF2CMDRQST         0x20                 //IF2命令请求寄存器
#define IF2CMDMSK          0x21                 //IF2命令掩码寄存器
#define IF2ARB1            0x24                 //IF2仲裁1寄存器
#define IF2MSGC            0x26                 //IF2消息控制寄存器
#define IF2DATA1           0x27                 //IF2数据A1寄存器

//系统初始化
void sys_init(void)
{
	 uchar i=0;
	//看门狗禁止
	EA=0;		  				//禁止所有中断
	WDTCN = 0x07;	 			//禁止看门狗定时器	
    WDTCN = 0xDE;   
   	WDTCN = 0xAD;
	EA=1;	 				 	//打开总中断
	//端口引脚配置
	SFRPAGE=0x0F;
	XBR2=0x40;					//交叉开关使能
	XBR3=0x80;					//CAN TX引脚为推挽输出
	P7MDOUT=0x03;			    //P7.0和P7.1推挽方式输出
	P3MDIN=0xFF;				//P3引脚配置为数字量输入
	//系统时钟初始化
	SFRPAGE=0x0F;
	CLKSEL=0x01;		//外部振荡器
	OSCXCN=0x67;		//外部晶振16MHz,
	for(;i<255;i++);	//等待至少1ms
	while(!(OSCXCN&0x80));//查询XTLVLD是否为1,等待外部晶振稳定振荡
}

//**********************CAN控制器初始化程序**************************
void can_init(void)
{	
	unsigned char i;
	//将所有消息清零
	EA=0;                           //关闭总中断
EIE2&= ~0x20; 				//CAN中断关闭
	SFRPAGE = CAN0_PAGE;
	
	XBR3|= 0x80;  				//CAN TX引脚设置成推挽输出
	CAN0ADR = IF1ARB1;
	CAN0DAT = 0x0000; 			//设定消息对象MsgVal=0,表示该消息对象无效
   	SFRPAGE = CAN0_PAGE;
	CAN0ADR = IF1CMDMSK; 
	CAN0DATL = 0xFF;            
	for (i=1;i<33;i++)
     {
		CAN0ADR = IF1CMDRQST;     
		CAN0DATL = i;
     } 
	//初始化发送
  	SFRPAGE = CAN0_PAGE;
	CAN0ADR = IF1CMDMSK; 	//指向IF1命令掩码寄存器
	CAN0DAT = 0x00b3; 		//WR/RD=1,Mask=0,Arb=1,Control=1,ClrIntPnd=0,
	                            //TxRqst=0,DataA=1,DataB=1,一次发送8字节数据

	CAN0ADR = IF1ARB1;            
	CAN0DAT = 0x0000;  
	CAN0DAT = 0xa004;       //MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=1,为		                                //发送,发送报文识别符ID=1
	CAN0ADR = IF1MSGC;
	CAN0DAT = 0x0080;       //NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,
		                       //RxIE=0,RmtEn=0,TxRqst=0,EoB=1,DLC3-0=1000,
//即数据长度为0,实际发送时重写
	CAN0ADR = IF1CMDRQST;          
	CAN0DAT = 0x02;   	    //将以上配置写入0x02号消息 
	//初始化接收
	SFRPAGE = CAN0_PAGE;
	CAN0ADR = IF2CMDMSK; 
	CAN0DAT = 0x00bb;       //WR/RD=1,Mask=0,Arb=1,Control=1,ClrIntPnd=1,        
	                           //TxRqst=0,DataA=1,DataB=1,一次发送8字节数据
	CAN0ADR = IF2ARB1;           
	CAN0DAT = 0x0000;            
	CAN0DAT = 0x8010;	   //MsgVal=1,Xtd=0,为标准模式,扩展ID无效,Dir=0,
//为接收, 接收报文识别符ID=2
     CAN0ADR = IF2MSGC;
	CAN0DAT = 0x0480;      //NewDat=0,MsgLst=0,IntPnd=0,UMask=0,TxIE=0,
		                      //RxIE=1,接收中断使能;RmtEn=0,TxRqst=0,EoB=1,
//DLC3-0=0000,即数据长度为0 ,接收时重写
	CAN0ADR = IF2CMDRQST;        
	CAN0DATL = 0x04; 	   //将以上配置写入0x04号消息          
	//设置传输速率
	EIE2|=0x20;				//开CAN中断
	EA=1;
	SFRPAGE=CAN0_PAGE;
	CAN0CN|=0x41;	 	    //CCE=1,INIT=1 进入CAN初始化
	CAN0ADR=BITREG;
	CAN0DAT=0x2301;		    //调波特率 500kbps
	SFRPAGE=CAN0_PAGE;
	CAN0CN|=0x22; 		    //开放自动重发,收发中断
	CAN0CN&=~0x41 ;		    //退出初始化
}   

//**********************CAN数据发送子程序**************************
void transmit_data(void) 
{
	unsigned int data Val ;
	unsigned char data i ;
	SFRPAGE=CAN0_PAGE;				//选定页地址
	CAN0ADR=IF1CMDRQST;
	Val=CAN0DAT;
	if(val&0x8000) 					//IF1 是否正在忙着写其他,是则等待
	{ 
		CAN0ADR=IF1CMDRQST;
		Val=CAN0DAT;
	}
	CAN0ADR=IF1CMDMSK; 				//设定为向消息存取器写内容,
									//CAN0ADR 会自动加“1”
	CAN0DAT=0x0087;					//仲裁及控制已经初始化过,请求发送
	
	CAN0ADR=IF1MSGC;
	if(CAN_FLAG&0x01) 				//是否是远程帧?
	{ 
		CAN0DATH=0x23; 				//设置为远程帧,关发送中断使能
		CAN0DATL=0x80;
	}
	else 
	{
		CAN0DATH=0x23 ; 			//关发送中断使能
		CAN0DATL=Tx_DLC; 			//TX_DLC 被定义为预发送数据长度
		
	}
	CAN0ADR=IF1DATA1;				//IF1消息数据起始寄存器,
//根据发送字节多少,地址自动加1
	for (i=0;i<Tx_DLC;i++) 			//把数据写入消息存取器
	{ 
		if ((i+1)<Tx_DLC)  			//至少一个字的数据
		{
			CAN0DATH=Tx_DATA[i+1];
			CAN0DATL= Tx_DATA[i];
			i++;
		}
		else
			CAN0DATL= Tx_DATA[i];	//只有一个字节的数据
	}
	CAN0ADR=IF1CMDRQST;				//IF1命令请求
	CAN0DATH=0x80 ; 				//设定IF1正在忙于传送数据
	CAN0DATL=0x02; 					//发送数据准备完成,等待中断发生
}

//**********************CAN数据接收子程序**************************
void receive_data(void)
{
	unsigned int data Val ;
	SFRPAGE=CAN0_PAGE;				//选定页地址
	CAN0ADR=IF2CMDMSK;  			//IF2 指向消息对象
	Val=CAN0DAT ;
	if (Val&0x8000) 				//IF2是否正在忙着写其他,是则等待
	{ 
		CAN0ADR=IF2CMDRQST;
		Val=CAN0DAT;
	}
	CAN0ADR=IF2CMDMSK; 				// 设定为向消息存取器写内容,
//CAN0ADR 会自动加“1”
	CAN0DAT=0x000F;
	CAN0ADR=IF2MSGC;  
	CAN0ADRL=Rx_DLC;  				//设定接收数据长度

	CAN0ADR=IF2CMDRQST;
	CAN0DATH=0x80; 					//设定IF2正忙      	
	CAN0DATL=0x04; 					//指向0x04号消息      	   
	CAN0ADR=IF2DATA1;     	 
	for(i=0;i<Rx_DLC;i++)			//接收数据
		Rx_DATA[i] =CAN0DAT;			
}
//**********************CAN数据接收中断子程序**************************
void can_interrupt(void) interrupt 19
{	
unsigned char temppage;
temppage=SFRPAGE;				//保存页地址
    SFRPAGE=CAN0_PAGE;
    status=CAN0STA;					//读取CAN状态
    if(status&0x10)
	{
	   CAN0STA&=0xef;
	   receive_data();				//读取数据
     } 
    SFRPAGE=temppage;				//恢复消息初始状态
}

⌨️ 快捷键说明

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