原创 贴一个本人原创的CAN总线通信程序

2007-11-8 08:14 7494 7 8 分类: MCU/ 嵌入式

//------------------------------------------------------
//  CAN <==> UART的协议转换器
//
//  程序名称:CAN <---> UART协议转换程序<透明方式>
//
//  作者: 王猛
//  创建: 2007-10-09
//
//  说明:
//  1,单片机使用P89C61X2BA 
//   --晶振11.0592MHZ                                                                                 
//   --CAN总线中断使用单片机的中断0,外部有上拉电阻,波特率可以设定
//  2,CAN总线发送采用查询方式,接收采用中断方式
//  3,看门狗复位时间1.2S
//  4,SJA1000晶振8MHZ,Peil模式
//  5,串口中断接收,查询发送,波特率可设置
//  6,×××当串口收到数据后,每8个数一组打包,通过CAN总线发送出去
//
//   -----10.16日,重新修改程序完成以下功能-----   
//    ----此功能已经改为,每收到一帧数据,启动一次CAN传输,传输字节数等于串口收到的数据
//    ----串行帧的帧间界定通过当前波特率下传输5个字节为时间间隔,具体为当顺序接收到的任
//     意两个数据,它们之间的时间间隔大于5个字节传送时间,认为这两个数据分属于两个不
//     同的帧
//
//  7,当CAN总线每接收一帧信息后,通过串口发送出去
//   -----10.15日,改为可以识别CAN的报文字节长度,即串口只发送CAN报文长度个字节
//  8,看门狗芯片MAX1232CPA,硬件溢出时间1.2S
//  
//-------------------------------------------------------


#include
#include
#include
#include "CANCOM.h"


//unsigned char UART_TX_Data[8] = {0,1,2,3,4,5,6,7};
//unsigned char CAN_TX_Data[8] = {0,1,2,3,4,5,6,7};     
unsigned char xdata UART_RX_Data[255];        //串口接收到的串行帧
unsigned char xdata CAN_TX_Data[255];        //待发送的数据缓冲区
unsigned char code ACR_ID[4] = {0,0,0,0};       //CAN初始设置验收滤波值
unsigned char code AMR_ID[4] = {0xff,0xff,0xff,0xff};
unsigned char CAN_TX_ID[4] = {0,0,0,0};        //待发送的目标的ID
unsigned char CAN_RX_ID[4] = {0,0,0,0};        //接收到的信息来自何ID
unsigned char CAN_RX_Data[8] = {7,6,5,4,3,2,1,0};     //接受到的数据缓冲
unsigned char code CAN_BTR0[10] = {0xdf,0xcf,0xc7,0xc3,0x43,0xc1,0xc1,0xc0,0xc0,0x80};                                                                                                                                                                                                                                                                                                                                                        
unsigned char code CAN_BTR1[10] = {0x7f,0x7f,0x7f,0x7f,0x2f,0x7f,0x4d,0x3e,0x3a,0x23};
//         5K  10K  20K  40K  50K  80K  100K 200K 250K 500K
unsigned char code UART_BTR[4] = {0xe8,0xf4,0xfa};  
//          1.2K,2.4K,4.8K


unsigned char CAN_flag;      //CAN发送标志位
unsigned char UART_flag;     //
unsigned char CAN_ERROR_flag = NOT;   //
unsigned char CAN_DataLength = 8;    //CAN信息的报文长度
unsigned char UART_DataLength = 0;   //串口接收时的当前指示 
unsigned char UART_Length = 0;    //串口接收区的长度指示
//sbit AAA = P1^4;


