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

📄 main._c

📁 本软件实现了232到CAN的具体转换的代码,对232和CAN都进行了很好的说明,编程环境是IAR
💻 _C
字号:
/*##############################################################################
功能:CAN与232相互转换
作者:LHF
时间:2007-01
版本:V1.0
################################################################################
资源分配:	PORTC.2~5:JTAG
##############################################################################*/
//##############################################################################
#include <iom16v.h>	         //寄存器定义;
#include <macros.h>	         //宏定义;
#include "MCP2515.h"  			 //2515寄存器定义
#define uchar unsigned char  //数据类型定义
#define uint unsigned int    //数据类型定义

#pragma interrupt_handler INT1_17:3 //定义INT1的中断服务程序
#pragma interrupt_handler Timer0:10 //定义定时计数器0的中断服务程序
#pragma interrupt_handler Usart_receive:12 //定义接收中断服务程序
#define fosc 7372800 //晶振7.3728MHZ
uchar can_boud=0x07;//MCP2515在16M晶振情况,can_boud=0x00总线波特率为1M,0x01=500K,0x03=250K,0x07=125K;公式:16M/(16*(1+X))
uint bps=38400;//定义串口波特率

uchar eflag=0;//是不是扩展帧,为1则表示接收到的是扩展帧,0表示标准帧
uchar Tdate[10]={0};//存放要发送标准帧的数据,最大10位,前2位是ID号,后8位是数据位
uchar TID[2]={0,0};//存放要发送标准帧的ID号

uchar Rdate[8]={0};//存放接收到的数据
uchar RESID[4];//存放接收到的数据帧的ID号,标准帧只用到RESID[0],RESID[1],扩展帧全部用到

uchar bytetime;//232与CAN透明转换时,根据不同的波特率确定所要延时的时间,
uint usart_number=0;//计数当前所接收的串行数据的那一组数据流的数据个数,串口传来的数据存放在Tdate中等待用CAN标准帧发送

uchar state;//2515状态(包括发送接收中断标志位和各请求发送位),具体见数据手册
uchar DLC=8;//接收到数据的长度

//****************************************************************************//
//********************************延时程序************************************//
void delay(uchar k)//
{uint i=0;
 while(k--){for(i=0;i<8000;i++);}
 }
//##############################################################################
void Set_CS(uchar level)          //
{if(level)    PORTB|=0x10;        //
 else         PORTB&=0xef;        //
}
//##############################################################################
//********************************SPI对2515访问*******************************//
//****************WriteSPI()*******************//
void WriteSPI(uchar order)
{	uchar clear;
	Set_CS(0);  //
	SPDR=order;			 //2515读指令为0x03
    while(!(SPSR&0x80)); //等待SPIF置位,等数据发送完毕
    clear=SPSR;
    state=SPDR;//
    Set_CS(1);  //
}

