♪³ CAN总线
♪⁶ 硬件组成
1.两根线(CAN_H、CAN_L),差分信号,无需共地(不过实际使用时,两个设备之间会有额外的共地);
2.线路连接方式: STM32(UART) → CAN收发器 → 设备;
♪⁶ 电平标准
高速CAN:电压差为0V → 逻辑1(隐性电平)、电压差为2V → 逻辑0(显性电平);
低速CAN:电压差为-1.5V → 逻辑1(隐性电平)、电压差为3V → 逻辑0(显性电平);


注:
两线没有电压差是总线的默认状态 → 因此是隐性;
此外电路总线中默认高电平拉高,因此默认是逻辑1;
在低速CAN中,由于长距离线路中会有损耗,因此总线需要拉高电平,这样,默认的两根差分信号线电平不再相同,因此不能像高速CAN一样相连,此外高速,之所以高速,其闭环的连接方式,也能让差分信号更快地归零,从而实现高速
♪⁶ CAN帧格式
包括以下类型:(都是人为定义的)
- 数据帧、遥控帧、错误帧、过载帧、帧间隔
数据帧格式:
1.标准格式
| 起始位 | 仲裁段 | - | 控制段 | - | - | 数据段 | CRC段 | - | ACK段 | - | 帧结束 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 说明 | SOF | ID | RTR | IDE | r0 | DLC | Data | CRC | CRC界定符 | ACK槽 | ACK界定符 | EOF |
| 位数 | 1 | 11 | 1 | 1 | 1 | 4 | 0-64 | 15 | 1 | 1 | 1 | 7 |
| 数据约束 | 0 | 1/0 | 0 | 0 | 0 | 1/0 | 1/0 | 1/0 | 1 | 发送方:1 接收方:0 | 1 | 1 |
默认空闲时总线是逻辑1,起始位为逻辑0,表示开始发数据了;
仲裁段-报文ID:区分设备id、决定消息优先级;
- RTR:远程请求标志位,数据帧必须为0,遥控帧必须为1;
- 相同id下,数据帧优先级大于遥控帧;
控制段: - IDE:ID扩展标志位,用于区分该数据帧是标准格式还是扩展格式;
- r0:保留位,暂时无用,用于后续升级;
- DLC:指定数据段的长度;如 1000 表示数据段有8个字节;
数据段: - 和DLC对应,最小单位为字节,即0-8个字节,也就是0-64个位;
CRC段: - CRC:CRC检验码,按CRC算法计算出来的;
- CRC界定符,用于给发送方释放总线后监听接收方操作总线留出时间;
ACK段: - ACK位:应答位,发送方发送完数据段和CRC段后,会短暂监听总线,此时接收方在这一位操作总线,拉开电平发送逻辑0,这样发送方就能知道此时接收方接收到信息了;
- ACK界定符:和CRC界定符组合使用,用于监听应答和总线控制交接的缓存;
- 应答是夹在发送过程之中的;
帧结束: - EOF:7个停止位;
2.扩展格式:增加ID个数,原本的11位ID数不够用,因此产生了扩展格式;
| 起始位 | 仲裁段 | - | - | - | - | 控制段 | - | - | 数据段 | CRC段 | - | ACK段 | - | 帧结束 | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 说明 | SOF | ID1 | SRR | IDE | ID2 | RTR | r1 | r0 | DLC | Data | CRC | CRC界定符 | ACK槽 | ACK界定符 | EOF | |
| 位数 | 1 | 11 | 1 | 1 | 18 | 1 | 1 | 1 | 4 | 0-64 | 15 | 1 | 1 | 1 | 7 | |
| 数据约束 | 0 | 1/0 | 1 | 1 | 1/0 | 0 | 0 | 0 | 1/0 | 1/0 | 1/0 | 1 | 发送方:1 接收方:0 | 1 | 1 |
SRR:
- 在仲裁规则中,是先比较11个ID位,后比较RTR位,因此在扩展格式中,原本的RTR位就移到了整个仲裁段的最后面,在中间插入新的ID段,但是为了和标准格式兼容,原本的RTR位就空出来了,因此规定为SRR位,之后由于要保证标准格式的优先级高于扩展格式,因此为了区分,在SRR位规定为1,和原本标准格式的RTR位规定位0作区分;
IDE: - 用于区分当前是标准格式还是扩展格式,标准格式为显性(逻辑0),扩展格式为隐性(逻辑1);
控制段: - 在标准格式中原本的r1、r0都是保留位,后续增加了IDE位,因此在标准格式中没有r1位,而是IDE位,但在扩展格式中,IDE已经在前面出现了,因此这里恢复成r1位,和r0位一起作为新的保留位,可供后续升级;
- DLC:和标准格式一样,用于指定数据段的长度;
数据段之后和标准格式都一样;
符号说明:
- SOF:Start of Frame 帧起始,标志一段波形的开始;
- ID:Identify 标识;
- RTR:Remote Transmission Request 远程请求位,区分数据帧和遥控帧;
- IDE:Identify Extension 扩展标志位,区分标准格式和扩展格式;
- SRR:Substitute Remote Request 替代RTR,协议升级后的无意义占位;
- r0/r1:Reserve 保留位,为协议升级留下空间;
- DLC:Data Length Code 数据长度,指定Data有多少字节;
- Data:数据帧中的有效数据内容;
- CRC:Cyclic Redundancy Check 循环冗余校验,检测数据是否正确;
- ACK:Acknowledgement 应答位,判断数据有没有被接收方接收;
- CRC/ACK界定符:位应答位前后发送方和接收方交接总线控制权留出缓冲时间;
- EOF:End of Frame 帧结束,表示数据位已经传输完毕;
遥控帧格式:
从机主动请求数据,主机从总线接收到后再发送数据帧给从机;
其实就是除部分标志位与数据帧不同外,数据帧为空的数据帧;
遥控帧RTR为1;遥控帧ID部分表示要请求的数据,类似于功能码;
(错误帧、过载帧、帧间隔相对复杂,初学无需了解)
错误帧:
总线上的设备都会监控总线上的数据,如果发现有位错误、CRC校验错误等,就会用错误帧破坏数据帧,同时终止当前的发送设备;
♪⁶ 位填充(了解)
用于给波形增加定时信息,防止波形一直无变化,因为可能每个设备的时钟会有一点偏差,长时间不变的波形可能会导致计数异常;
此外位填充还能表示总线是处于活跃状态的,因为默认状态是长时间的逻辑1,有相反逻辑电平时,说明总线是正在传输数据的;
位填充规则:
发送方每发送5个相同电平后,就会自动追加一个相反的电平,接收方则会基于相同规则自动移除该填充位,
如 发送 100000110 → 实际发送 1000001110;
如果填充后仍然有5个相同的,则继续填充,
如 发送 10000011110 → 实际发送 → 1000001111100;
此外,错误帧中的错误标注和错误数据长度都是6个位,而正常波形不会超过5个相同电平,因此位填充能特异化错误帧,便于识别。
♪⁶ 数据采样和同步(了解)
CAN总线没有时钟线,通过波特率决定每个位的时长;
(波特率:每秒发送的位数)
硬件同步:
以第一次跳变沿为起始参考位置,向后偏移半个采样周期作为第一位数据的采样位置,之后依次进行,就能保证每个采样点都在数据中心附近;
再同步:
由于设备的时钟可能存在误差,在采样的过程中,每次采样周期可能不是刚好和发送方约定好的实际采样周期,随着数据位数的增加,误差不断累积,导致之后某一次采样点会恰好落到跳变沿的位置;
为了解决这个问题,引入再同步:
即,以每次跳变沿的位置为参考位置,观察到采样点偏离这个参考位置太多的时候,就适当地调整下一次采样点的位置,之后按原有采样周期进行,构成一个动态监控修复的过程;
位时序
将一个位的时长进行更细致地划分,分成一个个以最小时间单位(Tq)为计数单位的时长,
如同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)、相位缓冲段2(PBS2);
采样点就发生在PBS1和PBS2之间;
每一段的时长会根据实际信号跳变沿的位置进行动态调整,以实现采样点的偏移。

