参考内容
https://www.analog.com/cn/glossary/can.html
https://www.analog.com/cn/technical-articles/understanding-can-transceiver-how-validate-multinode-can-system-performance.html
https://blog.steven53.top/p/stm32-0x0b/#%E4%BD%8D%E6%97%B6%E5%BA%8F
CAN

介绍
- 两根通信线: CANH 和 CANL, 使用差分信号进行通信,抗干扰,无需时钟线
- 总线上挂载多设备,异步通信,冲突时通过报文ID进行仲裁
- 在2.0协议帧下,可以传输 0 ~ 8 Byte
- 广播式通信、请求-响应式通信
- 应答机制、CRC校验机制
- can2.0 最高速率 1Mbit/s
名词解释:
差分线:
https://en.wikipedia.org/wiki/Differential_signalling
两根等长且平行的线,它们同一时刻的电压差描述了 1 bit 的数字信号
- 抗干扰能力强。干扰噪声一般会等值、同时的被加载到两根信号线上,而其差值为0,即,噪声对信号的逻辑意义不产生影响。
- 有效抑制电磁干扰(EMI)。由于两根线靠得很近且信号幅值相等,这两根线与地线之间的耦合电磁场的幅值也相等,同时他们的信号极性相反,其电磁场将相互抵消。因此对外界的电磁干扰也小。
- 时序定位准确。差分信号的接收端是两根线上的信号幅值之差发生正负跳变的点,作为判断逻辑0/1跳变的点的。而普通单端信号以阈值电压作为信号逻辑0/1的跳变点,受阈值电压与信号幅值电压之比的影响较大,不适合低幅度的信号。
协议硬件要求
|
|
- 使用特性阻抗为 120Ω 双绞线分别连接所有设备的 CANH 和 CANL
- 在总线最远的两个点放置两个 120R 阻抗匹配电容,
- 实际测得总线电阻约 60R
- 中间其他节点不装总线电阻
协议细节
基本bit
如果 CANH-CANL 电压大于 1.5V,CAN接收器将其视为逻辑 0
- 这意味着收发器主动产生了两根总线上的压差
如果 CANH-CANL 电压小于 200mV, CAN接收器将其视为逻辑 1 - 这意味着收发器释放了总线,让总线处于默认电压
接收器根据接收到的逻辑在 TXD 和 RXD 上回送数据
节点A发送:1 1 0 1
节点B发送:1 0 0 1
总线结果 :1 0 0 1
- 可以理解为一种线与操作,只要有某个收发器在总线上产生了0,整个总线就体现为0
- 如果某设备试图发送1,但是读到了0,这意味着总线上有其他设备正在发送报文,将停止发送
数据帧结构
can有两种数据帧,一种是基本帧,一种是扩展帧,此外还有过载帧和错误帧
基本帧

SOF(1位): 帧起始位, 固定为显性 0。
CAN ID(11位): 报文标识符,发送时高位在前, 数值越小,仲裁优先级越高。
RTR(1位): 0:数据帧。1:远程帧,请求其他节点发送数据。
IDE(1位): 0:11位标准帧。1:表示采用扩展帧结构。
r0(1位):保留位,经典CAN标准帧中通常为 0。
DLC(4位): 表示数据长度。经典CAN数据长度为0~8字节。
Data(0~64位): 实际负载数据,即0~8字节。
CRC(15位): 用于检测报文在传输中是否出错。
- CRC界定符(1位): 固定为1。
ACK(1位): 发送节点发送隐性 1。正确接收报文的节点将其覆盖为显性 0,表示确认收到。
- ACK界定符(1位): 固定为1。
EOF(7位):帧结束,7*1。
IFS 帧间隔
正常情况下,IFS至少包含连续 3*1。
- 3位结束后:
- 没有节点发送:总线继续保持隐性,称为总线空闲。
- 有节点发送:发送显性SOF,开始下一帧。
- 多个节点同时发送:进入仲裁。
扩展帧

-
扩展帧与基本帧结构基本一样,只有少量区别:
- SRR位固定为1
- IDE为1,代表扩展帧
- 18位扩展ID
- RTR:0:扩展数据帧。1:扩展远程帧。
-
因为SRR固定为1,这导致前11位ID相同的基本帧和扩展帧中,基本帧会赢得仲裁。
错误帧

CAN采取 bit stuffing 模式,即:总线上不允许出现连续6个相同位
-
如果出现6个相同位,将在第六位前插入一个相反位。
-
主动/被动错误标志不采用bit stuffing, 所以其他can设备将轻易地发现此错误
-
如果其他设备刚好在某设备发送完错误标志后开始连续发送,错误标志段可能最长为12bit
错误状态转换 (Error State Transition): CAN控制器硬件内部有三个状态,由两个计数器:发送错误计数器 (TEC, Transmit Error Counter) 和 接收错误计数器 (REC, Receive Error Counter) 决定:
- 主动错误状态 (Error Active):正常状态,发错误帧用 6个0。
- 被动错误状态 (Error Passive):错误较多,发错误帧用 6个1。
- 总线关闭状态 (Bus Off):错误过多,硬件直接断开与总线的物理连接,不再发送任何数据。
仲裁
如果某个节点正在发信,其他节点在该时刻不可以发信
-
仲裁行为只会出现在 两个节点恰好同时开始发信 的前提下
-
前面提到:总线上如果有多个设备一起发信,只要有一个设备发 0 ,总线电平都是 0
-
对于该节点而言,只会有三种情况:
- 总线为0,自己发1
- 总线为0,自己发0
- 总线上可能会有其他试图发 1 的设备,但是被当前设备覆盖成 0 了
- 总线为1,自己发1
-
节点会一边发一边读总线,在第二种情况和第三种情况下,发的东西和读到的东西是一样的
- 此时,仲裁通过
- 如果节点没有通过仲裁,因为can协议帧的头就是 canID, 这意味着赢了它的那个节点ID一定比它大。
- 根据协议,当前节点需要停止发送。
-
综上所述,can仲裁并不需要什么额外步骤,接收方可以持续监听,这就很高效。
举例:两节点ID分别为 9(1001) 和 10(1010)
假设两节点同时发送数据。
- 第一个时间段,两者同步发送
1,总线为1,均继续发送。- 第二个时间段:
- 两者同步发送
0,总线为0,均继续发送。- 9发送
0,10发送1,总线状态0: 9继续发送,10看到总线状态与自己发送的不一致,于是中断之后所有发送。仲裁完成。9之后继续正常发送
时序同步
can是没有时钟线的,但是一条总线上的所有节点必须要保证时钟同步才能确保信息的正常收发
晶振也是不准的,我们需要一套更有效的校准手段

