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

📄 can实验装置程序.txt

📁 我自己开发的CAN总线实验软件
💻 TXT
字号:
// 2007.12.21--温世坚。查询方式接收CAN报文。
/********************************
采用stc89c52+sja1000,分离晶体,stc89c52晶体11.0592M
    sja1000外部晶体为16M,   
*********************************/
#include<reg52.h>
#include<absacc.h>
#include<intrins.h>
#include<stdio.h>
#include<dingyi.h>
#define AD0809 0x7f00
#define LED XBYTE[0xbf00]
//#define fengming P1^7;
/*              全局寄存器及变量声明区                 */
uchar S_Data[13];
uchar R_Data[13];
unsigned char comm_rec[13];
uchar i,j,k;
uchar rec_count;
uchar comm_rec_flag;        //串口接受标志位
uchar can_rec_flag;         //CAN接收标志位
sbit start=P3^3; 
sbit fengming=P1^7;
unsigned char seg[]={0xb7,0x12,0x67,0x76,0xd2,0xf4,0xf5,0x16,0xf7,0xf6};
void shumaxianshi();
void CanInt();
void delay(uchar x);
void xianshi();


/*               函数声明区                        */
void get_id();
void receive();// 
void send2pc(uchar temp);// 串口发送单个字节
void CommSend(unsigned char p[13]); //串口数组发送,可以一次发送13个字节
void commrecd();   //串口接收,每次一个字节中断方式。

void MCU_Init(void);
void SJA_Init(void);
void send();
void ch_btr();
void writebyte(uchar addr,uchar dat);
uchar readbyte(uchar addr);
//void shuma(uchar i,uchar j);

/* 向特定地址单元写一个字节的数据 */
/* 入口:addr,dat                 */
/* 出口:无                       */                    
void writebyte(uchar addr,uchar dat)
{
  XBYTE[SJA_REG_BaseADD + addr]=dat;
}
/* 从特定单元读一个字节的数据     */
/* 入口:addr                     */
/* 出口:i   (uchar类型的一个字节)*/

uchar readbyte(uchar addr)
{
  uchar i;
  i=XBYTE[SJA_REG_BaseADD + addr];
  return i;
}

void shumaxianshi()
{ 
  unsigned char temp;
  SCON=0x00;
  start=1;
  temp=R_Data[6];
  SBUF=temp;
  while(!TI);
  TI=0;
  //start=0;
  temp=R_Data[7];
  SBUF=temp;
  while(!TI);
  TI=0;
  //start=0;
  temp=R_Data[8];
  SBUF=temp;
  while(!TI);
  TI=0;
  //start=0;
  temp=R_Data[9];
  SBUF=temp;
  while(!TI);
  TI=0;
  start=0;


}


/*******************************************************
    
    以下为c的主程序

    
    *******************************************************/

