帧结构
帧起始与帧结束:用于界定一个数据帧
仲裁段:通过仲裁段的ID来确定数据帧的优先级。RTR为远程帧标识位,为显性。
控制段:IDE为识别符扩展位。
数据段:存储64位数据。
CRC段:为校验数据和检验设备,提高安全性。
特点
1、实时性强、传输距离较远、可在高噪声干扰环境中工作,抗电磁干扰能力强、成本低等优点;
2、物理接口电平具有优先权和仲裁功能
3、发送的信息遭到破坏后,可自动重发
4、CRC校验
5、Payload 部分最长 8 个字节
6、位填充编码
类型
CAN总线分为高速CAN(500kbit/s 到 1Mbit/s,不过也可以低于 500kbit/s)和低速CAN(100kbit/s)。
以高速 CAN 为例,引入一个显隐电平的概念:
显性电平:逻辑 0(CANH-CANL 差分电压为正)
隐形电平:逻辑 1(CANH-CANL 差分电压为 0)
CAN 总线上,“显性”的优先级要高于“隐性”;当“显性”位和“隐性”位同时发送到总线上时,总线上
的数值表现为“显性”。
可以理解为:
逻辑 1-->“隐性”,总线处于高阻,任何一个 CAN 节点都可以将总线驱动成“显性”。
逻辑 0-->“显性”,在总线上的电平优先级要高于“隐性”
CAN通信特点
无主从之分
总线中的每个节点没有主从之分,因为大家都处在相等的地位。因此,当总线空闲状态,所有结点都可以直接向总线上发出消息。
最先向总线上发出消息的节点就得到了总线的传输授权。
当几个节点一起传送报文后,被传送的报文的优先级最高的那个节点得到总线的传输权限。
总线空闲状态:如果总线通道上存在连续的十一个隐性电平,则总线通道将处在闲置状态。也就是说对任意结点来说,如果它已经监听到了总线通道上的存在十一个隐性电平,那么这个结点就会觉得总线通道当前处在空闲状态,也就会立刻向总线通道上发出自己的报文。
非破坏性位仲裁机制
在CAN协议中,所有的消息均以固定帧格式传输。当几个节点在一起向总线上传送消息时,对各个消息的ID值进行逐位仲裁,一旦一个节点发出的的消息仲裁胜利了,则这个节点就获得了总线的传输权利,而仲裁失利的节点则将马上中止传输,或转换为监听状态。
这个仲裁机制既没有产生新发送数据的时间,又没有损坏新收到的信息,故而又称为无破坏性仲裁机制。
系统的柔性
CAN总线上的所有节点都没有"地址"的定义,所以当在总线上增加节点时,并不能对总线上所有现存节点的软硬件网络和运行层产生影响。地址存放在消息之内,节点通过消息的ID来决定是否是自己想要的消息。
通信速度
在同一段CAN通讯链路上,每个节点的通讯速率(位速率)应该一致,如2个不同通讯速率上的节点为了进行消息通讯,需要使用网关。
数据传输方式
CAN总线上能够完成一对一,一对多以及广播的信息传输方式,依赖于验收滤波技术。
错误检测、错误通知、错误恢复功能
错误检测:每个节点都能够检查出错误。
错误通知:检测出错误的节点会立刻通知总线上其他所有节点。
错误恢复:正在发送消息的节点,一旦侦测到出错,会马上暂停发送,并于同一时间持续地再次发送此消息,直至该消息发送完成为止。
故障封闭
节点可以确定出错的类型,确定是暂时的数据出错或者连续性的数据出错,一旦确定是严重的持续性出错,则节点会断开自身与总线的联系,以此防止干扰总线上其他节点的正常运作。
CAN网络层次及定义事项
CAN总线的网络底层只采用了网络参照模式的数据链路层和物理层,CAN总线中对每一级网络的定义事项:
网络结构 | 具体实现 | 结构定义 | 具体事项 |
数据链路层 | 逻辑链路控制LLC | 接收过滤 | 点到点、组播、广播。 |
过载通知 | 通知“接收准备尚未完成”。 | ||
错误恢复 | 再次发送。 | ||
媒介访问控制MAC | 数据打包/解包 | 数据帧、远程帧、错误帧、过载帧和帧间隔。 | |
连接控制方式 | 竞争方式,支持多点传送。 | ||
仲裁方式 | 位仲裁方式,优先级高的ID可以继续被发送。 | ||
故障扩散抑制 | 自动判定暂时性错误或持续性错误,并切断持续性错误节点与总线之间的联系。 | ||
错误通知 | CRC错误、位填充错误、位错误、ACK错误、格式错误 | ||
错误检测 | 所有节点均可以随时检测出错误 | ||
应答方式 | ACK应答、DACK应答。 | ||
通信方式 | 半双工通信,串行通信。 | ||
物理层 | 物理信令子层PLS | 位编码/解码方式 | NRZ方式编码,位填充。 |
物理介质连接PMD | 位时序 | 位时序、位的采样数。 | |
介质相关接收MDI | 同步方式 | 根据同步段实现同步。 |
CAN总线状态
主动错误状态、被动错误状态、总线关闭状态这三种状态根据发送和接收的错误计数进行改变:
主动错误状态:保持在该状态的节点,能够不受任何影响的收到报文和主动错误帧。
被动错误状态:处在被动出错状态下的节点,只能发出报文或者被动错误帧。
总线关闭状态:处于该状态的节点暂时无法实现与总线之间的通讯。这一状态下,既无法发出报文,也无法收到报文。只有发送器可以进入总线关闭状态。
基于rt1064的CAN回环实现
demo
发送函数
__NO_RETURN static void CAN_Thread (void *arg) {
int i;
char a[64]="jhgjfytffdshfdshfohfoewfsds";
char *b = NULL;
(void)arg;
memset(&tx_msg_info, 0U, sizeof(ARM_CAN_MSG_INFO)); // Clear message info structure
tx_msg_info.id = ARM_CAN_EXTENDED_ID(0x12345678U); // Set extended ID for transmit message
i = 0;
b = a;
while (1) {
i++;
if(*(b+8) == '\0' || *(b+8) == NULL)
{
i = 0;
}
memcpy (tx_data, b, CAN_DATA_LEN); // Fill transmit buffer
b = a + 8*i;
// Send data message
ptrCAN->MessageSend(tx_obj_idx, &tx_msg_info, tx_data, CAN_DATA_LEN);
osDelay(1000U);
}
}
效果
流程
1、消息发送
2、存入寄存器
3、从寄存器中读取数据
4、tx->rx
5、下一个
can初始化流程
ARM_CAN_CAPABILITIES can_cap;
ARM_CAN_OBJ_CAPABILITIES can_obj_cap;
int32_t status;
uint32_t i, num_objects, clock;
can_cap = ptrCAN->GetCapabilities (); //获取CAN状态
num_objects = can_cap.num_objects; //对象收发的数量
status = ptrCAN->Initialize (CAN_SignalUnitEvent, CAN_SignalObjectEvent); // 初始化CAN收发器
if (status != ARM_DRIVER_OK) { return false; }
status = ptrCAN->PowerControl (ARM_POWER_FULL); // 给CAN控制器上电
if (status != ARM_DRIVER_OK) { return false; }
status = ptrCAN->SetMode (ARM_CAN_MODE_INITIALIZATION); //进入初始化模式
if (status != ARM_DRIVER_OK) { return false; }
clock = ptrCAN->GetClock(); // 获取CAN外部时钟