♪⁶ 仲裁机制
总线的资源分配机制:当多设备同时发送时遇到的问题;
先占先得规则:
当其他设备已经在操作总线时,其他设备无法发送数据帧和遥控帧,但可以发错误帧;
任何设备规定:检测到总线存在连续11个隐性电平逻辑1时,即认为总线当前处于空闲状态,这时才会开始发数据帧或遥控帧,否则等待总线空闲再发送;
非破坏性仲裁:
当总线上的设备要同时发送数据时(也就是当前总线是空闲的,但是多个设备都检测到了,都想要发送数据的时候),总线协议根据仲裁段(ID号)进行比较,ID号小的优先级更高,将会获得总线的控制权,ID号大的转为接收状态,等待下一次空闲再发送;
线与特性:总线上有0则0,全1才1;
回读机制:设备在发送一位数据后会读取当前总线状态,检查是否和当前发送的一致;
根据线与和回读,设备在发送过程中回读发现和自己发送的ID不一样就会停止发送进入等待,这样ID号小的就能继续发送,从而实现优先级的效果;
♪³ 达妙电机的数据协议
MIT模式参数注意事项:
1.位置模式:;
2.速度模式:;
3.力矩模式:;
通过上位机调试助手设置电机ID:
在只连接一个电机的情况下(不要将他们串联,否则所有电机的ID都会被设为一样的),将USB转UART连接到电机串口调试口,通过下图这个地方设置当前电机的ID

