</div><!--end: blogStats -->
</div><!--end: navigator 博客导航栏 -->
CAN总线要点
CAN总线要点
前言
CAN总线的应用在现在看来越来越广泛,我厂设备从最初的ARM9与ARM7平台、期间升级过度到CortexA8与Cortex M3平台,再到现在的Cortex M4平台,围绕CAN进行了一系列产品的开发,CAN总线的稳定性是毋庸置疑的。
CAN总线物理结构与特性
CAN总线网络
CAN总线网络主要挂在CAN_H和CAN_L,各个节点通过这两条线实现信号的串行差分传输,为了避免信号的反射和干扰,还需要在CAN_H和CAN_L之间接上120欧姆的终端电阻,但是为什么是120欧姆呢?那是因为电缆的特性阻抗为120欧。
CAN收发器
CAN收发器的作用是负责逻辑电平和信号电平之间的转换。
即从CAN控制芯片输出逻辑电平到CAN收发器,然后经过CAN收发器内部转换将逻辑电平转换为差分信号输出到CAN总线上,CAN总线上的节点都可以决定自己是否需要总线上的数据。具体的管教定义如下:
信号表示
CAN总线采用不归零码位填充技术,也就是说CAN总线上的信号有两种不同的信号状态,分别是显性的(Dominant)逻辑0和隐形的(recessive)逻辑1,信号每一次传输完后不需要返回到逻辑0(显性)的电平。
位填充规则:发送器只要检测到位流里有5个连续相同值的位,便自动在位流里插入补充位。
状态 |
逻辑信号 |
电压范围 |
显性Dominant |
0 |
|
隐性recessive |
1 |
CAN总线采用的”线与”的规则进行总线冲裁。即1&0=0;所以0为显性。
类型 |
标准 |
最高速率 |
描述 |
高速CAN |
CAN/ISO 11839-2 |
1Mbit/秒 |
最通用的CAN总线类型 |
低速CAN |
ISO/ISO 11839-3 |
125Kbit/秒 |
容错,在一条总线短路的时候仍然能工作 |
单线CAN |
SAE J2411 |
50Kbit/秒 |
高速模式可达到100Kbit/s主要用在汽车上,例如通用公司 |
CAN总线上任意两个节点的最大传输距离与其位速率有关,如下表:
位速率/kbps |
1000 |
500 |
250 |
125 |
100 |
50 |
20 |
10 |
5 |
最大距离/m |
40 |
130 |
270 |
530 |
620 |
1300 |
3300 |
6700 |
10000 |
如果想要更远的传输(大于10公里);可以考虑用多个CAN控制器连接或是加其他通讯协议(如485或是TCP/IP)的接口芯片组成的一个设备,这样就可实现长距离的通讯需求。
只要总线空闲,总线上任何节点都可以发送报文,如果有两个或两个以上的节点开始传送报文,那么就会存在总线访问冲突的可能。但是CAN使用了标识符的逐位仲裁方法可以解决这个问题。
CAN标准定义了四种消息类型,每条消息用一种叫做比特位仲裁(Arbitration)机制来控制进入CAN总线,并且每条消息都标记了优先权。另外CAN标准还定义了一系列的错误处理机制。
- 数据帧:数据帧将数据从发送器传输到接收器。
- 远程帧:总线单元发出远程帧,请求发送具有同一标识符的数据帧。
- 错误帧:任何单元检测到总线错误就发出错误帧。
- 过载帧:过载帧用在相邻数据帧或远程帧之间的提供附加的延时。
CAN总线中有标准帧和扩展帧两种格式,两种格式不同的地方在于仲裁域格式的不同,看下面两个表格可以很清楚的看出两者的不同,下面第一个表是标准帧(CAN2.0 A),第二个为扩展帧(CAN2.0 B):
域 |
描述 |
仲裁域 |
仲裁域决定了当总线上两个或是多个节点争夺总线时的优先权。 |
数据域 |
包含了0到8字节的数据。 |
CRC域 |
包含了15位的校验和,校验和用来做错误检测。 |
应答槽 |
任何一个已经正确接收到消息的控制器在每一条消息的末端发送一个应答位,发送器检查消息是否存在应答位,如果没有就重发消息。 |
作为数据接收器的站,通过发送远程帧,可以启动其资源节点传送它们各自的数据。远程帧和数据帧非常类似,只是远程帧没有数据域。
上图就是远程帧的帧格式,它相对与数据帧没有远程帧,但是要注意发送远程帧的时候RTR位要置1,表示发送的是远程帧。下图更加清晰了呈现了这种结构。
如上图所示错误标志和错误定界符组成,高低代表分别代表隐性和显性,其中错误标志为所有节点发过来的错误标志的叠加(Superposition)。下图更为清楚的看出各个数据位的分布:
- 主动错误标志,它由6个连续的显性位0组成,它是节点主动发送的错误标志。
-
刚才说到一个节点上检测到错误会导致总线上所有的节点都会检测到错误并发送错误标志,这是为什么呢?
因为单一节点上的错误标志格式违背了从帧起始到CRC界定符的位填充规则,也破坏了ACK域或帧结尾的固定格式。下面简要说下位填充规则。
位填充规则:发送器只要检测到位流里有5个连续相同值的位,便自动在位流里插入补充位。
当某个节点发送错误帧(带有错误标志),其他节点收到了错误帧,检测到错误条件,就通过发送”被动错误标志”的错误帧来提示错误。
传送了错误标志以后,每一个站就发送一个隐性位,并一直监视总线直到检测出一个隐性位为止,然后就开始发送其余7个隐性位。
过载帧,意思就是某个接收节点来不及处理数据了,希望其他节点慢点发送数据帧或者远程帧,所以告诉发送节点,我已经没有能力处理你发送过来的数据了。
过载帧跟错误帧结构类似包括过载标志和过载定界符,有3中情况会引起过载:
- 接收器内部的原因,它需要延迟下一个数据帧或是远程帧。
- 在间歇字段(看下面的帧间空间)的第一位和第二位检测到一个显性位(间歇字段都是隐性位的)
- 如果CAN节点在错误界定符或是过载界定符的第八位(最后一位)采样到一个显性位逻辑0,节点会发送一个过载帧,错误计数器不会增加。
上图中很清晰的表示了过载标志有6个显性位组成,而叠加部分和”主动错误”标志一样,过载的标志破坏的是间歇域的固定格式。所以导致其他的节点都检测到过载条件,并一同发出过载标志。
这里所说的针间空间包括”间歇”、”总线空闲”的位域。如果是发送前一报文的”被动错误”的站,则还包括叫做”挂起传输”的位域。
若不是”被动错误”的站,或作为前一报文的接收器的站,帧间空间格式为下图:
若是”被动错误“的站,如果想要发送8个隐性电平,在发送其他帧,帧间空间格式为下图,即包括了挂起传输,
特别的在间歇期间,所有的节点都不允许传送数据帧和远程帧,唯一看做的是标示一个过载条件。
只要总线空闲,任何节点就可以往总线发送数据,并且是开始于间歇之后的第一个位。一旦总线上检测到显性位即逻辑”0”,可以认为是帧的开始。
“被动错误”的节点发送报文之后,在下一个报文开始传送之前或是确认总线空闲之前发出8个隐性位跟随在间歇的后面。如果这个时候有一个报文从其他的节点发过来,则这个节点就成为了接收器。
错误类型 |
出错条件 |
出错域 |
帧测单元 |
|
比特错误 bit error |
发送的位值与所监控的位值不相符合(填充比特和ACK比特除外) |
数据帧(SOF~EOF) |
发送单元 接收单元 |
|
填充错误stuff error |
侦测到6个连续相同的电平 |
数据帧(SOF~CRC) 远程帧(SOF~CRC) |
发送单元 接收单元 |
|
CRC 错误 |
计算结果和接收到的CRC不同 |
数据帧(CRC) 远程帧(CRC) |
接收单元 |
|
格式错误 Form Error |
某个固定的格式位置出现无效的比特 |
数据帧: (CRC Delimiter, ACK Delimiter EOF) 远程帧: (CRC Delimiter,ACK Delimiter) 错误帧: (Error Frame Delimiter) 过载帧: (Overload Delimiter) |
接收单元 |
|
应答错误 Acknowledgment |
发送端在应答间隙所监视的位不为显性,即逻辑0,发送器就检测到一个应答错误。 |
数据帧(ACK slot) 远程帧(ACK slot) |
发送单元 |
错误条件 |
Transmit Error Counter |
Receive Error Counter |
|
1 |
RECEIVER端侦测到一个位Error错误,除了发送ACTIVE ERROR FLAG 和OVERLOAD FLAG |
- |
+1 |
2 |
TRANSMITIER 发送ERROR FLAG |
+8 |
|
3 |
TRANSMITTER发送ACTIVE ERROR FLAG OVERFLAG时侦测到BIT ERROR |
+8 |
|
4 |
当RECEIVER发送ACTIVE ERROR FLAG或OVERFLAG时侦测到BIT ERROR |
+8 |
|
5 |
一个帧被成功发送之后(取得ACK并且知道END OF FRAME完成都没有错误) |
-1 IF TEC=0,TEC will not be changed |
- |
6 |
一个帧被成功接收(知道ACK域都没有检测到错误,并成功发送ACK比特) |
- |
1. if 1 <= REC <= 127 -> REC-1 2. if REC = 0 -> REC = 0 3. if REC > 127 -> REC = a value Between 119 to 127 |
7 |
在总线上检测到128此连续的11个1,”bus off”的节点允许变成不再是”bus off” |
Cleared to TEC = 0 |
Cleared to REC = 0 |
</div>
<div class="postDesc">posted @ <span id="post-date">2017-03-31 00:07</span> <a href="http://www.cnblogs.com/spoorer/">wfjiang</a> 阅读(<span id="post_view_count">1451</span>) 评论(<span id="post_comment_count">0</span>) <a href="https://i.cnblogs.com/EditPosts.aspx?postid=6649303" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(6649303);return false;">收藏</a></div>
</div>
<script type="text/javascript">var allowComments=true,cb_blogId=340509,cb_entryId=6649303,cb_blogApp=currentBlogApp,cb_blogUserGuid='53c6dbe8-7c08-e711-845c-ac853d9f53ac',cb_entryCreatedDate='2017/3/31 0:07:00';loadViewCount(cb_entryId);var cb_postType=1;</script>
</div><!--end: forFlow -->
</div><!--end: mainContent 主体内容容器-->
<div id="sideBar">
<div id="sideBarMain">
<div id="calendar"><div id="blog-calendar" style=""><table id="blogCalendar" class="Cal" title="日历" cellspacing="0" cellpadding="0">
<tbody><tr><td colspan="7"><table class="CalTitle" cellspacing="0">
<tbody><tr><td class="CalNextPrev"><a href="javascript:void(0);" onclick="loadBlogCalendar('2017/10/01');return false;"><</a></td><td align="center">2017年11月</td><td class="CalNextPrev" align="right"><a href="javascript:void(0);" onclick="loadBlogCalendar('2017/12/01');return false;">></a></td></tr>
</tbody></table></td></tr><tr><th class="CalDayHeader" abbr="日" scope="col" align="center">日</th><th class="CalDayHeader" abbr="一" scope="col" align="center">一</th><th class="CalDayHeader" abbr="二" scope="col" align="center">二</th><th class="CalDayHeader" abbr="三" scope="col" align="center">三</th><th class="CalDayHeader" abbr="四" scope="col" align="center">四</th><th class="CalDayHeader" abbr="五" scope="col" align="center">五</th><th class="CalDayHeader" abbr="六" scope="col" align="center">六</th></tr><tr><td class="CalOtherMonthDay" align="center">29</td><td class="CalOtherMonthDay" align="center">30</td><td class="CalOtherMonthDay" align="center">31</td><td align="center">1</td><td align="center">2</td><td align="center">3</td><td class="CalWeekendDay" align="center">4</td></tr><tr><td class="CalWeekendDay" align="center">5</td><td align="center">6</td><td align="center">7</td><td align="center">8</td><td align="center">9</td><td align="center">10</td><td class="CalWeekendDay" align="center">11</td></tr><tr><td class="CalWeekendDay" align="center">12</td><td align="center">13</td><td align="center">14</td><td align="center">15</td><td align="center">16</td><td align="center">17</td><td class="CalWeekendDay" align="center">18</td></tr><tr><td class="CalWeekendDay" align="center">19</td><td align="center">20</td><td class="CalTodayDay" align="center">21</td><td align="center">22</td><td align="center">23</td><td align="center">24</td><td class="CalWeekendDay" align="center">25</td></tr><tr><td class="CalWeekendDay" align="center">26</td><td align="center">27</td><td align="center">28</td><td align="center">29</td><td align="center">30</td><td class="CalOtherMonthDay" align="center">1</td><td class="CalOtherMonthDay" align="center">2</td></tr><tr><td class="CalOtherMonthDay" align="center">3</td><td class="CalOtherMonthDay" align="center">4</td><td class="CalOtherMonthDay" align="center">5</td><td class="CalOtherMonthDay" align="center">6</td><td class="CalOtherMonthDay" align="center">7</td><td class="CalOtherMonthDay" align="center">8</td><td class="CalOtherMonthDay" align="center">9</td></tr>
<div id="leftcontentcontainer">
<div id="blog-sidecolumn"><div id="sidebar_search" class="sidebar-block">
搜索
我的标签
最新评论
评论排行榜
推荐排行榜
</div><!--end: sideBarMain -->
</div><!--end: sideBar 侧边栏容器 -->
<div class="clear"></div>
</div><!--end: main -->
<div class="clear"></div>
<div id="footer">
Copyright ©2017 wfjiang
@requires_authorization
def somefunc(param1='', param2=0):
'''A docstring'''
if param1 > param2: # interesting
print 'Greater'
return (param2 - param1 + 1) or None
class SomeClass:
pass
>>> message = '''interpreter
... prompt'''
脚注
生成一个脚注1.
目录
用 [TOC]
来生成目录:
数学公式
使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com.
- 行内公式,数学公式为:
Γ(n)=(n−1)!∀n∈ℕ 。 - 块级公式:
更多LaTex语法请参考 这儿.
UML 图:
可以渲染序列图:
或者流程图:
离线写博客
即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。
用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。
博客发表后,本地缓存将被删除。
用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。
注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱。
浏览器兼容
- 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。
- IE9以下不支持
- IE9,10,11存在以下问题
- 不支持离线功能
- IE9不支持文件导入导出
- IE10不支持拖拽文件导入
- 这里是 脚注 的 内容. ↩
【推荐】Vue.js 2.x 快速入门,大量高效实战示例
【活动】腾讯云 学生专属优惠套餐 多规格选择
· 沃尔沃宣布与Uber达成框架协议,「自动驾驶」的专车离我们不远了
· Realm发布Realm.NET,扩展支持.NET技术栈
· 一款办公室版的“吃鸡”游戏,却在Reddit斩获了10万点赞
· Tim Berners-Lee 谈论网络未来:狂风呼啸而来,系统正在失效
· A站十年,它是如何把一手好牌打烂的?
» 更多新闻…
· 关于编程,你的练习是不是有效的?
· 改善程序员生活质量的 3+10 习惯
· NASA的10条代码编写原则
· 为什么你参加了那么多培训,却依然表现平平?