1. CAN协议基础回顾:从帧结构到CMS32外设特性
各位同学,咱们今天正式开讲。CAN协议这东西,说实话,搞嵌入式的人迟早都得碰。我最早接触CAN是在做汽车BCM项目的时候,那时候被总线上的波形折腾得够呛。后来慢慢摸透了它的脾气,才发现CAN的设计其实非常巧妙。
这一节,咱们先打好地基。把CAN 2.0A/B的帧结构、仲裁机制、位填充和CRC校验这些核心概念过一遍,最后再看看CMS32的CAN模块长什么样。
1.1 CAN 2.0A/B帧结构:标准帧与扩展帧
CAN总线上的报文,说白了就是一串电平跳变。但这一串跳变里,藏着严格的分段结构。CAN 2.0A定义的是标准帧,11位标识符;CAN 2.0B扩展帧,29位标识符。两者在总线上是完全兼容的,但帧格式有区别。
我习惯把CAN帧分成这么几段:
- SOF(Start of Frame):1个显性位,告诉总线上所有节点“我要发数据了”。
- 仲裁场:标准帧11位ID + RTR位;扩展帧29位ID + SRR + IDE + RTR。这里藏着总线仲裁的秘密。
- 控制场:IDE位、保留位、DLC(数据长度码,4位)。DLC告诉接收方后面跟了多少字节数据。
- 数据场:0~8字节。嗯,CAN一次最多传8个字节,这是硬限制。做大数据包拆分的时候要记住这个。
- CRC场:15位CRC + 1位CRC界定符。校验整个帧的完整性。
- ACK场:发送方释放总线,接收方在ACK Slot位拉低电平,表示“我收到了”。
- EOF:7个隐性位,帧结束。
下面这张图,把标准帧和扩展帧的结构画清楚了:
1.2 仲裁机制:谁先说话,谁赢
CAN总线是CSMA/CA架构。多个节点同时发送时,不会冲突,而是通过ID逐位仲裁。谁ID小,谁优先级高。
具体怎么仲裁的?我举个例子:
- 节点A发ID = 0x123(二进制:0001 0010 0011)
- 节点B发ID = 0x456(二进制:0100 0101 0110)
从最高位开始比。第1位,A发0(显性),B发0(显性),总线保持显性,两者继续。第2位,A发0(显性),B发1(隐性),总线被A拉成显性。B检测到总线电平与自己发送的不一致,立刻退出竞争。A胜出,继续发送剩余帧。
整个过程发生在仲裁场,不丢数据,不浪费带宽。这就是CAN的优雅之处。
1.3 位填充与CRC校验:保证数据不出错
CAN总线是差分信号,抗干扰能力很强。但再强的物理层,也怕连续相同的电平。为什么?因为接收节点靠电平跳变来同步时钟。如果连续5个相同位,接收方可能丢失同步。
位填充规则很简单:发送方在连续发送5个相同位后,自动插入一个相反位。接收方检测到5个相同位后,自动丢弃第6位(填充位)。这样保证了总线上的电平跳变密度。
CRC校验呢?CAN用的是15位CRC,生成多项式是:
CRC生成多项式:x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1
这个多项式覆盖了SOF、仲裁场、控制场、数据场。接收方重新计算CRC,与发送方附带的CRC值比对。不一致就发错误帧。
1.4 CMS32 CAN模块外设特性概览
好了,理论讲完,咱们看看CMS32的CAN外设长什么样。CMS32的CAN模块,我总结下来有这几个特点:
| 特性 | 说明 | 我的评价 |
|---|---|---|
| 协议支持 | CAN 2.0A/B,标准帧和扩展帧 | 主流配置,够用 |
| 邮箱数量 | 最多32个消息邮箱 | 比很多MCU多,适合多节点场景 |
| 位速率 | 最高1 Mbps | 常规CAN的上限 |
| 过滤方式 | ID掩码过滤,支持单个/双滤波 | 灵活,但配置稍复杂 |
| 中断支持 | 发送完成、接收完成、错误中断 | 齐全,低功耗设计必备 |
| 低功耗模式 | 支持CAN唤醒,总线活动检测 | 这个后面章节会重点讲 |
我个人觉得,CMS32的CAN模块最值得关注的是它的邮箱管理和低功耗唤醒机制。邮箱多,意味着你可以同时缓存多个不同ID的报文,不用频繁中断CPU。低功耗唤醒,则是做电池供电设备的关键。
下面这张图,展示了CMS32 CAN模块的内部结构: