USB CDC串口转 FDCAN
本协议用于 USB CDC串口协议收发 CAN FD 报文,为变长协议,支持标准帧和扩展帧,单帧数据区最大 64 字节。CAN FD 支持 BRS。仲裁段波特率由 AT+SETFDCAN=<arb_baud>,<data_baud> 的 arb_baud 配置,数据段波特率由 data_baud 配置,当前支持 2Mbps 或 5Mbps。
出厂默认 CAN/FDCAN 参数为仲裁段 1Mbps、数据段 5Mbps、BRS 开启;如果现场 CAN FD 总线使用该参数,可以直接按本页 SF / EF 帧格式发送。需要修改波特率时,再通过 USB CDC串口工具发送 AT+SETFDCAN=<arb_baud>,<data_baud>,并把发送结束符设置为 CRLF。配置会写入固件持久化存储,下次上电继续使用,无需重复配置。
如果在 Linux 上使用 SocketCAN,请参考 SocketCAN / gs_usb。SocketCAN 不使用本页的 SF / EF 帧头。
USB CDC串口转 FDCAN 协议报文以 0x0D 0x0A 结尾。
协议格式
类型 |
帧格式 |
|---|---|
CAN FD 扩展帧 |
|
CAN FD 标准帧 |
|
字段说明
字段 |
说明 |
|---|---|
|
ASCII |
|
ASCII |
|
|
|
29 bit 扩展帧 CAN ID,放在 4 字节字段低 29 bit |
|
11 bit 标准帧 CAN ID,放在 2 字节字段低 11 bit |
|
标准帧保留字段,固定 |
|
CAN FD 数据长度编码,取值 |
|
CAN FD 数据,真实长度由“数据长度编码”决定 |
|
报文尾 |
CAN FD 的“数据长度编码”,字段范围 0x00~0x0F。
编码字段值 |
真实数据长度 |
|---|---|
|
0 |
|
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
12 |
|
16 |
|
20 |
|
24 |
|
32 |
|
48 |
|
64 |
扩展帧示例
帧头 |
Channel |
CANID |
数据长度编码 |
Data |
帧尾 |
|---|---|---|---|---|---|
|
|
|
|
16 字节有效数据 |
|
标准帧示例
帧头 |
Channel |
Reserved |
CANID |
数据长度编码 |
Data |
帧尾 |
|---|---|---|---|---|---|---|
|
|
|
|
|
12 字节有效数据 |
|
Python 示例
TAIL = bytes([0x0D, 0x0A])
LEN_TABLE = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64]
def length_code_to_size(code: int) -> int:
if not 0 <= code < len(LEN_TABLE):
raise ValueError("invalid CAN FD length code")
return LEN_TABLE[code]
def build_usb_fdcan_ext(channel: int, can_id: int, length_code: int, data: bytes) -> bytes:
if not 0 <= can_id <= 0x1FFFFFFF:
raise ValueError("extended CAN ID must be 0..0x1FFFFFFF")
size = length_code_to_size(length_code)
if len(data) != size:
raise ValueError("data length does not match CAN FD length code")
return bytes([0x45, 0x46, channel & 0xFF]) + can_id.to_bytes(4, "big") + bytes([length_code]) + data + TAIL
def build_usb_fdcan_std(channel: int, can_id: int, length_code: int, data: bytes) -> bytes:
if not 0 <= can_id <= 0x7FF:
raise ValueError("standard CAN ID must be 0..0x7FF")
size = length_code_to_size(length_code)
if len(data) != size:
raise ValueError("data length does not match CAN FD length code")
return bytes([0x53, 0x46, channel & 0xFF, 0x00, 0x00]) + can_id.to_bytes(2, "big") + bytes([length_code]) + data + TAIL