协议规定
差分信号
差值为0为逻辑1(隐性电平)
差值不为0为逻辑1(显性电平) (具体差值范围多少和高速\低速CAN协议有关)
可记为电平拉开为0, 闭合为1
异步半双工
帧格式
数据帧 遥控帧 错误帧 过载帧 帧间隔
EOF之后仍需3位显性电平的帧间隔才能进入下一个通信
位填充机制:兼容错误帧和过载帧 避免错位和防止被误认为是空闲
位同步
通过引入位时序
解决时序起始位不同步->硬同步
解决时序传输过程中的偏差->再同步
can总线中码元指的是一个位时序, 波特率也因此由一个位时序所需时间决定
仲裁
连续11个隐形电平->空闲状态
两种仲裁机制护航:
- 先到先得 只有当检测到空闲状态的情况下才尝试发送数据
- 通过仲裁段进行仲裁
ID + RTR 作为仲裁段
线与特性: can总线拉开代表显性0, 当多个主机中任一主机拉开总线时 总线代表显性0 当所有主机都释放总线时 总线才代表隐性1
回读机制: 每个主机在发送数据后都会读取总线的状态
根据上述两个机制得到仲裁的特性
当主机发出隐性1但是读回的确实显性0时, 说明当前有主机正在使用该主线发送数据 但是发送0的这个主机却不知道有另一个主机正在使用这条主线
这时发送1的主机仲裁失败, 回到读取状态
这也决定了总是发送ID号小的帧的数据仲裁会成功
Q: 位填充是否会影响到仲裁?
A: 结论是不会, 假设位填充会影响到仲裁 那么位填充之前的位均为一样的, 这种情况显然不会影响,因为填充的那位也是相同的 如果位填充之前的位都不一样, 那更不可能了 如果只有一个主机产生位填充 那很明显前面5位绝不相同, 这点也毋庸置疑
那么两个主机发送同一个ID号的数据帧和遥控帧的情况呢
数据帧的RTR位为0, 遥控帧的RTR位为1
发送遥控帧的主机会仲裁失败
回到实际意义来讲, 发送遥控帧的主机获得的数据永远是最新的, 不会导致数据不同步的错误情况, 这点是符合实际项目要求的
那么拓展格式的情况呢
同样分标准数据帧和标准遥控帧来讨论, 拓展格式中数据帧和遥控帧和上面讨论情况相同
先说标准数据帧
拓展格式的SRR位(对应的就是标准格式的RTR位)为隐性1, 所以面对标准数据帧, 拓展格式是仲裁失利的
那么标准遥控帧呢
遥控帧的RTR位为1, 同时仲裁段也只是ID + RTR 这一段
那么遥控帧就有了必胜的理由,那么我们接着看
RTR位紧跟着的就是IDE位, 拓展格式的这一位规定置为隐性1, 所以必定会仲裁失败
这里和前面帧格式为什么要这么定义形成逻辑闭环
错误处理
5种错误: 位错误(回读), 填充错误, CRC错误, 格式错误(各种界定符错误), ACK错误
错误状态机制与TEC(Transmit Error Counter), REC
TEC和REC并不总是每次-1, 很大可能是一次-8, 但需要8次正确传输才能补救回来

Q: 为什么结束的EOF要给7个隐性1
A: 一是7个隐性1 + ACK界定符(一位) + 3位帧间隔 刚好11位隐性1, 这之后满足进入空闲状态的要求
二是留给错误处理置错误标志一段时间, 避免接收方还未意识到发送的数据错了就已经进入下一帧了
Q: 在哪个区段里会产生位填充现象
SOF到CRC校验之间的数据
Q: 延迟传送的作用
其中一个作用是使其处于仲裁失利, 避免易出错的设备优先去发送数据占用总线资源
位屏蔽机制
1 | //32位屏蔽#2 |
中断
| 中断宏 | 含义 | 触发时机 |
|---|---|---|
| CAN_IT_TME | 发送邮箱空 | 可以发送下一帧 |
| CAN_IT_FMP0 | FIFO0 有消息 | 接收到数据 |
| CAN_IT_FF0 | FIFO0 满 | 3 条消息满了 |
| CAN_IT_FOV0 | FIFO0 溢出 | 数据覆盖 |
| CAN_IT_FMP1 | FIFO1 有消息 | 接收到数据 |
| CAN_IT_FF1 | FIFO1 满 | |
| CAN_IT_FOV1 | FIFO1 溢出 | |
| CAN_IT_EWG | 错误警告 | 错误计数 > 96 |
| CAN_IT_EPV | 错误被动 | 错误计数 >= 128 |
| CAN_IT_LEC | 最后错误码变化 | 出现新的错误 |
| CAN_IT_ERR | 任意错误事件 | CRC/ACK/stuff 等错误 |
| CAN_IT_WKU | 唤醒 | 从 sleep→正常模式 |
| CAN_IT_SLK | 睡眠完成 |