(电机)接收帧:(STM32 → 关节电机)

如:
电机 ID=0x02,MIT模式,位置,速度,,, 时
CAN ID为:0x002;
CAN 数据帧为:90 13 7F F0 08 19 97 FF;
位置:Data[0], Data[1] 占2字节:0x0000 → 0xFFFF
即从 -12.50 → 12.50 ,映射至 0x0000 → 0xFFFF;
0 的时候为 0x7FFF
速度:Data[2], Data[3][0:3] 占2.5字节:0x000 → 0xFFF
即从 -45.00 → 45.00 ,映射至 0x000 → 0xFFF
0 的时候为 0x7FF
:Data[3][4:7], Data[4] 占2.5字节:0x000 → 0xFFF
即从 0.00 → 500 ,映射至 0x000 → 0xFFF
0 的时候为 0x000
:Data[5], Data[6][0:3] 占2.5字节:0x000 → 0xFFF
即从 0.00 → 5.00 ,映射至 映射至 0x000 → 0xFFF
0 的时候为 0x000
转矩 :Data[6][4:7], Data[7] 占2.5字节:0x000 → 0xFFF
即从 -18.00 → 18.00 ,映射至 0x000 → 0xFFF
0 的时候为 0x7FF
因此零状态数据帧为:7F FF 7F F0 00 00 07 FF;
(电机)反馈帧:(关节电机 → STM32)


反馈帧同样是数据帧,
反馈帧 ID 是主控制器的 ID,默认是 0x000,因此需要将STM32自身这个CAN设备节点的ID设置为 0x000
数据段部分:
Data [0] 为 ID 的低8位 再加上错误类型,然后取低8位:
如ID为0x001,错误类型为8,则 0x001 << 4 → 0x010,加上错误类型并取低8位:0x10 + 0x08 → 0x18;
但这里控制器ID是0x000,因此对应错误类型就是:
| 错误类型 | 超压 | 欠压 | 过电流 | MOS过温 | 电机线圈过温 | 通讯丢失 | 过载 |
|---|---|---|---|---|---|---|---|
Data[0] | 0x08 | 0x09 | 0x0A | 0x0B | 0x0C | 0x0D | 0x0E |
Data[1], Data[2]:POS,位置,电机此时角度(rad),和控制帧中的位置对应,占2字节,
0x0000 → 0xFFFF 对应 -12.50 → 12.50 ;
Data[3], Data[4][0:3]:VEL,速度,电机此时转速(rad/s),占2.5字节,
0x000 → 0xFFF 对应 -45.00 → 45.00 ,
如电机当前速度为 25.0rad/s,速度范围 VMAX=45rad/s时,
对应数据 0xC71;
Data[4][4:7], Data[5]:T,转矩,电机当前输出扭矩,占2.5字节,
0x000 → 0xFFF 对应 -18.00 → 18.00 ;
Data[6]:T_MOS,驱动电路的MOS管平均温度,占1字节;
Data[7]:T_Rotor,电机内部线圈平均温度,占1字节;

