SPI 转 CAN

  • 如下协议定义只适用于固件 V4.1 版本及以后

  • 发送 AT+VER 串口指令,可以查询固件版本,如未返回版本号或者返回 V33,请下载最新固件

  • 支持 SANPO 电机调试工具 快速生成调试代码,支持全系列 CAN/RS485 协议电机

协议说明

适用场景

接线规则

发送协议(SPI->CAN)

接收协议(CAN->SPI)

CAN 扩展帧电机(固定报文长度 23 个字节)

CS1 片选通道控制 CAN1、CAN2;CS2 片选通道控制 CAN3、CAN4

固定帧头 2 个字节(0x45 0x54)+ Channel 1 个字节 + CANID 扩展帧 4 个字节 + CAN 数据长度(1 字节)+ CAN 数据(固定 8 字节,不够 8 字节使用 0x00 补齐)+ 固定帧尾 2 个字节(0x0D 0x0A)+ 预留 4 个字节(0x00 0x00 0x00 0x12)+ CRC 校验(1 字节)

固定帧头 2 个字节(0x45 0x54)+ Channel 1 个字节 + CANID 扩展帧 4 个字节 + CAN 数据长度(1 字节)+ CAN 数据(固定 8 字节,不够 8 字节使用 0x00 补齐)+ 固定帧尾 2 个字节(0x0D 0x0A)+ 预留 4 个字节(0x00 0x00 0x00 0x12)+ CRC 校验(1 字节)

CAN 标准帧电机(固定报文长度 23 个字节)

CS1 片选通道控制 CAN1、CAN2;CS2 片选通道控制 CAN3、CAN4

固定帧头 2 个字节(0x53 0x54)+ Channel 1 个字节 + 固定 2 个字节(0x00 0x00)+ CANID 标准帧 2 个字节 + CAN 数据长度(1 字节)+ CAN 数据(固定 8 字节,不够 8 字节使用 0x00 补齐)+ 固定帧尾 2 个字节(0x0D 0x0A)+ 预留 4 个字节(0x00 0x00 0x00 0x12)+ CRC 校验(1 字节)

固定帧头 2 个字节(0x53 0x54)+ Channel 1 个字节 + 固定 2 个字节(0x00 0x00)+ CANID 标准帧 2 个字节 + CAN 数据长度(1 字节)+ CAN 数据(固定 8 字节,不够 8 字节使用 0x00 补齐)+ 固定帧尾 2 个字节(0x0D 0x0A)+ 预留 4 个字节(0x00 0x00 0x00 0x12)+ CRC 校验(1 字节)

CAN 扩展帧报文示例

发送报文

固定帧头(2 字节)

Channel(1 字节)

CANID(4 字节)

数据长度(1 字节)

数据(固定 8 字节)

固定帧尾(2 字节)

预留 4 个字节

CRC 校验(1 字节)

0x45 0x54

0x00

0x00 0x00 0xFD 0x01

0x08

0x48 0x45 0x4C 0x4F 0x00 0x00 0x00 0x00

0x0D 0x0A

0x00 0x00 0x00 0x12

0x0F

  • SPI(CS1)控制 CAN1 和 CAN2 接口,SPI(CS2)控制 CAN3 和 CAN4 接口,请参考开发板背面的说明

  • Channel 为 0x01 或者 0x02 或者 0x03 或者 0x04,指定向哪个 CAN 接口发送报文,如果为 0x00,将向当前 SPI(CS)通道上的所有 CAN 接口发送报文

  • 扩展帧 CANID 为 29bit,占据 CANID 4 个字节的低 29bit

接收报文

固定帧头(2 字节)

Channel(1 字节)

CANID(4 字节)

数据长度(1 字节)

数据(固定 8 字节)

固定帧尾(2 字节)

预留 4 个字节

CRC 校验(1 字节)

0x45 0x54

0x00

0x00 0x00 0x01 0xFE

0x08

0x48 0x45 0x4C 0x4F 0x01 0x02 0x03 0x04

0x0D 0x0A

0x00 0x00 0x00 0x12

0x0F

代码片段(SPI 转 CAN 扩展帧,Python)

完整代码样例请参考 spi_cybergear_demo_v4.py

FRAME_HEADER = [0x45, 0x54]
FRAME_TAIL = [0x0D, 0x0A]
RESERVED = [0x00, 0x00, 0x00, 0x12]

# 发送(帧头2字节 + channel1字节 + CANID4字节 + DLC1字节 + data + 帧尾2字节 + 预留4个字节 + CRC校验(1字节))

def build_spi_ext_frame(channel: int, arbitration_id: int, data: list[int]) -> list[int]:
    ext_id = [
        (arbitration_id >> 24) & 0xFF,
        (arbitration_id >> 16) & 0xFF,
        (arbitration_id >> 8) & 0xFF,
        arbitration_id & 0xFF,
    ]
    data_bytes = (data + [0x00] * 8)[:8]
    payload = (
        FRAME_HEADER
        + [channel & 0xFF]
        + ext_id
        + [len(data[:8])]
        + data_bytes
        + FRAME_TAIL
        + RESERVED
    )
    crc = crc8_calculator.calculate(payload)
    return payload + [crc]


tx = build_spi_ext_frame(channel=0x00, arbitration_id=0x0000FD01, data=[0x01] + [0x00] * 7)
rx = spi.xfer2(tx)  # 固定长度23字节

# 接收报文(帧头2字节 + channel1字节 + CANID4字节 + DLC1字节 + data + 帧尾2字节 + 预留4个字节 + CRC校验(1字节))
data_part = rx[:22]
crc_ok = crc8_calculator.calculate(data_part) == rx[22]

CAN 标准帧报文示例

发送报文

固定帧头(2 字节)

Channel(1 字节)

预留 2 个字节

CANID(2 字节)

数据长度(1 字节)

数据(固定 8 字节)

固定帧尾(2 字节)

预留 4 个字节

CRC 校验(1 字节)

0x53 0x54

0x00

0x00 0x00

0x01 0x42

0x08

0x48 0x45 0x4C 0x4F 0x01 0x02 0x03 0x04

0x0D 0x0A

0x00 0x00 0x00 0x12

0x0F

  • SPI(CS1)控制 CAN1 和 CAN2 接口,SPI(CS2)控制 CAN3 和 CAN4 接口

  • Channel 为 0x01 或者 0x02 或者 0x03 或者 0x04,指定向哪个 CAN 接口发送报文,如果为 0x00,将向当前 SPI(CS)通道上的所有 CAN 接口发送报文

  • 标准帧 CANID 为 11bit,占据 CANID 2 个字节的低 11bit

接收报文

固定帧头(2 字节)

Channel(1 字节)

预留 2 个字节

CANID(2 字节)

数据长度(1 字节)

数据(固定 8 字节)

固定帧尾(2 字节)

预留 4 个字节

CRC 校验(1 字节)

0x53 0x54

0x00

0x00 0x00

0x01 0x42

0x08

0x48 0x45 0x4C 0x4F 0x01 0x02 0x03 0x04

0x0D 0x0A

0x00 0x00 0x00 0x12

0x0F

开发样例