基于CAN总线大作业.docx
《基于CAN总线大作业.docx》由会员分享,可在线阅读,更多相关《基于CAN总线大作业.docx(12页珍藏版)》请在冰豆网上搜索。
基于CAN总线大作业
基于CAN总线的楼宇智能环境智能监测系统设计
某楼宇有多个房间(如下图所示),其中一个房间可作为集中监控室,每个房间都安装温度和湿度传感器,并通过CAN总线监测到的温度、湿度信号发送到监控室中的上位机PC用于随时监控各房间的环境状况。
1)介绍CAN总线网络层次结构。
CAN总线与简单总线逻辑不同,CAN是一种复杂逻辑的总线结构。
参照ISO/OSI标准模型,CAN分为数据链路层和物理层。
而数据链路层又包括逻辑链路子层LLC(LogicLinkControl)和媒体访问控制子层MAC(MediumAccessControl)。
CAN的通信参考模型如图一所示。
1.物理层
在物理层中定义实际信号的传输方法,包括位的编码和解码、位的定时和同步等内容,作用是定义不同节点之间根据电气属性如何进行位的实际传输。
在物理连接上,CAN总线结构提供两个引脚--CANH和CANL,总线通过CANH和CANL之间的差分电压完成信号的位传输。
2.逻辑链路子层LLC
逻辑链路子层LLC的主要功能是,对总线上传输的报文实行接收滤波,判断总线上传输的报文是否与本节点有关,哪些报文应该为本节点接收;对报文的接收予以确认;为数据传送和远程数据请求提供服务;当丢失仲裁或被出错干扰时,逻辑链路子层具有自动重发的恢复管理功能等。
3.媒体访问控制子层MAC
MAC子层是CAN协议的核心。
它负责执行总线仲裁、报文成帧、出错检测、错误标定等传输控制规则。
数据链路层
逻辑链路子层LLC
接收滤波
超载通州
恢复管理
媒体访问控制层MAC
数据封装/拆装
帧编码(填充/解除填充)
媒体访问管理
错误检测
出错标定
应答
串行化/解除串行化
物理层
位编码/解码
位定时
同步
驱动器/接收器特性
连接器
图一CAN的通信参考模型
2)介绍CAN总线通讯协议的报文格式。
根据CAN报文帧的不同用途,可以把CAN报文帧划分为以下4种类型,数据帧,远程帧,出错帧,超载帧。
1.数据帧
数据帧携带数据从发送器至接收器。
总线上传输的大多是这种帧,从标识符长度上,又可以把数据帧分为标准帧(11位标识符)和扩展帧(29位标识符)。
数据帧由7个不同的位场组成:
帧起始、仲裁场、控制场、数据场、CRC场、应答场、帧结束。
其中,数据场的长度为0~8个字节。
标识符位于仲裁场中,报文接收节点通过标识符进行报文滤波。
数据帧结构如图二所示。
图二数据帧结构
2.远程帧
由总线上的节点发出,用于请求其他节点发送具有同一标识符的数据帧。
当某个节点需要数据时,可以发送远程帧请求另一节点发送相应数据帧。
与数据帧相比,远程帧没有数据场。
远程帧结构如图三所示。
图三远程帧结构
3.出错帧
任何单元,一旦检测到总线错误就发出错误帧。
错误帧由两个不同的场组成,第一个场是由不同站提供的错误标志的叠加(错误标志),第二个场是错误界定符。
出错帧结构如图四所示。
图四出错帧结构
4.超载帧
超载帧用于在先行的和后续的数据帧(或远程帧)之间提供附加延时。
超载帧包括两个场:
超载标志和超载界定符。
超载帧结构如图五所示。
图五超载帧结构
3)在总线上传输的报文以帧结构进行传输,与CAN总线传输相关的关键技术术是什么?
实现过程是什么?
答:
在CAN系统中为保证报文传输的正确性,需要对通信过程进行差错控制。
目前常用的方法是反馈重发,即一旦收到接收端发出的出错信息,发送端便自动重发,此时的差错控制只需要检错功能。
常用的检错码有两类:
奇偶校验码和循环冗余校验码。
奇偶校验码是一种最常见的检错码,其实现方法简单,但检错能力较差;循环冗余校验码的编码也很简单且误判率低,所以在通信系统中获得了广泛的应用。
下面介绍CAN网络中循环冗余校验码(即CRC码)的原理和实现方法。
1、CRC码检错的工作原理
CRC码检错是将被处理报文的比特序列当作一个二进制多项式A(×)的系数,该系数除以发送方和接收方预先约定好的生成多项式g(×)后,将求得的余数p(×)作为CRC校验码附加到原始的报文上,并一起发给接收方。
接收方用同样的g(×)去除收到的报文B(×),如果余数等于p(×),则传输无误(此时A(×)和B(×)相同);否则传输过程中出错,由发送端重发,重新开始CRC校验,直到无误为止。
上述校验过程中有几点需注意:
①在进行CRC计算时,采用二进制(模2)运算法,即加法不进位,减法不借位,其本质就是两个操作数进行逻辑异或运算;②在进行CRC计算前先将发送报文所表示的多项式A(×)乘以×n,其中n为生成多项式g(×)的最高幂值。
对二进制乘法来讲,A(×)·×n就是将A(×)左移n位,用来存放余数(×),所以实际发送的报文就变为A(×)·×n+p(×);③生成多项式g(×)的首位和最后一位的系数必须为1。
目前已经有多种生成多项式被列入国际标准中,如:
CRC-4、CRC-12、CRC-16、CCITT-16、CRC-32等。
CAN总线中采用的生成多项式为g(×)=×15+×14+×10+×8+×7+x4+×3+1。
可以看出,CAN总线中的CRC校验采用的多项式能够校验七级,比一般CRC校验(CRC-4、CRC-12、CRC-16等)的级数(二~五级)要高许多,因而它的检错能力很强,误判率极低,成为提高数据传输质量的有效检错手段。
2、CRC序列计算方法
多项式g(×)除法的余数就是发送到总线上的CRC序列。
为了实现这个功能,可以使用15位的移位寄存器----CRC_RG(14 :
0)。
如果NXTBIT指示位流的下一位,那么从帧的起始到数据末尾都由没有填充的位顺序给定。
CRC序列的计算如下:
CRC_RG=0;//初始化移位寄存器
REPEAT
CRCNXT=NXTBITEXORCRC_RG(14);//异或运算
CRC_RG(14:
1)=CRC_RG(13:
0);//寄存器左移1位
CRC_RG(0)=0;
IFCRCNXTTHEN
CRC_RG(14:
0)==CRC_RG(14:
0)EXOR(H)
ENDIF
UNTIL(CRC序列开始或有一错误条件)
4)进行测量结点的硬件设计(基于AT89S51、SJA1000的CAN总线智能结点的总体设计)。
SJA1000在电路中是一个总线接口芯片,通过它实现上位机与现场微处理器之间的数据通信。
该电路的主要功能是通过CAN接收来自上位机的数据进行分析组态然后就传给下位机的控制电路实现控制功能,当CAN总线接口收到下位机上传的数据,SJA1000就产生一个中断,引发微处理器产生中断,通过中断处理程序接收每一帧信息并通过CAN总线上传给上位机进行分析。
AT89S51是CAN总线接口电路的核心,其承担CAN控制器的初始化、CAN的收发控制等任务。
1、单片机AT89S51的选取:
1)4kBytesFlash片内程序存储器;
2)128bytes的随机存取数据存储器(RAM);
3)32个外部双向输入/输出(I/O)口;
4)6个中断源;
5)2个16位可编程定时器/计数器;
6)2个全双工串行通信口;
7)片内振荡器和时钟电路;
8)全静态工作:
0Hz-33MHz;
9)可编程串行通道;
10)低功耗的闲置和掉电模式。
在设计电路时要注意:
①总线两端必须接凉的终端匹配电阻;②SJA1000的TX1引脚的电位必须维持在约0.5V上;③将SJA1000的CLOCKOUT的时钟信号接至AT89S51的时钟电路输入端。
故其中的部分接线按以下说明来接:
CAN总线控制器SJA1000AD0~AD7连接到AT89S51的P0口,片选段CS非连接到AT89S51的P2.7,P2.7为1时,CPU外存储器可选中SJA1000,CPU通过这些地址就可对SJA1000执行相应的读/写操作。
SJA1000的RD非、WR非、ALE分别于单片机AT89S51对应的引脚相连。
由于SJA1000是低电平复位,单片机AT89S51是高电平复位,因此两者的复位电路的设计也不同。
SJA1000的11脚接高电平,选择Intel的二分频模式。
16脚的中断INT非接到单片机相应的外部中断0的输入脚INT0非。
5)进行硬件设计,包括AT89S51编程,CAN通讯协议等(CAN结点初始化,报文发送和报文接收三部分的设计作一个描述)。
1、串口初始化:
1)、确定T1的工作方式(方式2:
编程TMOD=0x20)。
2)、计算T1的初值,装载TH1,TL1(T1:
0xFD)。
3)、启动T1(编程TCON中的TR1位)。
4)、确定串行口控制(编程SCON寄存器);
5)、在中断方式工作时,要进行中断设置(编程IE,IP寄存器)。
2、程序
1)、主程序(单片机)
#include
Unsignedcharhas_r,rec_c;
Voidmain()
{
TMOD=0x20;//设T1工作方式位方式2
TH1=0xFD;
TL1=0xFD;
TR1=1;//打开T1
REN=1;//串口允许接收
SM0=0;//设置方式1
SM1=1;
SM2=0;
EA=1;//开串行总中断
ES=1;//开串行中断
While
(1)
{
if(has_r==1)
ES=0;//关串行中断
has_r=0;
SBUF=rec_c;
while(!
TI)
TI=0;
ES=1;
}
}
Voidser()interrupt4//接收中断
{
RI=0;//接收中断标志位清0
Rec_c=SBUF;
Has_r=1;//接收完成标志
}
2)、CAN控制器SJA1000的初始化程序
MOVDPTR,#MODE;模式寄存器
MOVA,#09H;进入复位模式,对SJA1000进行初始化
MOV@DPTR,A
MOVDPTR,#CDR;时钟分频寄存器
MOVA,#88H
MOVX@DPTR,A
NOVDPTR,#IFR;中断允许寄存器
MOVA,#0DH;开放发送中断、溢出中断
MOVX@DPTR,A
MOVDPTR,#AMR;验收屏蔽寄存器
MOVR6,#4
MOVR0,#DAMR
AMRINI:
MOVA,@R0
MOVX@DPTR,A;验收屏蔽寄存器赋初值
INCDPTR
DJNZR6,AMRINI
MOVDPTR,#ACR;验收代码寄存器
MOVR6,#4
MOVR0,#DACR
ACRINI:
MOVA,@R0
MOVX@DPTR,A;验收代码寄存器赋初值
INCDPTR
DJNZR6,ACRINI
MOVDPTR,#BTR0;总线定时寄存器0
MOVA,#03H
MOVX@DPTR,A
MOVDPTR,#BTR1;总线定时寄存器1
MOVA,#0FFH;设置波特率
MOVX@DPTR,A
MOVDPTR,#0CH;输出控制寄存器
MOVA,#0AAH
MOVX@DPTR,A
MOVA,#0;设置接收缓存器起始地址
MOVX@DPTR,A
MOVDPTR,#TXERR;发送错误计数寄存器
MOVA,#0;清除发送错误计数寄存器
MOVX@DPTR,A
MOVDPTR,#ECC;错误代码捕捉寄存器
MOVXA,@DPTR;清除错误代码捕捉寄存器
MOVDPTR,#MODE;模式寄存器
MOVA,#08H;设置单滤波接收方式,并返回
MOVX@DPTR,A
REI
3)、SJA1000发送程序
VoidCanSend(unsignedchar*bufDATA;Unsignedchardatalen)//Can设备发送函数
{unsignedintsja_addr;
unsignedcharj=0,temp;
unsignedintn;
sja_addr=SJA_EFF;
SendBufInfo=datalen;
WR_SJA(sja_addr.++;sendBufInfo)
{
for(j=0,j<2,j++)
WR_SJA(sja_addr+j,*(SendBufId+j));
unsignedcharsendBufId[2]={0x07,0x20};
for(j=0,jWR_SJA(sja_addr+2+j,*(bufDATA+j));
WR_SJA(sja_CMR,0x03);
for(n=0,n{
temp=RD_SJA(SJA_SR);
#defineSJA_SR2
if((temp8c0x08)==0x08)
{
for(n=0,n<300,n++);
break;
}
}
}
}
VoidWR_SJA(unsignedcharsja_addr,unsignedcharsja_date)
{
ALE_CAN=1//开启地址锁存允许将I/O口的地址锁存
P0=sja_addr;
delay2(3);
ALE_CAN=0//关闭地址锁存,改为发送数据有效
delay2
(1);
CS_CAN=0;
WR_CAN=0;
P0=sja_data
Delay2(4)
WR_CAN=1;//恢复到操作前的状态,避免影响单片机对SJA1000的该操作
CS_CAN=1;
ALE_CAN=0;
}
4)、SJA1000中断接收程序
Voidcan_rx_isr(void)interrupt0//功能SJA1000接收中断函数
{
unsignedchark=0;
unsignedcharsja_addr;
EA=0;
if((RD_SJA(SJA_IR)8c0x01)==0x01)
sja_addr=SJA_EFF
{
if(canRxAddr==MaxLen.Can.RxBuf)//unsigendintMaxLenCanRxBuf=440
CanRxBuf=0;
for(k=0;k<11;k++)
{
CanRxBuf[CanRxAdd+k]=RD_SJA(sja_addr);sja_addr++;
}
WR_SJA(SJA_CMR,0x04);
CanRxAddr+=11;
CanRxcompdateflag+=1
}
EA=1;
}
unsignedcharRD_SJA(unsignedcharSJA_addr)//读地址为SJA_addr的寄存器中的数据,通过ALE、RD、CS配合完成
{
unsignedcharSJA.date;
ALE_CAN=1;//置高开启地址锁存允许将I/O口的数据锁存
P0=SJA_addr;delay2(3);
ALE_CAN=0;
delay2
(1);
CS_CAN=0;//使能片选
P1=0xff;//I/O口初始化
RD_CAN=0;//使能读有效
delay2(4);
SJA_date=P0;
RD_CAN=1;
CS_CAN=1;
ALE_CAN=1;
ReturnSJA_data;
}