📄 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 + -