main()
{
  uchar temp,temp1;
  unsigned int temp2;
  SP=0x60;
  MCU_Init();
  SJA_Init();
  xianshi();   //上电自检测,包括数码管和8个LED
  fengming=1;
  S_Data[0]=0x88;   // CON
  S_Data[1]=0x33;   // ID3
  S_Data[2]=0x64;   // ID2
  S_Data[3]=0x99;   // ID1
  S_Data[4]=0xf8;   // ID0   F8
  while(1)
  { 
    receive();             //CAN查询方式进行数据接收
    if(can_rec_flag==1)    //判断是否接收成功
    {
      can_rec_flag=0;
	  //if(R_Data[2]!=0x55)continue;  //排除一定的条件
      switch(R_Data[5])
      {
      case 0x01:        //R_Data[5]=0x01 读CAN寄存器
        S_Data[7]=readbyte(R_Data[6]);
        S_Data[6]=R_Data[6];
        S_Data[5]=0x01;
        send();		   //读,返回
        break;
      case 0x02:         //R_Data[5]=0x02 写CAN寄存器
        writebyte(R_Data[6],R_Data[7]);
        S_Data[7]=readbyte(R_Data[6]);
        S_Data[6]=R_Data[6];
        S_Data[5]=0x02;
        send();			 //写,返回
        break;
      case 0x03:          //R_Data[5]=0x03 修改CAN的通信波特率
        ch_btr();
        break;
      case 0x04:          //    =00x04  A/D转换
        XBYTE[AD0809+R_Data[6]]=1;
        for(temp=0;temp<250;temp++);
        S_Data[7]=XBYTE[AD0809+R_Data[6]];
        S_Data[6]=R_Data[6];
        S_Data[5]=R_Data[5];
        send();			 //AD转换,返回
        break;
      case 0x05:          //  电机启动,停止。此处功能不仅仅是对电机进行控制,还可以选择性的控制P1口。
        temp1=P1 & R_Data[6];
        temp=~R_Data[6];
        temp=temp & R_Data[7];
        P1=temp |temp1;
        //S_Data[7]=R_Data[7];
        //S_Data[6]=R_Data[6];
        //S_Data[5]=R_Data[5];
        //send();				//返回
        break;
      case 0x06:          //   LED
        LED=R_Data[7];
        //S_Data[7]=R_Data[7];
        //S_Data[6]=R_Data[6];
        //S_Data[5]=R_Data[5];
        //send();			//LED返回
        break;
      case 0x07:          //数码管
        shumaxianshi();
        //S_Data[7]=R_Data[7];
        //S_Data[6]=R_Data[6];
        //S_Data[5]=0x07;
        //send();			 //数码管返回
        break;
      case 0x08:          //读开关量
	  	S_Data[6]=LED;
		S_Data[5]=0x08;
		send();			//开关量返回
		break;
      case 0x09:				//获取CAN节点的ID号
        get_id();
        S_Data[5]=0x09;
        send();			 //ID号返回
        break;
	  case 0x0a:							   //写CAN节点的外设,地址R_Data[6]*256+R_Data[7},数据:R_Data[8]
	  	temp2=R_Data[6]*256;
	  	XBYTE[temp2+R_Data[7]]=R_Data[8];	   
		//S_Data[8]=R_Data[8];
        //S_Data[7]=R_Data[7];
        //S_Data[6]=R_Data[6];
        //S_Data[5]=0x0a;
        //send();					   //写外设返回
		break;
	  case 0x0b:							   //读CAN节点的外设,地址R_Data[6]*256+R_Data[7},数据:R_Data[8]
	  	temp2=R_Data[6]*256;
	  	R_Data[8]=XBYTE[temp2+R_Data[7]];
		S_Data[8]=R_Data[8];
        S_Data[7]=R_Data[7];
        S_Data[6]=R_Data[6];
        S_Data[5]=0x0b;
        send();
		break;
	  case 0xaa:
	  	EA=0;
	  	if((R_Data[2]==0xa9)&&(R_Data[3]==0xa9)&&(R_Data[4]==0xa8))EA=1;
		break;

      }//switch
    }//if
  }//while
}   //main



void MCU_Init(void)
{ 
  //
  //xianshi();   //上电自检测,包括数码管和8个LED
  //
  //LED=0xff;
  //R_Data[6]=0x0;
  //R_Data[7]=0x0;
  //shumaxianshi();
  TMOD =0x20;
  SCON=0x50;
  PCON=0x80;
  TH1=0xfd;
  TL1=0xfd;
  TR1=1;
  TCON=0x0;	 //外部中断0,低电平出发方式
  EX0=1;	 //允许外部中断0
  EA = 0;	 //关闭中断
  ES = 0;

}

/* SJA1000初始化                      */
/* 入口:无                           */
/* 出口:无                           */
/* 功能:初始化,单滤波,扩展帧格式。 */
/* 参数:
                      ID3 ID2 ID1 ID0               AMR3 AMR2 AMR1 AMR0

  转换器 || 本地ID:  01、22、33、40    || 本地AMR: FF、 FF、 FF、 FF
         
  CAN节点|| 本地ID:  XX、22、33、40    || 本地AMR: 00、 FF、 FF、 FF
         
                                      */


void SJA_Init(void)
{
  unsigned char i;
  ES=0;                 //禁用串口中断
  for(i = 0;i < 125;i++);
  for(i = 0;i < 125;i++);
  for(i = 0;i < 125;i++);
  while((REG_MODE& 0x01)!= 0x01) REG_MODE=0x01;//在复位模式中
  REG_IR_ABLE = 0x00;       //interrupt disable
  REG_BTR0 = 0x45;
  REG_BTR1 = 0x2b; //40k at 16M
  REG_OCR = 0x1a;  //normal mode,推挽输出
  REG_CDR = 0xc8;  //peliCAN, 旁路缓冲器,clock off,f/2
  REG_RBSA = 0x00; //接收缓存起始地址
  REG_ACR0 = LED;   //0x40;  //ID3
  REG_ACR1 = 0xa8;  //ID2
  REG_ACR2 = 0xa8;  //ID1
  REG_ACR3 = 0xa8;  //ID0
  REG_AMR0 = 0x00;
  REG_AMR1 = 0xff;
  REG_AMR2 = 0xff;
  REG_AMR3 = 0xff;
  i=REG_ECC;
  REG_TXERR=0;
  REG_MODE = 0x08; //normal模式,单滤波
  while((REG_MODE & 0x0f)!= 0x08) REG_MODE=0x08;
  ES=1;
}

/* CAN发送子程序  ,能够一次性发送13个字节的数据 */
/* 入口:S_Data[13]    (全局变量)                */
/* 出口:无                                      */

