在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统
被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很
多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个 LAN,进行大量数据的高速通信”的需
要,1986 年德国电气商博世公司开发出面向汽车的 CAN 通信协议。此后,CAN 通过 ISO11898 及 ISO11519 进
行了标准化,现在在欧洲已是汽车网络的标准协议。
现在,CAN 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设备、工业设备等方面。
图 1 是车载网络的构想示意图。CAN 等通信协议的开发,使多种 LAN 通过网关进行数据交换得以实现。
1) 多主控制。
在总线空闲时,所有的单元都可以开始发送消息(多主控制)。
最先访问总线的单元可获得发送权。
多个单元同时发送时,发送高优先级 ID 消息的单元可获得发送权。
2) 消息的发送
在 CAN 协议中,所有的消息都以固定的格式发送。总线空闲时,所有与总线相连的单元都可以
开始发送新的消息。两个以上的单元同时发送消息是,根据标示符(Identifier 以下称 ID)决定
优先级。ID 并不是发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时
开始发送消息时,对各消息 ID 的每个位进行逐个仲裁。仲裁获胜(被判定为高优先级)的单元
可继续发送消息,仲裁失利的单元则立刻停止发送而转为接收模式。
3) 系统的柔软性
与总线相连的单元没有类似于“地址”的信息,因此在总线上增加单元时,连接在总线上的其他单
元的软硬件及应用层都不需要改变。
4) 通信速度
根据网络的规模,可设置合适的通信速度。在同一网络中,所有单元必须设置统一的通信速度。
5) 远程数据请求
任意单元都可以发送“遥控帧”来请求其他单元发出数据。
6) 错误检测功能—错误通知功能—错误恢复功能
所有单元都可检测错误(检测功能)。 检测出错的单元会立即通知其他所有单元(错误通知功能)。
发送出错的单元,会立即停止当前发送,并不断重新发送此消息,直到发送成功为止(错误恢复
功能)。
7) 故障封闭
CAN 可以判断出错误的类型是总线上暂时的错误(如外部噪声等)还是持续的数据错误(如单
元内部的故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此
故障的单元从总线上隔离出去。
8) 连接
CAN 总线是可以同时连接多个单元的总线。可连接的单元总数理论上是没有限制的,但实际上
可连接的单元数受总线上的时间延迟及电气负载的限制,降低通信速度,可连接的单元数增加;
提高通信速度,则可连接的单元数减少。
OSI(Open System Interconnect),即开放式系统互联。 一般都叫 OSI 参考模型,是 ISO(国际标准化组织)
总线上的电平有显性电平和隐性电平两种。 总线上执行逻辑上的线“与”时,显性电平的逻辑值为“0”,隐性电平为“1”。 “显性”具有“优先”的意味,只要有一个单元输出显性电平,总线上即为显性电平。并且,“隐 性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。(显性电平比 隐性电平更强。)
(2) 仲裁段
【注】 *1 ID 标准格式的 ID 有 11 个位。从 ID28 到 ID18 被依次发送。禁止高 7 位都为隐性。 (禁止设定:ID=1111111XXXX) 扩展格式的 ID 有 29 个位。基本 ID 从 ID28 到 ID18,扩展 ID 由 ID17 到 ID0 表示。基本 ID 和 标准格式的 ID 相同。禁止高 7 位都为隐性。(禁止设定:基本 ID=1111111XXXX
【注】 *1 保留位(r0、r1) 保留位必须全部以显性电平发送。但接收方可以接收显性、隐性及其任意组合的电平。 *2 数据长度码(DLC) 数据长度码与数据的字节数的对应关系如表 8 所示。 数据的字节数必须为 0~8 字节。但接收方对 DLC = 9~15 的情况并不视为错误。 表 8. 数据长度码和字节数的关系 数据长度码 数据字节数 DLC3 DLC2 DLC1 DLC0 0 D D D D 1 D D D R 2 D D R D 3 D D R R 4 D R D D 5 D R D R 6 D R R D 7 D R R R 8 R D D D “D”:显性电平 “R”:隐性电平
*1 CRC 顺序 CRC 顺序是根据多项式生成的 CRC 值,CRC 的计算范围包括帧起始、仲裁段、控制段、数据 段。 接收方以同样的算法计算 CRC 值并进行比较,不一致时会通报错误。
发送 ACK 发送 ACK 的是在既不处于总线关闭态也不处于休眠态的所有接收单元中,接收到正常消息的单元(发送单元不发送 ACK)。所谓正常消息是指不含填充错误、格式错误、CRC 错误的消息。 【注】 *1 发送单元的 ACK 段 发送单元在 ACK 段发送 2 个位的隐性位。 *2 接收单元的 ACK 段 接收到正确消息的单元在 ACK 槽(ACK Slot)发送显性位,通知发送单元正常接收结束。这称作“发 送 ACK”或者“返回 ACK”
8.3 遥控帧 接收单元向发送单元请求发送数据所用的帧。遥控帧由 6 个段组成。遥控帧没有数据帧的数据段。 遥控帧的构成如图 24 所示。 (1) 帧起始(SOF) 表示帧开始的段。 (2) 仲裁段 表示该帧优先级的段。可请求具有相同 ID 的数据帧。 (3) 控制段 表示数据的字节数及保留位的段。 (4) CRC 段 检查帧的传输错误的段。 (5) ACK 段 表示确认正常接收的段。 (6) 帧结束 表示遥控帧结束的段。
• 数据帧和遥控帧的不同
遥控帧的 RTR 位为隐性位,没有数据段。
没有数据段的数据帧和遥控帧可通过 RTR 位区别开来。
• 遥控帧没有数据段,数据长度码该如何表示?
遥控帧的数据长度码以所请求数据帧的数据长度码表示。
• 没有数据段的数据帧有何用途?
例如,可用于各单元的定期连接确认/应答、或仲裁段本身带有实质性信息的情况下。
8.4 错误帧 用于在接收和发送消息时检测出错误通知错误的帧。错误帧由错误标志和错误界定符构成。 错误帧的构成如图 25 所示。 (1) 错误标志 错误标志包括主动错误标志和被动错误标志两种。 主动错误标志:6 个位的显性位。 被动错误标志:6 个位的隐性位。 (2) 错误界定符 错误界定符由 8 个位的隐性位构成。
8.5 过载帧 过载帧是用于接收单元通知其尚未完成接收准备的帧。过载帧由过载标志和过载界定符构成。 过载帧的构成如图 26 所示。 (1) 过载标志 6 个位的显性位。 过载标志的构成与主动错误标志的构成相同。 (2) 过载界定符 8 个位的隐性位。 过载界定符的构成与错误界定符的构成相同。 8.6 帧间隔 帧间隔是用于分隔数据帧和遥控帧的帧。数据帧和遥控帧可通过插入帧间隔将本帧与前面的任何帧(数据帧、 遥控帧、错误帧、过载帧)分开。 过载帧和错误帧前不能插入帧间隔。 帧间隔的构成如图 27 所示。 (1) 间隔 3 个位的隐性位。 (2) 总线空闲 隐性电平,无长度限制(0 亦可)。 本状态下,可视为总线空闲,要发送的单元可开始访问总线。 (3) 延迟传送(发送暂时停止) 8 个位的隐性位。 只在处于被动错误状态的单元刚发送一个消息后的帧间隔中包含的段。
/* 函数功能:初始化CAN1 函数形参:brp:分频器;tbs1:时间段1;tbs2:时间段2;tsjw:同步跳转;mode:模式 */ u8 init_can1(u8 brp, u8 tbs1, u8 tbs2, u8 tsjw, u8 mode) { u16 cnt=0; RCC->AHB1ENR|=1<<0; //使能PORTA口时钟 GPIOA->MODER &= ~(3<<22); GPIOA->MODER |= (2<<22); //PA11 复用功能 GPIOA->MODER &= ~(3<<24); GPIOA->MODER |= (2<<24); //PA12 复用功能 GPIOA->OTYPER &= ~(3 << 11);//类型 推挽 GPIOA->OSPEEDR &= ~(0xf<< 22);//速度 50M GPIOA->OSPEEDR |= 0xa << 22; GPIOA->AFR[1] &= ~(0XF << 12); GPIOA->AFR[1] |= 9 << 12; //PA11 can1功能 AF9 GPIOA->AFR[1] &= ~(0XF << 16); GPIOA->AFR[1] |= 9 << 16; //PA12 can1功能 AF9 RCC->APB1ENR |= 1<<25;//使能CAN1时钟 CAN1使用的是APB1的时钟(max:42M) CAN1->MCR = 0; //退出睡眠模式(同时设置所有位为0) /* 非时间触发通信模式 软件自动离线管理 睡眠模式通过软件唤醒(清除CAN1->MCR的SLEEP位) 报文不锁定,新的覆盖旧的 优先级由报文标识符决定 */ CAN1->MCR |= 1<<0; //请求CAN进入初始化模式 while ((CAN1->MSR & 1 << 0) == 0) { if (++cnt > 100) { return 2; //进入初始化模式失败----超时监测 } } CAN1->MCR |= 1<<16; CAN1->MCR |= 1<<6; CAN1->MCR |= 1<<5; CAN1->MCR |= 1<<4; //禁止报文自动重发 CAN1->BTR = 0; //清除原来的设置. CAN1->BTR |= mode<<30; //模式设置 0,工作模式;1,回环模式; CAN1->BTR |= (tsjw - 1) << 24; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN1->BTR |= (tbs2 - 1) << 20; //Tbs2=tbs2+1个时间单位 CAN1->BTR |= (tbs1 - 1) << 16; //Tbs1=tbs1+1个时间单位 CAN1->BTR |= (brp - 1) ; //分频系数(Fdiv)为brp+1 //波特率:Fpclk1/((Tbs1+Tbs2+1)*Fdiv) CAN1->MCR &= ~(1<<0); //请求CAN退出初始化模式 while ((CAN1->MSR & 1<<0) == 1) { if (++cnt > 0XFFF0) { return 3;//退出初始化模式失败 } } //过滤器初始化 CAN1->FMR |= 1<<0; //过滤器组工作在初始化模式 CAN1->FA1R &= ~(1<<0); //过滤器0先关闭 CAN1->FS1R |= 1<<0; //过滤器0位宽为32位. CAN1->FM1R &= ~1; //过滤器0工作在标识符屏蔽位模式 CAN1->FFA1R &= ~1; //过滤器0关联到FIFO_0 CAN1->sFilterRegister[0].FR1 = 0;//32位ID CAN1->sFilterRegister[0].FR2 = 0;//32位MASK //任何一个ID都可以进来 CAN1->FA1R |= 1<<0; //激活过滤器0 CAN1->FMR &= ~1; //过滤器组进入正常模式 return 0; }