CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO*1 国际标准化的串行通信协议。CAN 通过 ISO11898 及 ISO11519 进行了标准化,现在在欧洲已是汽车网络的标准协议。现在,CAN 的高性能和可靠性已被认同,并被广泛地应用于汽车电子、工业自动化、船舶、医疗设备、工业设备等方面。
从CAN总线拓扑图中可以知道, CAN 控制器根据两根线上的电位差来判断总线电平。总线电平分为显性电平(0)和隐性电平(1),二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。
![](https://img-blog.csdnimg.cn/14053a0c4b4b4c09931b5378b96e6d38.png)
图1 CAN总线拓扑图
CAN 协议特点
(1) 多主控制: 在总线空闲时,所有的单元都可开始发送消息(多主控制)。 最先访问总线的单元可获得发送权(CSMA/CA 方式)。 多个单元同时开始发送时,发送高优先级 ID 消息的单元可获得发送权。
(2) 消息的发送: 在串口通信协议中,数据的收发是没有固定的数据格式的,而在 CAN 协议中,所有的消息都以固定的格式发送。总线空闲时,所有与总线相连的单元都可以开始发送新 消息。两个以上的单元同时开始发送消息时,根据标识符(Identifier 以下称为 ID)决定优先级。与IIC总线协议不同,ID 并不是表示发送的目的地址(设备地址),而是表示访问总线的消息的优先级。两个以上的单元同时开始发送消息时,对各消息ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。
(3) 系统的柔软性: 与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬 件及应用层都不需要改变。
(4) 通信速度: 根据整个网络的规模,可设定适合的通信速度。 在同一网络中,所有单元必须设定成统一的通信速度。即使有一个单元的通信速度与其它的不一样,此单元也会输出错误信号,妨碍整个网络的通信。不同网络间则可以有不同的通信速度。
(5) 远程数据请求: 可通过发送“遥控帧” 请求其他单元发送数据。
(6) 错误检测功能:错误通知功能·错误恢复功能 所有的单元都可以检测错误(错误检测功能)。 检测出错误的单元会立即同时通知其他所有单元(错误通知功能)。 正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送 此消息直到成功发送为止(错误恢复功能)。
(7) 故障封闭: CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部 故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上 隔离出去。
(8) 连接:CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。
ISO 标准化的 CAN 协议
CAN 协议经 ISO 标准化后有 ISO11898 标准和 ISO11519-2 标准两种。ISO11898 和 ISO11519-2 标准对于数据 链路层的定义相同,但物理层不同。
(1) 关于 ISO11898 ISO11898 是通信速度为 125kbps-1Mbps 的 CAN 高速通信标准。 目前,ISO11898 追加新规约后,成为 ISO11898-1 新标准。
(2) 关于 ISO11519 ISO11519 是通信速度为 125kbps 以下的 CAN 低速通信标准。 ISO11519-2 是 ISO11519-1 追加新规约后的版本。
![](https://img-blog.csdnimg.cn/4bbd19b9a1084bb2b34d7f7110370f5b.png)
CAN 收发器根据两根总线(CAN_High 和 CAN_Low)的电位差来判断总线电平。 总线电平分为显性电平和隐性电平两种。总线必须处于两种电平之一。总线上执行逻辑上的线“与”时, 显性电平为“0”,隐性电平为“1”。
![](https://img-blog.csdnimg.cn/aea95d6fb67042c7b018705409c92aa2.png)
以TJA1050收发器芯片数据手册为例:
![](https://img-blog.csdnimg.cn/b0e93f01dc8640d78e86a5f5a914dfc1.png)
![](https://img-blog.csdnimg.cn/9a7524b9f3b141f4ad05337386ccb9dc.png)
TJA1050 采用的是ISO11898标准, 总线电平=CAN_H的电压-CAN_L的电压,由数据手册可以看出,当电平在-1v-0.5v之间是隐性,电平在0.9-5v之间是显性。 显性电平对应逻辑0=总线电平为2V左右 隐性电平对应逻辑1=总线电平为0V。 显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。 隐形电平则具有包容的意味,只有所有的单元都输出隐性电平, 总线上才为隐性电平(显性电平比隐性电平更强)。 在CAN总线的起止端都有一个120Ω的终端电阻,来做阻抗匹配,以减少回波反射,增加总线通信的稳定性。
通信波特率:CAN总线是基于相同波特率通信的,在同一网络中,所有单元必须设定成统一的通信速度,否则就会输出错误信号妨碍整个网络的通信。因此在设备接入总线之前就要先知道总线波特率是多少。计算公式参考:波特率=(pclk1/((1+8+7)*9)) = 36Mhz/16/9 = 250Kbits
设置低速AHB时钟(PCLK1),APB1时钟 = HCLK/2 = 36MHZ(外部晶振8HMZ)
设置高速AHB时钟(PCLK2),APB2时钟 = HCLK = 72MHZ(外部晶振8HMZ)
因为CAN总线挂载在APB1时钟上,所以pclk1=36Mhz。
![](https://img-blog.csdnimg.cn/22186637388d4a2685e2f54d4f732318.png)
CAN协议
CAN总线发送部分:
报文:CAN设备一次发送出去的完整数据信息
邮箱:用于发送报文的发送调度器
帧种类:不同用途的报文种类。有数据帧、遥控帧、错误帧、过载帧、帧间隔
帧格式:一个报文里包含的内容。
标识符(ID):CAN总线上的设备可以用此判断数据是不是发给自己的
其中邮箱集成在CAN控制器中,有3个邮箱,当向程序向CAN控制器发数据时,CAN会选择优级级最高的空邮箱放入数据,如果所有邮箱都满了,会使溢出标志位置1,需要等待有空邮箱,满邮箱把先后顺序排队发送数据,发送完成后会变成空邮箱。
帧种类:
我们都知道,USART串口收发的都是没有格式的单纯数据,如果想用USART做高级应用,那么需要自定义数据格式。而在CAN总线中的报文是由格式的。
![](https://img-blog.csdnimg.cn/8fd83662a0604718853051693db7b37c.png)
CAN中的所有设备都会接收报文,但标识符(ID)不符的报文会被过滤器删除
![](https://img-blog.csdnimg.cn/073ef18811214be2ad3967f4ec777ba3.png)
每种报文的格式都不相同, 数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有 11 个位的标识符(Identifier: 以下称 ID), 扩展格式有 29 个位的 ID。
数据帧或遥控帧报文格式:
![](https://img-blog.csdnimg.cn/ce351b77bace4311bd79e5af33c72610.png)
数据帧:
![](https://img-blog.csdnimg.cn/0307c13332104dfa82f11cfbab3bf6cc.png)
遥控帧:
![](https://img-blog.csdnimg.cn/89f6bc853cf0465ab7ff3be7f630a63c.png)
数据帧和遥控帧的不同 : 遥控帧的 RTR 位为隐性位,没有数据段。没有数据段的数据帧和遥控帧可通过 RTR 位区别开来。
![](https://img-blog.csdnimg.cn/234cfbeb156e4408866bb9a177a69047.png)
优先级的决定:
在总线空闲态,最先开始发送消息的单元获得发送权。 多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送。
![](https://img-blog.csdnimg.cn/43c78c9f7eab40c1944078fd40d79891.png)
仲裁过程
数据帧和遥控帧的仲裁过程:
具有相同 ID 的数据帧和遥控帧在总线上竞争时,仲裁段的最后一位(RTR)为显性位的数据帧具有优先权, 可继续发送
标准格式和扩展格式的仲裁过程:
![](https://img-blog.csdnimg.cn/2e23479e58cc472190570e9efda08644.png)
在STM32中bxCAN特点:
1、CAN接口兼容规范2.0A和2.0B主动模式
2、波特率(位速率)最高可达1Mb/S
3、接受和发送11位标识符的数据帧或29位标识符的扩展帧
4、具有3个发送邮箱
5、3级深度的2个接受FIFO,3级14个可调节过滤器
FIFO:即先入先出,此指的是有层级深度的接受邮箱。STM32F103系列单片机上有2个FIFO邮箱,每个FIFO有3层深度。 与过滤器匹配的报文会被放入FIFO邮箱。
![](https://img-blog.csdnimg.cn/1a0183532eb047a6a122cc662d2135ec.png)
CAN接收有2个邮箱,FIFO0和FIFO1,每个邮箱有3层深度。 3层深度是指每个邮箱可以接收3个报文,但读取时只能读到最先收到的报文 报文处理完成后,再读取时则是下一个报文。
过滤器:可由硬件判断报文中的标识符,过滤掉标识符不匹配的报文。 STM32F103系列单片机中的CAN总线控制器提供了14个过滤器组。 过滤器是由硬件实现的,只有与过滤器匹配的报文才需要软件处理。
在接受数据的时候,第一个问题就是搞懂如何接受的———过滤。
![](https://img-blog.csdnimg.cn/485568c1a17d4f5186c4a9dd54e21304.png)
过滤器组中的模式设置分为32位模式下的标识符屏蔽和标识符列表,16位模式下的标识符屏蔽和标识符列表。在 16 位模式下,只不过把两个 32 位寄存器拆成了 4 个 16 位的而已,原理和 32 位模式下是一 样的。
标识符列表模式:(这里仅用8位数据举例,实际的过滤器为16位或32位的)
![](https://img-blog.csdnimg.cn/a5ba230ca44a4457948af6f574c87830.png)
这里所说的ID并不是发送数据帧里面的 ID,这两个没有什么关系的,这 里的 ID 是根据自己的实际需要设置的。
标识符屏蔽模式:(这里仅用8位数据举例,实际的过滤器为16位或32位的)
![](https://img-blog.csdnimg.cn/baf8ee977f8e419689b03130ce0e5ab0.png)
因此这里的屏蔽和 ID 共同配合完成过滤。
![](https://img-blog.csdnimg.cn/cf81b86e020f4b3289ba446dd9c802d6.png)
![](https://img-blog.csdnimg.cn/ace1c8f1e071484f85cfd20958a7c21f.png)
过滤器根据下列优先级规则来确定:
1、位宽为32位的过滤器,优先级高于位宽为16位的过滤器
2、对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式
3、位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高
过滤器初始化函数:
u8 CAN_FilterConfiguration(viod){
//设置过滤器
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位宽
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;//屏蔽值都为0,代表任何数据都可以通过过滤器
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0
CAN_FilterInit(&CAN_FilterInitStructure); //滤波器初始化
}
发送和接收函数:
typedef struct
{
uint32_t StdId; //标准帧 ID,如果您要发送扩展帧。可以不管它
uint32_t ExtId; //扩展帧 ID,如果您要发送标准帧。可以不管它
uint8_t IDE; //您是想发送标准帧还是扩展帧?
uint8_t RTR; //您是想发送数据帧还是远程帧?
uint8_t DLC; // 您想发送数据的长度。
uint8_t Data[8]; //您想要发送的数据。
} CanTxMsg;
typedef struct
{
uint32_t StdId;
uint32_t ExtId;
uint8_t IDE;
uint8_t RTR;
uint8_t DLC;
uint8_t Data[8];
uint8_t FMI;//FMI域
} CanRxMsg;
//CAN发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//msg:数据指针,最大为8个字节,len:数据长度(最大为8)
//返回值:0,成功; 其他,失败;
u8 CAN_Send_Msg(u8* msg,u8 len){
u8 mbox;
u16 i=0;
CanTxMsg TxMessage;
TxMessage.StdId=0x12; // 标准标识符
TxMessage.ExtId=0x00; // 设置扩展标识符
TxMessage.IDE=CAN_Id_Standard; // 标准帧
TxMessage.RTR=CAN_RTR_Data; // 数据帧
TxMessage.DLC=len; // 要发送的数据长度
for(i=0;i<len;i++)
TxMessage.Data[i]=msg[i]; //写入数据
mbox= CAN_Transmit(CAN1,&TxMessage);
i=0;
while((CAN_TransmitStatus(CAN1,mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束
if(i>=0XFFF)return 1;
return 0;
}
//can口接收数据查询
//buf:数据缓存区;
//返回值:0,无数据被收到,其他,接收的数据长度;
u8 CAN_Receive_Msg(u8 *buf){
u32 i;
CanRxMsg RxMessage;
if(CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;//没有接收到数据,直接退出
CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);//读取数据
for(i=0;i<8;i++) //把8个数据放入参数数组
buf[i]=RxMessage.Data[i];
return RxMessage.DLC; //返回数据数量
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)