如何一步一步建立CAN通讯
时间:12-14
来源:互联网
点击:
CAN通讯的优点在此就不多说了,10公里,5Kb/s的速度是能保证的。
第一步:硬件环境的建立。
这里采用的是SJA1000作为总线控制器,CTM8251模块作为总线驱动器。MCU采用的是MEGA16:利用I/O口模拟数据总线,当然也可以使用有总线的MCU:MCS-51,MEGA8515等。
原理图如下:
第二步:SJA1000的控制
首先阅读下SJA1000的手册,基本了解下SJA1000的结构,主要是寄存器方面的。还要了解下CAN总线方面的东西:BasicCAN,Peli CAN,远程帧,数据帧等等……
SJA1000工作之前需要配置一下,才能正常工作,没有经过配置的SJA1000回拉坏总线的:组成网络的时候,如果其中有的SJA1000没有正确配置,这个设备会干扰总线,使其它设备的数据发送不出去。
怎么才能控制SJA1000呢,请看下面的SJA1000读写的时序图:
写的时序
根据时序要求,可以利用I/O口模拟总线了:
//**************************读SJA1000*************************//
uint Read_SJA1000(uint address)
{
uchar data;
asm("nop");
ALE_off;
WR_on;
RD_on;
CAN_cs_on;
DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址
asm("nop");//delay5us(1);
ALE_on;
asm("nop");//delay5us(1);
//DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址 //再次输出地址,确保一致。
asm("nop");//delay5us(1);
ALE_off;
//delay5us(1);
CAN_cs_off;
RD_off;
asm("nop");//delay5us(2);
asm("nop");
DDRA=0x00; //数据口为输入
PORTA=0xff; //上拉
asm("nop");
data=PINA; //获得数据
asm("nop");//delay5us(1);
RD_on;
CAN_cs_on;
asm("nop");//delay5us(2);
//dog();
return data;
}
//**************************写SJA10000*************************//
void Write_SJA1000(uint address,uint data)
{ asm("nop");
//uint temp1,temp2;
DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址
CAN_cs_on;
ALE_off;
WR_on;
RD_on;
asm("nop");//delay5us(1);
ALE_on;
asm("nop");//delay5us(1);
//DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址 再次输出地址,确保数据准确
asm("nop");//delay5us(1);
ALE_off;
//delay5us(1);
CAN_cs_off;
WR_off;
asm("nop");//delay5us(1);
asm("nop");
//DDRA=0xff;
PORTA=data; //输出数据
asm("nop");//delay5us(2);
WR_on;
PORTA=data; //再次输出数据,取保一致
CAN_cs_on;
asm("nop");//delay5us(2);
asm("nop");
//dog();
}
现在可以读写SJA1000了。
配置SJA1000需要使SJA1000进入复位模式,然后对一些寄存器写入数据。在这里,CAN使用Pelican模式,速率为5K,双滤波工作,
//*************************CAN复位初始化********************//
void CAN_Init(void)
{ uchar i_temp=0,j_temp=0;
CLI();
//Read_SJA1000(CAN_IR); //读中断寄存器,清除中断位
Write_SJA1000(CAN_MOD,0x01);
while(!(Read_SJA1000(CAN_MOD)&0x01))//保证进入复位模式,bit0.0不为1,再写CAN_MOD
{
Write_SJA1000(CAN_MOD,0x01);
dog();
}
Write_SJA1000(CAN_CDR,0xc8); //配置时钟分频寄存器-Pelican,CBP=1,
//关闭TX1中断与时钟输出
Write_SJA1000(CAN_AMR0,0xff); //配置验收屏蔽AMR0=0FFH
Write_SJA1000(CAN_AMR1,0x00); //配置验收屏蔽AMR1=000H
Write_SJA1000(CAN_AMR2,0xff); //配置验收屏蔽AMR2=0FFH
Write_SJA1000(CAN_AMR3,0x00); //配置验收屏蔽AMR3=000H
Write_SJA1000(CAN_ACR1,0x00); //配置验收代码ACR1=0:广播
Write_SJA1000(CAN_ACR3,addr); //配置验收代码ACR3=地址
Write_SJA1000(CAN_BTR0,0x7f); //配置总线定时--5kbps
Write_SJA1000(CAN_BTR1,0xff);
Write_SJA1000(CAN_OCR,0x1a); //配置输出控制
Write_SJA1000(CAN_EWLR,0xff); //配置错误报警限制为255
do
{
Write_SJA1000(CAN_MOD,0x00); //进入工作模式双滤波
dog();
}
while((Read_SJA1000(CAN_MOD))&0x01); // 确认复位标志是否被删除
Write_SJA1000(CAN_TXB+4,ID3); //配置发送缓冲区的ID3-
Write_SJA1000(CAN_IER,0x07); //配置SJA10000中断-错误报警/发送/接收中断
SEI();
}
在这之前,需要获取设备的地址,就是读取拨码开关各个脚的电平。需要注意的是,SJA1000使用的是双滤波模式,响应地址有:广播的:0x00,还有自己的地址:0x**。为什么要这么做呢,一个系统中,主机的地址一般是0X00,从机地址从0X01开始,这里面如果有两个从机的地址一样,就很可能产生一些混乱。从机一旦多了起来,查找地址相同的设备就有些麻烦了。
在程序的初始化的时候,进行SJA1000的配置。
第三部:工作程序
接下来,做的工作就是CAN试发送,别小看这个试发送,这可是解决地址重复的问题的哦,还能检测CAN网络是否正常。
//****************CAN第一次发送 通讯地址测试2e*****************//
void CAN_first_send(void)
{ //uchar add_temp=0;
uchar a_temp=0;
uchar SR_temp;
asm("nop"); //延时
NET_
第一步:硬件环境的建立。
这里采用的是SJA1000作为总线控制器,CTM8251模块作为总线驱动器。MCU采用的是MEGA16:利用I/O口模拟数据总线,当然也可以使用有总线的MCU:MCS-51,MEGA8515等。
原理图如下:
第二步:SJA1000的控制
首先阅读下SJA1000的手册,基本了解下SJA1000的结构,主要是寄存器方面的。还要了解下CAN总线方面的东西:BasicCAN,Peli CAN,远程帧,数据帧等等……
SJA1000工作之前需要配置一下,才能正常工作,没有经过配置的SJA1000回拉坏总线的:组成网络的时候,如果其中有的SJA1000没有正确配置,这个设备会干扰总线,使其它设备的数据发送不出去。
怎么才能控制SJA1000呢,请看下面的SJA1000读写的时序图:
写的时序
根据时序要求,可以利用I/O口模拟总线了:
//**************************读SJA1000*************************//
uint Read_SJA1000(uint address)
{
uchar data;
asm("nop");
ALE_off;
WR_on;
RD_on;
CAN_cs_on;
DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址
asm("nop");//delay5us(1);
ALE_on;
asm("nop");//delay5us(1);
//DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址 //再次输出地址,确保一致。
asm("nop");//delay5us(1);
ALE_off;
//delay5us(1);
CAN_cs_off;
RD_off;
asm("nop");//delay5us(2);
asm("nop");
DDRA=0x00; //数据口为输入
PORTA=0xff; //上拉
asm("nop");
data=PINA; //获得数据
asm("nop");//delay5us(1);
RD_on;
CAN_cs_on;
asm("nop");//delay5us(2);
//dog();
return data;
}
//**************************写SJA10000*************************//
void Write_SJA1000(uint address,uint data)
{ asm("nop");
//uint temp1,temp2;
DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址
CAN_cs_on;
ALE_off;
WR_on;
RD_on;
asm("nop");//delay5us(1);
ALE_on;
asm("nop");//delay5us(1);
//DDRA=0xff; //数据口为输出
PORTA=address; //输出数据的地址 再次输出地址,确保数据准确
asm("nop");//delay5us(1);
ALE_off;
//delay5us(1);
CAN_cs_off;
WR_off;
asm("nop");//delay5us(1);
asm("nop");
//DDRA=0xff;
PORTA=data; //输出数据
asm("nop");//delay5us(2);
WR_on;
PORTA=data; //再次输出数据,取保一致
CAN_cs_on;
asm("nop");//delay5us(2);
asm("nop");
//dog();
}
现在可以读写SJA1000了。
配置SJA1000需要使SJA1000进入复位模式,然后对一些寄存器写入数据。在这里,CAN使用Pelican模式,速率为5K,双滤波工作,
//*************************CAN复位初始化********************//
void CAN_Init(void)
{ uchar i_temp=0,j_temp=0;
CLI();
//Read_SJA1000(CAN_IR); //读中断寄存器,清除中断位
Write_SJA1000(CAN_MOD,0x01);
while(!(Read_SJA1000(CAN_MOD)&0x01))//保证进入复位模式,bit0.0不为1,再写CAN_MOD
{
Write_SJA1000(CAN_MOD,0x01);
dog();
}
Write_SJA1000(CAN_CDR,0xc8); //配置时钟分频寄存器-Pelican,CBP=1,
//关闭TX1中断与时钟输出
Write_SJA1000(CAN_AMR0,0xff); //配置验收屏蔽AMR0=0FFH
Write_SJA1000(CAN_AMR1,0x00); //配置验收屏蔽AMR1=000H
Write_SJA1000(CAN_AMR2,0xff); //配置验收屏蔽AMR2=0FFH
Write_SJA1000(CAN_AMR3,0x00); //配置验收屏蔽AMR3=000H
Write_SJA1000(CAN_ACR1,0x00); //配置验收代码ACR1=0:广播
Write_SJA1000(CAN_ACR3,addr); //配置验收代码ACR3=地址
Write_SJA1000(CAN_BTR0,0x7f); //配置总线定时--5kbps
Write_SJA1000(CAN_BTR1,0xff);
Write_SJA1000(CAN_OCR,0x1a); //配置输出控制
Write_SJA1000(CAN_EWLR,0xff); //配置错误报警限制为255
do
{
Write_SJA1000(CAN_MOD,0x00); //进入工作模式双滤波
dog();
}
while((Read_SJA1000(CAN_MOD))&0x01); // 确认复位标志是否被删除
Write_SJA1000(CAN_TXB+4,ID3); //配置发送缓冲区的ID3-
Write_SJA1000(CAN_IER,0x07); //配置SJA10000中断-错误报警/发送/接收中断
SEI();
}
在这之前,需要获取设备的地址,就是读取拨码开关各个脚的电平。需要注意的是,SJA1000使用的是双滤波模式,响应地址有:广播的:0x00,还有自己的地址:0x**。为什么要这么做呢,一个系统中,主机的地址一般是0X00,从机地址从0X01开始,这里面如果有两个从机的地址一样,就很可能产生一些混乱。从机一旦多了起来,查找地址相同的设备就有些麻烦了。
在程序的初始化的时候,进行SJA1000的配置。
第三部:工作程序
接下来,做的工作就是CAN试发送,别小看这个试发送,这可是解决地址重复的问题的哦,还能检测CAN网络是否正常。
//****************CAN第一次发送 通讯地址测试2e*****************//
void CAN_first_send(void)
{ //uchar add_temp=0;
uchar a_temp=0;
uchar SR_temp;
asm("nop"); //延时
NET_
CAN通讯硬件环 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)