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