我们把每Bit的时间进行进一步细分,使用Tq单位描述其
$$\Large T_{\text{bit}} = T_{SS} + T_{PTS} + T_{PBS1} + T_{PBS2}$$名词解释:
-
$T_{\text{bit}}$:位时间 (Bit Time)。传送1个比特的总时间。
-
$T_{SS}$:同步段 (Synchronization Segment)。
- 取值:固定为 $1 \times T_q$。
- 边沿跳变应该发生在这一段时间里
-
$T_{PTS}$:传播时间段 (Propagation Time Segment)。
- 取值:1~8$T_q$
- 用于补偿信号在物理导线上传播的物理延迟。
-
$T_{PBS1}$:相位缓冲段1 (Phase Buffer Segment 1)。
- 取值:1~8$T_q$
- 用来做同步调整的“缓冲区1”,可以被拉长。
-
$T_{PBS2}$:相位缓冲段2 (Phase Buffer Segment 2)。
- 取值:1~8$T_q$
- 用来做同步调整的“缓冲区2”,可以被缩短。
执行流程
CAN通过每个电平跳变边沿来同步各节点时钟,带有自校准功能
硬同步(帧开始时同步)
- 开始发送,发送方开始计时,在SS时间段中将数据线驱动为逻辑低电平
- 在检测到SOF (Start Of Frame)下降沿时,接收方同步开始从SS段计时
再同步(逻辑电平跳变边沿不在SS段时再同步)
- 除了帧开始时的第一个下降沿,后续每个数据位都可以进行再同步
- 如果逻辑跳变发生在SS段前或后,则对应增加PBS1或者减少PBS2
- SJW:最大补偿的Tq数,用于防止单次补偿过度

stm32的can外设

发送
- can外设有三个发送缓存(邮箱)
- can外设自动在总线空闲时从三个邮箱中选择一个进行发送
- 可以配置优先级
TXFP(TX Fifo Priority)- 1: 先请求先发送
- 0: 按报文ID优先级发送
- 可以配置
NART(Not Allow ReTransmit)=1 禁止发送失败后自动重传
状态转移图:

- RQCP:发送请求已经完成
- TXOK:发送成功
- TME:发送邮箱空
- ABRQ:终止发送
接收
- can外设有两个三级接收FIFO缓存
- 收发控制器接收到报文,将其送入过滤器匹配
- 如果报文符合过滤条件,则会被放入过滤器指定的一个FIFO
- 配置RFLM (Recieve Fifo Lock Mode):如果FIFO已满,有新的报文到达,可以
- 1: FIFO上锁,新到来的报文被丢弃
- 0: FIFO未上锁,丢弃队列中末尾(最晚到达)的报文,再放入新的报文
状态转移图:

过滤器

每一个过滤器有两个32位的寄存器,和以下几个过滤器配置位
-
FSCx(Filter Bank Scale):
- 0: 每个过滤器使用4个16位寄存器,仅支持标准CAN地址长度 (将32位的寄存器拆成两个16位的使用,能更好的利用资源)
- 1: 每个过滤器使用2个32位寄存器,支持标准和扩展CAN地址长度
-
FBMx(Filter Bank Mode):
- 0: 掩码模式 将新收到的报文ID和过滤器中的ID进行比较,但是仅比较Mask中为1的位(类似IP地址掩码)
- 1: 列表模式 将新收到的报文ID和过滤器中的ID进行比较,一个过滤器允许两个特定的报文ID
-
FACT(Filter ACTive): 过滤器使能开关
-
FFA(Filter Fifo Assignment): 通过过滤器的报文进入哪一个FIFO
掩码机制
配置为掩码模式时,过滤器将输入的报文ID和寄存器中的ID进行比较,但是仅比较二进制下,Mask中为1的位,其它位无论是什么都可以。
用公式来描述,满足以下公式的数据包,可以通过过滤器 CAN_ID & MASK == FILTER_ID & MASK
基于 AND 运算逻辑,我的理解:
- Mask:我们关心的位需要写1, 不关心的位需要写0
- Filter: 需要填写我们关心的位,其余位全部填充 0
我们要接收 0x100 到 0x1FF:
- 最小值 0x100 = 0b0001 0000 0000
- 最大值 0x1FF = 0b0001 1111 1111
- 规律:前 4 位(高 4 位)必须固定为 0001,后 8 位(低 8 位)无所谓。
- 所以:
- Filter 设为:0b0001 0000 0000(即 0x100)
- Mask 设为:0b1111 0000 0000(即 0xF00。前 4 位是 1 表示必须匹配,后 8 位是 0 表示忽略)。