void main(void)
{
 EA = 0;     
 System_init();   //系统初始化
 Timer_init();   //定时器初始化
 Interrupt_init();  //中断
 UART_ini();
 CAN_init();
 Delay(1);
 W_WDT();
 EA = 1;


 //Delay(1);
 //UART_Length = 8;
 //CAN_Transmit(0);
 //UART_Transmit();


 while (1)
 {
  W_WDT();


  if (CAN_flag == YES)
  {
   CAN_flag = NOT;
   CAN_Transmit(0);
   LED1 = !LED1;
  }
  else
  {
   CAN_flag = NOT;
  }
/*
  if (UART_flag == YES)
  {
   UART_flag = NOT;
   //Delay(50);
   UART_Transmit();
   //Clear_Buffer(CAN_RX_Data,8);
   //LED3 = !LED3;
  }
  else
  {
   UART_flag = NOT;
  } 


*/
  if ((CAN_ERROR_flag == YES))
  {
   CAN_ERROR_flag = NOT;
   CAN_init();
  }
  else
  {
   CAN_ERROR_flag = NOT;
  }
 }
}
//---------------------------
// 功能:系统设置
//   --外部数据存储区访问使能
//   --LED指示灯关(1=on,0=off)
//   --流程控制标志置为无效NOT
//   --清空串口,CAN的相关数据缓冲区
//---------------------------
void System_init(void)
{
 CKCON = 0x00;   //Fosc devide 12
 AUXR  = 0x00;//0x02;   //EXM enable
 LED1 = 0;    //LED0-3 off  指示灯,共阴接法,1时亮
 LED2 = 0;
 LED3 = 0;
 LED4 = 0;
 WDT = 1;    //WDT ini
 
 CAN_DataLength = 8; 
 UART_DataLength = 0; 
 UART_Length = 0;  
 
 CAN_flag = NOT;
 CAN_ERROR_flag = NOT; 
 //UART_flag = NOT;


 Clear_Buffer(UART_RX_Data,255);
 Clear_Buffer(CAN_TX_Data,255);
 Clear_Buffer(CAN_TX_ID,4);
 Clear_Buffer(CAN_RX_ID,4);
 Clear_Buffer(CAN_RX_Data,8);
 
 /*
 CAN_flag = YES;
 UART_flag = YES;
 */
}
//-----------------------------
//
//  软件延时(非精确)
//   ----内置清看门狗定时器子函数
//    防止多次调用延时过长导致
//    看门狗复位
//
//-----------------------------
void Delay(unsigned char time)
{
 unsigned char i;
 unsigned int j;
 
 for (i = 0;i < time;i++)
 {
  W_WDT();
  for (j=0;j<30000;j++)
  {
  }
 }
}


//---------------------------------
// 串行口初始化设置
// 方式1,8数据位,一个停止位,无奇偶校验
// 串口中断允许
//------------------------------------
void UART_ini(void)
{
 SCON = 0x50;  //方式1,波特率可变,8bits,接受允许
 PCON&= 0x7F;  //SMOD = 0                          
 TMOD |= 0x20;  //timer1 mode 2                     
 
 TL1 = UART_BTR[2]; //|     f              
      //| 波特率=----------------------   
 TH1 = UART_BTR[2]; //|   32*2^smod*12*(256-TL1)  
 TCON |= 0x40;  //start                             
                                                                                                                
 TI = 0;                                             
}


//-----------------------------------------------
//
// 看门狗“喂狗”程序,WDT的一个下降沿触发一次
//
//-----------------------------------------------
void W_WDT(void)   //triggle WDT
{
 unsigned char i;
 WDT = 1;
 for (i=0;i<10;i++)
 {
 }
 WDT = 0;
}


//---------------------------------------------------
//
// 中断初始化
//  
//  ----外部中断0有效,下降沿触发,用于SJA1000产生CAN事件中断
//  ----定时器中断,用于判定串口接收的顺序两个字节是否分属两帧
//  ----串口中断,RX使用中断,TX未使用
//  ----中断优先级暂时未设定
//
//---------------------------------------------------
void Interrupt_init(void)
{
 //IP = 0x00;     
 IT0 = 0x01;      //外部0中断沿触发
 
 ET0 = 1;      //定时器0中断使能
 EX0 = 1;      //外部中断使能
 ES = 1;                //串行中断使能
}