void send()//要发送的数据(13位)存于s_data数组
{
  uchar temp_data1,temp;
  REG_CMD = 0x02;					//取消正在发送的数据
  do{temp_data1 = REG_SR;}             //判断是否正在接收,是则等待
    while((temp_data1 & 0x10) == 0x10);
  do{temp_data1 = REG_SR;}             //判断上次是否发送完成,未完成则等待
    while((temp_data1 & 0x08) != 0x08);
  do{temp_data1 = REG_SR;}
    while((temp_data1 & 0x04) != 0x04); //发送缓冲区是否锁定,等待可向发送缓冲器写
  for(temp_data1=0;temp_data1<13;temp_data1++)  //装入数据
       {temp= S_Data[temp_data1];
       //send2pc(temp);
        XBYTE[SJA_REG_BaseADD + 0x10+temp_data1]=temp;
        }
  //red=0;
  REG_CMD = 0x01;  //send
}

/* CAN接收子程序,查询方式接收                  */
/* 入口:无                                     */
/* 出口:R_Data[13]  (全局变量)                 */
/* 功能:通过查询状态位SR。0得到是否可以接收报文*/

void receive() //接收的数据(13位)存于s_data数组
{
  uchar temp_data1;
  uchar temp; 
  temp= REG_SR;
  if((temp & 0x01) == 0x01) //有接收数据
    {
      can_rec_flag=1;                                 //CAN数据接收标志
      ES=0;
      for(temp_data1=0;temp_data1<13;temp_data1++)//读出数据
        { 
          temp=XBYTE[SJA_REG_BaseADD + 0x10+temp_data1];
          R_Data[temp_data1]=temp;                  //把接收的数据保存在R_Data[]中
        }
       ES=1;

      REG_CMD =0x04;  //释放接收缓存
     }
  if((temp & 0x40) == 0x40)//Error    //错误计数器超出计数限额
    {
    REG_CMD =0x04;
    temp=REG_ECC;                     //错误状态
    REG_TXERR=0;                      //读取并清除出错误
    REG_RXERR=0;
    return;
    }   
  if((temp & 0x02)==0x02)
    {
      REG_CMD=0x08;
      return;
    }


}

void ch_btr()
{
  uchar temp;
  for(temp=0;temp<255;temp++);
  for(temp=0;temp<255;temp++);
  while((REG_MODE & 0x01)!=0x01) REG_MODE=0x09;
  REG_BTR0=R_Data[6];
  REG_BTR1=R_Data[7];
  while((REG_MODE & 0x0f)!=0x08)REG_MODE=0x08;
}

void get_id()
{
  uchar temp;
  for(temp=0;temp<255;temp++);
  for(temp=0;temp<255;temp++);
  while((REG_MODE & 0x01)!=0x01) REG_MODE=0x09;
  S_Data[6]= REG_ACR0; //ID3
  S_Data[7]= REG_ACR1; //ID2
  S_Data[8]= REG_ACR2; //ID1
  S_Data[9]= REG_ACR3; //ID0
  while((REG_MODE & 0x0f)!=0x08)REG_MODE=0x08;
}

//100 U秒的延时程序
void delay(uchar x)
{
	uchar m,n;
	for(m=100;m>0;m--)
		for(n=x;n>0;n--);
}

//中断方式发送数据,低电平触发
void CanInt() interrupt 0 using 2
{
	S_Data[0]=0x88;
	S_Data[1]=LED;	 //ID号
	S_Data[2]=0xaa;
	S_Data[3]=0xaa;
	S_Data[4]=0xaa;
	S_Data[5]=0x04;
	S_Data[6]=0x0;
    XBYTE[AD0809+R_Data[6]]=1;
    delay(1);
    S_Data[7]=XBYTE[AD0809+R_Data[6]]; //读ADC0809
	send();
	//LED=0XAA;
}

void xianshi() 	//上电自检测,包括数码管和8个LED
{
	uchar m,n;
	m=0x01;
	P1=0X7F;
	for(n=0;n<8;n++)
	{
		R_Data[6]=m;
		R_Data[7]=m;
		R_Data[8]=m;
		R_Data[9]=m;
		shumaxianshi();		//数码管逐位笔形显示
		LED=m;				//LED逐个点亮
		delay(250);
		//delay(200);
		m=m+m;
		//P1=0XFF;
	}
		P1=0XFF;
		R_Data[6]=0xff;
		R_Data[7]=0xff;
		R_Data[8]=0xff;
		R_Data[9]=0xff;
		shumaxianshi();	  //点亮所有的数码管
		LED=0xFF;		  //点亮LED
		delay(250);
		delay(250);
		delay(250);
		delay(250);
		R_Data[6]=0x00;	  //熄灭
		R_Data[7]=0x00;
		R_Data[8]=0x00;
		R_Data[9]=0x00;
		shumaxianshi();
		LED=0x00;		  //熄灭

}

⌨️ 快捷键说明

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