//****************Read_state()*******************//
uchar Read_state(uchar order)//读状态命令,order=0xa0,0xa1,
{	uchar clear;
	Set_CS(0);  //
	SPDR=order;			 //
    while(!(SPSR&0x80)); //等待SPIF置位,等数据发送完毕
    clear=SPSR;
    clear=SPDR;//
    
	SPDR=0;		        //空数据
    while(!(SPSR&0x80));//等待SPIF置位,等数据发送完毕
    clear=SPSR;
    clear=SPDR;		 //通过先读SPSR,紧接着访问SPDR来对SPIF清零
	
	Set_CS(1);  //
	return clear;
}
//**从2515指定地址Address读取一个字节数据Data**//
uchar Read_Byte(uchar Address)
{uchar clear;
 uchar date;
 Set_CS(0);            //使能SPI器件
 
 SPDR=0x03;			 //送2515读指令为0x03
 while(!(SPSR&0x80));	 //等待SPIF置位,等数据发送完毕
 clear=SPSR;
 clear=SPDR;             //通过先读SPSR,紧接着访问SPDR来对SPIF清零
 
 SPDR=Address;				//送地址
 while(!(SPSR&0x80));
 clear=SPSR;
 clear=SPDR;
 
 SPDR=0x00;	             //发空数据,启动数据发送以接收数据
 while(!(SPSR&0x80));
 clear=SPSR;
 clear=SPDR;
 
 date=SPDR;              //接收数据
 Set_CS(1);              //关SPI器件DS1722
 return date;
}
//**向2515指定地址Address写一个字节数据Data**//
void Write_Byte(uchar Address,uchar Data)
{uchar clear;
 Set_CS(0);          //使能SPI器件2515
 
 SPDR=0x02;		     //送2515写命令为0x02
 while(!(SPSR&0x80));//等待SPIF置位,等数据发送完毕
 clear=SPSR;
 clear=SPDR;	
 
 SPDR=Address;		 //送地址,启动SPI时钟
 while(!(SPSR&0x80));//等待SPIF置位,等数据发送完毕
 clear=SPSR;
 clear=SPDR;		 //通过先读SPSR,紧接着访问SPDR来对SPIF清零
 
 SPDR=Data;
 while(!(SPSR&0x80));
 clear=SPSR;
 clear=SPDR;
 Set_CS(1);         //关SPI器件
}
//****************************************************************************//
//###########################对CAN的一些操作####################################
//***************************要发送的数据包***********************************//
void load_Standard_ID_dates(uchar num)//给标准帧装载ID和数据
//选用发送缓冲器0,num:要发送的个数(最大8个)
{
 uchar i,j,T0=0x36;
 uchar TIDH,TIDL;
 i=TID[1]>>3;j=TID[0]<<5;j=j+i;i=TID[1]<<5;
 TIDL=i;TIDH=j;//将数组TID中的值转化为TIDH,TIDL以便给TXB0SIDH,TXB0SIDL附值
 Write_Byte(CANCTRL,0x80);//CAN工作在配置模式
 Write_Byte(CNF1,can_boud);
 Write_Byte(TXB0SIDH,TIDH);
 Write_Byte(TXB0SIDL,TIDL);
 Write_Byte(TXB0DLC,num);// 
 for(i=2;i<num+2;i++,T0++)Write_Byte(T0,Tdate[i]);
 }
//##############################################################################
void Receive_all_ID_process(void)//结合MCP2515数据手册来看
{uchar k;
 k=RESID[1];//先判断接收到的是不是标准帧,因为标准帧和扩展帧的ID处理不一样
 if((k&0x08)==0)
   {//如果是标准处理方法
    RESID[1]=RESID[1]>>5;
    k=RESID[0]&0x1f;//借用k
	k=k<<3;
	RESID[1]=RESID[1]+k;
	RESID[0]=RESID[0]>>5;
	}
 else
    {//扩展帧处理方法,RESID[3]、RESID[4]不变
	 k=k>>5;
	 k=k<<2;
	 RESID[1]=RESID[1]&0x03;
	 RESID[1]=RESID[1]+k;
	 k=RESID[0];
	 k=k<<5;
	 RESID[1]=RESID[1]+k;
	 RESID[0]=RESID[0]>>3;//将RXB0SIDH,RXB0SIDL转化
	}		 
}
//##############################################################################
//##############################USART初始化程序###########################//
void usart_init(void)
{
 UCSRB=(1<<RXEN)|(1<<TXEN);//允许发送和接收
 UBRRL=(fosc/16/(bps+1))%256;
 UBRRH=(fosc/16/(bps+1))/256;
 UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位数据+1位STOP位
 bytetime=215983/bps;//215983=1000000*20/92.6,92.6=1024/11.0592,定时器分频为1024
 bytetime=255-bytetime;//计算不同的波特率所要延时的初值,要附值给TCNT0,实现透明转换中用到
} 

//##########################串行通信##########################//
void putchar(uchar c)
{while(!(UCSRA&(1<<UDRE)));//判断上次发送有没有完成
 UDR=c;}