//---------------------------------------------------
//
// 定时中断程序
//  
//  一旦中断,说明一帧的接收已经结束,开始启动CAN发送程序
//  把串口接收到的数据准备好给CAN总线发送
//  RX_buffer ===> CAN_TX_buffer
//
//---------------------------------------------------
void Timer0_ISR(void) interrupt 1 using 2
{
 static unsigned char i;
 //unsigned char counter;


 //TH0 = temp_TH0;
 //TL0 = temp_TL0;


 /*counter += 1;
 if (counter == 20)    //到1S了么?
 {
  //UART_flag = YES;
 }
 if (counter == 40)    //到2S了么?
 {
  //CAN_flag = YES;
  counter = 0;
 }*/
 //AAA = !AAA;
 TR0  = 0;      //定时器关,开始次CAN信息传送


 for (i=0;i {
  CAN_TX_Data = UART_RX_Data;
 }
 UART_Length = UART_DataLength;
 UART_DataLength = 0;
 CAN_flag = YES;
}
//---------------------------------------------------------------
//
//  串口中断服务程序
//
//  ----只有接收使用   
//  ----每收一个数重新初始化定时器
//
//----------------------------------------------------------------
void RX_INT(void) interrupt 4 using 3
{
 static unsigned char  n;
 
 if (RI==1)
 {
  do
  {
   RI = 0;
  }
  while (RI != 0);


  //UART_RX_Data[UART_DataLength++] = SBUF;
  n = SBUF;
  UART_Send_Byte(n);
  
  TH0 = temp_TH0;  
  TL0 = temp_TL0;
  TR0  = 1;       //启动数据间隔定时,判断是否分属两帧
 }
 else
 {
  //TX
 }
}
//---------------------------------------------------------------
//
//  串口发送单字节程序
//
//----------------------------------------------------------------
void UART_Send_Byte(unsigned char Data)
{    
 SBUF = Data; 
 while (TI == 0)     //等待发送完毕
 {
 }
 TI = 0; 
}


//---------------------------------------------------------------
//
//  初始化定时器程序
//
//  ----定时器0方式1,定时器1方式2留给串口
//
//----------------------------------------------------------------
void Timer_init(void)
{
 TMOD |= 0x01;     //使用定时器0-方式1
 
 TH0 = temp_TH0;
 TL0 = temp_TL0;
 //TR0  = 1;      //这里不打开定时器
}


void CAN_init(void)
{
 
 EA = 0;
 MOD_CAN1 |= 0x08;     //单滤波方式
 do
 {
  MOD_CAN1 |= 0x01;               //request to reset mode
 }
 while ((MOD_CAN1&0x01) != 0x01);
 
 CDR_CAN1 = 0xc8;     //选择PeliCAN模式,使用输入比较器,clk_out关闭
 IER_CAN1 = 0x01;     //允许发送中断,其他中断禁能


 ACR0_CAN1 = ACR_ID[0];
 ACR1_CAN1 = ACR_ID[1];
 ACR2_CAN1 = ACR_ID[2];
 ACR3_CAN1 = ACR_ID[3];
 AMR0_CAN1 = AMR_ID[0];
 AMR1_CAN1 = AMR_ID[1];
 AMR2_CAN1 = AMR_ID[2];
 AMR3_CAN1 = AMR_ID[3];


 //ECC_CAN1 = 0;
 //TXERR_CAN1 = 0;
 //RBSA_CAN1 = 0;


 BTR0_CAN1 = CAN_BTR0[0];   
 BTR1_CAN1 = CAN_BTR1[0];
 OCR_CAN1 = 0xaa;     //normal output


 W_WDT();
 do
 {
  MOD_CAN1 &= 0xfe;
 }
 while ((MOD_CAN1&0x01) != 0x00);
 EA = 1;
}


//-----------------------------------
//
//  串口发送一帧接受到的CAN数据
//   
//   ----长度1-8,根据接收到的CAN信息来确定
//
//-----------------------------------
void UART_Transmit(void) //using 0
{
 unsigned char i;
 
 LED3 = !LED3;
 for (i=0;i {
  UART_Send_Byte(CAN_RX_Data);
 }
}
//-----------------------------------
//
//  CAN发送接受到的一帧串口数据
//   
//   ----最大长度255,根据接收到的串口信息的
//    个数来确定
//   ----按每依次8个数据作为一个CAN帧的报文部分
//    不足8个或超过8的倍数的部分按实际个数作
//    为CAN报文
//   ----FarmeType = 1为扩展帧,FarmeType = 0为
//    标准帧
//-----------------------------------
void CAN_Transmit(bit FarmeType)
{


 unsigned char i;
 unsigned char m;
 unsigned char can_status;
 unsigned char xdata *pointer;
 
    
 if (FarmeType == 0)   //标准帧
 {
  for (m=0;m<(UART_Length/8);m++)
  {
   W_WDT();
   do         //发送缓冲区空么?
   {
    can_status = SR_CAN1;
   }
   while ((can_status&0x04) != 0x04);
   
   TXFrameInfo1 = 0x00 + 0x08;
   pointer = &TXID1;
   for (i=0;i<2;i++)
   {
    *(pointer++) = CAN_TX_ID;
   }


   pointer = &TXID3; 
   for (i=0;i<8;i++)
   {
    *(pointer++) = CAN_TX_Data[i+8*m];
   }
   CMR_CAN1 = Request_TX;
   W_WDT();
  }
  
  if ((UART_Length%8) != 0)
  {
   W_WDT();
   do          //发送缓冲区空么?
   {
    can_status = SR_CAN1;
   }
   while ((can_status&0x04) != 0x04);
   TXFrameInfo1 = 0x00 + UART_Length%8;
   pointer = &TXID1;
   for (i=0;i<2;i++)
   {
    *(pointer++) = CAN_TX_ID;
   }


   pointer = &TXID3; 
   for (i=0;i<(UART_Length%8);i++)
   {
    *(pointer++) = CAN_TX_Data[i+8*(UART_Length/8)];
   }
   CMR_CAN1 = Request_TX;
   W_WDT();
  }
  else
  {
  }
 }
 else        //扩展帧
 {
  for (m=0;m<(UART_Length/8);m++)
  {
   W_WDT();                                                 
   do         //发送缓冲区空么?   
   {                                                        
    can_status = SR_CAN1;                                
   }                                                        
   while ((can_status&0x04) != 0x04);                       


   TXFrameInfo1 = 0x80 + 0x08;
   pointer = &TXID1;
   for (i=0;i<4;i++)
   {
    *(pointer++) = CAN_TX_ID;
   }


   pointer = &TXDATA1;  
   for (i=0;i<8;i++)
   {
    *(pointer++) = CAN_TX_Data[i+8*m];
   }
   CMR_CAN1 = Request_TX;
   W_WDT();
  }
  
  if ((UART_Length%8) != 0)
  {
   W_WDT();
   do         //发送缓冲区空么?
   {
    can_status = SR_CAN1;
   }
   while ((can_status&0x04) != 0x04);
   TXFrameInfo1 = 0x80 + UART_Length%8;
   pointer = &TXID1;
   for (i=0;i<4;i++)
   {
    *(pointer++) = CAN_TX_ID;
   }


   pointer = &TXDATA1;  
   for (i=0;i<(UART_Length%8);i++)
   {
    *(pointer++) = CAN_TX_Data[i+8*(UART_Length/8)];
   }
   CMR_CAN1 = Request_TX;
   W_WDT();
  }
  else
  {
  }
 }
 
 UART_Length = 0;


}


//-----------------------------------
//
//  CAN接收中断服务程序
//   
//   ----判断是否是RX中断,如果是
//    把接受到的CAN信息通过串行口发送出去
//   ----其他的中断说明CAN总线出现错误或脱离
//    
//-----------------------------------
void CAN_ISR(void) interrupt 0 using 1
{
 unsigned char can_int;


 EA = 0;


 can_int = IR_CAN1;
 if ((can_int&0x01) == 0x01)   //接收中断
 {
  CAN_Receive();
  CMR_CAN1 |= ReleaseRXBuf;
 }
 else
 {
  CAN_ERROR_flag = YES;   //其他中断,暂时未用
 }


 //UART_flag = YES;
 //CAN_flag = YES;
 UART_Transmit();


 EA = 1;
}

//-----------------------------------
//
//  CAN接收数据函数
//   
//   ----根据接受到的帧信息,按不同的长度存储
//    报文数据
//    
//-----------------------------------           
void CAN_Receive(void) using 1
{
 unsigned char i;
 unsigned char xdata *pointer;
 unsigned char Info;


 Info = RXFrameInfo1;


 if ((Info&0x80) == 0)   //standard Frame
 {
  //CAN_RX_ID[0] = RXID1;  
  //CAN_RX_ID[1] = RXID2;


  CAN_DataLength = Info&0x0f;
  pointer = &RXID3;
  for (i=0;i  {
   CAN_RX_Data = *(pointer++);
  }
  for (;i<8;i++)
  {
   CAN_RX_Data = 0x00;
  }
 }
 else       //Ex  Frame
 {
  //CAN_RX_ID[0] = RXID1;  
  //CAN_RX_ID[1] = RXID2;
  //CAN_RX_ID[2] = RXID3;  
  //CAN_RX_ID[3] = RXID4;
  CAN_DataLength = Info&0x0f;
  pointer = &RXDATA1;
  for (i=0;i  {
   CAN_RX_Data = *(pointer++);
   //pointer += 1;
  }
  for (;i<8;i++)
  {
   CAN_RX_Data = 0x00;
  }
 } 
}
//-----------------------------------
//
//  清0缓冲区
//   
//   ----pointer,指向待清0 的缓冲区首地址
//   ----length 清0 的长度   
//-----------------------------------
void Clear_Buffer(unsigned char *pointer,unsigned char length)
{
 unsigned char i;


 for (i=0;i {
  *(pointer++) = 0x00;
 }
}


另外头文件为:


#ifndef _CANCOM_H
#define _CANCOM_H


#define CS1_SJA1000  0x7f00       //SJA1000 Pin /CS ----> P2.7,low level active
  
#define MOD_CAN1  XBYTE[CS1_SJA1000+0]   //Peli
#define CMR_CAN1  XBYTE[CS1_SJA1000+1]  //command
#define SR_CAN1   XBYTE[CS1_SJA1000+2]   //state
#define IR_CAN1   XBYTE[CS1_SJA1000+3]   //interrupt
#define IER_CAN1  XBYTE[CS1_SJA1000+4]  //interrupt enable  //Peli
#define BTR0_CAN1  XBYTE[CS1_SJA1000+6]        //bus timing0
#define BTR1_CAN1  XBYTE[CS1_SJA1000+7]        //bus timing1
#define OCR_CAN1  XBYTE[CS1_SJA1000+8]
#define TEST_CAN1  XBYTE[CS1_SJA1000+9]
#define ECC_CAN1  XBYTE[CS1_SJA1000+12]  //error catch
#define EWLR_CAN1  XBYTE[CS1_SJA1000+13]  //error warning limit
#define RXERR_CAN1  XBYTE[CS1_SJA1000+14]  //
#define TXERR_CAN1  XBYTE[CS1_SJA1000+15]
#define ACR0_CAN1  XBYTE[CS1_SJA1000+16]
#define ACR1_CAN1  XBYTE[CS1_SJA1000+17]
#define ACR2_CAN1  XBYTE[CS1_SJA1000+18]
#define ACR3_CAN1  XBYTE[CS1_SJA1000+19]
#define AMR0_CAN1  XBYTE[CS1_SJA1000+20]
#define AMR1_CAN1  XBYTE[CS1_SJA1000+21]
#define AMR2_CAN1  XBYTE[CS1_SJA1000+22]
#define AMR3_CAN1  XBYTE[CS1_SJA1000+23]
#define RBSA_CAN1  XBYTE[CS1_SJA1000+30]  //beginning of receive
#define CDR_CAN1  XBYTE[CS1_SJA1000+31]  //clock devide


#define TXFrameInfo1  XBYTE[CS1_SJA1000+16]  
#define TXID1    XBYTE[CS1_SJA1000+17]  
#define TXID2    XBYTE[CS1_SJA1000+18]  
#define TXID3    XBYTE[CS1_SJA1000+19]  
#define TXID4    XBYTE[CS1_SJA1000+20]  
#define TXDATA1   XBYTE[CS1_SJA1000+21]
#define TXDATA2   XBYTE[CS1_SJA1000+22]
#define TXDATA3   XBYTE[CS1_SJA1000+23]
#define TXDATA4   XBYTE[CS1_SJA1000+24]
#define TXDATA5   XBYTE[CS1_SJA1000+25]
#define TXDATA6   XBYTE[CS1_SJA1000+26]
#define TXDATA7   XBYTE[CS1_SJA1000+27]
#define TXDATA8   XBYTE[CS1_SJA1000+28]


#define RXFrameInfo1  XBYTE[CS1_SJA1000+16]  
#define RXID1    XBYTE[CS1_SJA1000+17]  
#define RXID2    XBYTE[CS1_SJA1000+18]  
#define RXID3    XBYTE[CS1_SJA1000+19]  
#define RXID4    XBYTE[CS1_SJA1000+20]  
#define RXDATA1   XBYTE[CS1_SJA1000+21]
#define RXDATA2   XBYTE[CS1_SJA1000+22]
#define RXDATA3   XBYTE[CS1_SJA1000+23]
#define RXDATA4   XBYTE[CS1_SJA1000+24]
#define RXDATA5   XBYTE[CS1_SJA1000+25]
#define RXDATA6   XBYTE[CS1_SJA1000+26]
#define RXDATA7   XBYTE[CS1_SJA1000+27]
#define RXDATA8   XBYTE[CS1_SJA1000+28]


#define  GoToRESET    0x01
#define  ReleaseRXBuf   0x04
#define  Request_TX    0x01


#define  NOT  0
#define  YES  1
//4800bps 5bits 1.04mS
#define TIME_MS  1
#define temp_TH0 (0 - 922*TIME_MS)/256
#define temp_TL0 (0 - 922*TIME_MS)%256


sbit LED1 = P1^2;
sbit LED2 = P1^3;
sbit LED3 = P1^5;
sbit LED4 = P1^4;
sbit WDT = P3^4;


void System_init(void);
void Delay(unsigned char time);
void W_WDT(void);
void Interrupt_init(void);
void CAN_init(void);
//void CAN_Transmit(unsigned char Farmeinfo);
void CAN_Transmit(bit FarmeType);
void CAN_Receive(void);
void Timer_init(void);
void UART_ini(void);
void UART_Send_Byte(unsigned char Data);
void UART_Transmit(void);
void Clear_Buffer(unsigned char *pointer,unsigned char length);


#endif

文章评论1条评论)

登录后参与讨论

用户741296 2007-11-8 10:00

收了!

相关推荐阅读
用户59449 2007-11-27 13:57
晒刚画好的一个小板子
...
用户59449 2007-11-14 09:38
贴一个本人原创数字温湿度传感器SHT71的驱动程序
单片机:AVR  的ATMEGA128L温湿度传感器是SHT71,测量结果用串口发送出来程序如下:#include <iom128.h>#include <macros.h>#...
用户59449 2007-11-09 08:09
贴一个本人原创的图形点阵LCD驱动程序
说明:单片机是华邦的78E516B,液晶屏是T6963控制器的240×128点阵的,单片机总线方式访问。基本功能见各个函数的说明:#include "W78E516.h"#include #inclu...
用户59449 2007-11-05 17:34
关于电阻的一点总结
国家标准规定了电阻的阻值按其精度分为两大系列,分别为E-24系列和E-96系列,E-24系列精度为5%,E-96系列为1%, 在这两种系列之外的电阻为非标电阻,较难采购。下面列出了常用的5%和1%精度...
用户59449 2007-11-05 17:24
二极管的一些总结
 1、检波用二极管  就原理而言,从输入信号中取出调制信号是检波,以整流电流的大小(100mA)作为界线通常把输出电流小于100mA的叫检波。锗材料点接触型、工作频率可达400MHz,正向压降小,结电...
我要评论
1
7
关闭 站长推荐上一条 /2 下一条