//##############################中断服务程序##################################//
void INT1_17(void)
{
uchar i,j,k,R0=0x66;
GICR &=0x7f;
WriteSPI(0xa0);//读取2515状态指令,状态值附值给state
if((state&0x01)!=0)
   {//判断是不是接收缓冲器0满产生的中断
    k=Read_Byte(RXB0SIDL);//为了判断是标准帧还是扩展帧
	if((k&0x08)==0)eflag=0;//置标准帧标志
   	 else eflag=1;//置扩展帧标志
	DLC=Read_Byte(RXB0DLC);
	DLC &=0x0f;
	RESID[0]=Read_Byte(RXB0SIDH);
	RESID[1]=Read_Byte(RXB0SIDL);
	RESID[2]=Read_Byte(RXB0EID8);
	RESID[3]=Read_Byte(RXB0EID0);//先读取所有ID
	Receive_all_ID_process();//处理RESID
	for(i=0;i<DLC;i++,R0++)Rdate[i]=Read_Byte(R0);//从2515缓冲区内读取收到的数据部分
	if(eflag==0)
	  {//如果是标准帧
	   putchar(RESID[0]);
	   putchar(RESID[1]);//先送标准帧ID号
	   }
	else 
	  {//如果是扩展帧
	   putchar(RESID[0]);
	   putchar(RESID[1]);
	   putchar(RESID[2]);
	   putchar(RESID[3]);//先送扩展帧ID号    
	  }
	putchar(DLC);
	for(i=0;i<DLC;i++)putchar(Rdate[i]);//再送接收到的DLC位数
	}
Write_Byte(CANINTF,0x00);//接收完一次必须对中断标志位清0
GICR |=0x80;
}
//####################################
void Usart_receive(void)//定义接收中断服务程序
{Tdate[usart_number]=UDR;
 usart_number++;
 TIMSK=0x05;//打开T1,T0中断屏蔽
 TCCR0=0x05;//设T0分频数为1024
 TCNT0=bytetime;//设T0时间常数,从此值开始计数
 }
//##############定时器中断0,串行数据流控制
void Timer0(void)
{TIMSK=0x00;//关T0中断屏蔽
 TCNT0=0x00;//
 TCCR0=0x00;//T0停止计数
 if((usart_number>2)&&(usart_number<11))
   { 
    TID[0]=Tdate[0];TID[1]=Tdate[1];
 	load_Standard_ID_dates(usart_number-2);//对2515发送缓冲器0和ID寄存器进行数据装载
    usart_number=0;
 	Write_Byte(CANCTRL,0x00);//选定工作模式
 	WriteSPI(CAN_RTS_TXB0);//发送缓冲器0请求发送
   }
   else  usart_number=0;
 }
//##############################CAN(2515)初始化程序###########################//
void CAN_Initialize(void)
{
  WriteSPI(CAN_RESET);
  delay(20);
  Write_Byte(CANCTRL,0x80);//CAN工作在配置模式
  Write_Byte(CNF1,can_boud);
  Write_Byte(CNF2,0x80 | PHSEG1_3TQ | PRSEG_1TQ);//Set CNF2
  Write_Byte(CNF3,PHSEG2_3TQ);
  //0x80+0x10+0x00,相位缓冲段2由CNF3确定,相位缓冲段1为3TQ,传播段为1TQ
  Write_Byte(RXB0CTRL,0xf0);//接收类型选择,接收所有报文
  Write_Byte(CANINTF,0x00);//接收完一次必须对中断标志位清0
  Write_Byte(CANINTE,0x01);//接收缓冲器0满中断使能
  Write_Byte(CANCTRL,0x00);//选定正常工作模式
}
//##############################系统初始化程序################################//
void AVR_Initialize(void)         //初始化
{
 DDRB=0xff;	 //SPI口
 PORTB=0xff;
 DDRD=0xf0;//将外部中断引脚设定为输入
 PORTD=0x7f;
 SPCR=0b01011100;//关中断(SPIE=0),使能SPI(SPE=1),MSB首先发送(DORD=0)
 				 //选择微机为主机模式(MSTR=1)
                 //空闲时SCK 为高电平(CPOL=1)
				 //在SCK 的结束沿采样(CPHA=1)以保证数据稳定
 				 //SPR1=0和SPR0=0,SCK=fosc/4
 SPSR |=0x01;//SPI的速度加倍
 MCUCR=0x0a;//设置外部中断的中断触发方式为下降沿触发
 GICR=0xc0;//通用中断控制寄存器设置,打开中断INT0和INT1
 SREG=0x80;//开全局中断
}
//##################################主程序####################################//
void main()
{
 AVR_Initialize();               //I/O口及中断初始化
 CAN_Initialize();
 usart_init();
 UCSRB |=0x80;//接收中断使能
}

⌨️ 快捷键说明

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