Written by CC -- 2024-12-09
RV-C(Recreational Vehicle Communication Protocol)协议是为房车通信网络设计的标准通信协议,基于CAN(Controller Area Network)总线技术,定义了一套适用于各种房车设备的通信机制。以下是该协议的技术文档总结,涵盖其核心组成部分及应用层规范。
RV-C协议是一种用于房车内部设备间通信的协议,支持多种设备类型和数据交换。该协议的设计重点是设备之间的互操作性和数据可靠性,采用CAN总线的扩展帧格式来实现数据传输。协议层级包括物理层、数据链路层、网络层、传输层和应用层。RV-C协议规定所有消息必须使用CAN数据帧的扩展帧格式,数据长度为8字节。RV-C协议支持多种房车设备,定义了标准化的数据组和功能接口。当多个设备尝试声明同一地址时,RV-C协议提供了一套仲裁机制以确保地址分配唯一性及优先级分配。
• 电缆类型:建议使用屏蔽双绞线以减少电磁干扰。
• 数据速率:支持标准CAN速率(如250 kbps)。
• 拓扑结构:总线拓扑,终端电阻要求为120欧姆。
• 连接器类型:符合诊断标准的接头,便于设备连接和维护。
• 优先级位(Priority Bits):用于决定当两个设备同时传输时,哪条消息优先通过总线。
• 数据组号(Data Group Number, DGN):唯一标识数据包类型。
• 源地址(Source Address, SA):标识数据包的发送节点,必须唯一。
• 地址分配:每个设备需要唯一的源地址,可以通过静态分配或动态地址声明实现。
• 数据分组:通过17位的数据组号(DGN)标识参数组和设备类型。
• 多包消息支持:允许分片发送大于8字节的数据,支持多个包的组装与解析。
• 错误处理:协议支持基本的错误检测和消息确认机制。
• 信息共享:设备定期广播其状态数据(如电池电量、空调状态)。
• 控制消息:用于发送控制命令(如启动发电机、调整温控设备)。
• 诊断消息:用于设备故障检测与状态查询。
• 设备标识:通过产品标识消息,提供设备的制造商和型号信息。
• 电源设备:如逆变器、电池管理系统(BMS)。
• 传感器:如气体传感器、水箱液位传感器。
• 环境控制:如空调、暖气控制器。
• 导航与位置服务:如GPS模块。
• 安全系统:如门窗锁定状态传感器。
• RV-C协议采用小端序(Little-Endian)编码方式。
• 数据类型包括布尔值、整数、浮点数和字符串。
• 所有未使用的位或字段应填充为默认值0xFF,以避免解析错误。
1. 设备广播其地址声明消息。
2. 如果检测到冲突,设备根据优先级字段重新声明地址。
3. 地址声明过程确保每个设备获得唯一地址。
RV-C协议在某些方面与SAE J1939协议保持兼容,例如数据帧结构和优先级处理机制。这使得RV-C设备可以与基于J1939协议的系统共存,但也引入了部分协议间的差异,需要在设备实现时加以注意。
• GENERAL_RESET (17F00h):通用重置消息,用于设备复位或清除故障。
• LEVELING_CONTROL_COMMAND (1FFEEh):用于控制房车水平调节系统。
• GPS_POSITION (0xFEF3):提供GPS位置信息,包括纬度、经度和海拔。
• 实时性强:基于CAN总线的设计,使RV-C协议具有低延迟和高可靠性。
• 标准化接口:定义了丰富的设备类型和数据组,便于集成与扩展。
• 可扩展性:支持多包消息和动态地址声明,适应多种应用场景。
• 在设备开发时,确保实现协议的全部强制性消息。
• 定期广播设备的状态消息(如DMRV),以确保网络内设备能够正确互操作。
• 在多设备系统中,合理规划地址分配和消息优先级,以避免冲突和延迟。
RV-C是基于CAN总线通信,数据在网络上传输时以帧的形式发送(通信速率范围为125kbps~1Mbps)。一个CAN数据帧包含以下主要字段:
|字段|长度(位)|描述|
|Start of Frame (SOF)|1|帧开始标志,用于标识一帧的起始位置|
|Arbitration ID|29|扩展 ID,用于定义消息优先级、数据类型(PGN/DGN)和源地址(SA)|
|Control Field|6|包含数据长度代码(DLC)和保留位|
|Data Field|0-64 位|数据负载,最多 8 字节(64 位)。|
|CRC Field|15|循环冗余校验,用于检测数据传输中的错误|
|CRC Delimiter|1|CRC结束标志位,固定逻辑为1|
|ACK Field|2|确认字段,用于接收节点确认是否成功接收到消息|
|End of Frame (EOF)|7|帧结束标志,用于标识帧的结束位置|
标准的扩展帧格式(29位CAN ID)中,Arbitration ID按以下原则分配: | Priority (3 bits) | PGN/DGN (18 bits) | Source Address (8 bits) | 示例数据帧:
|SOF | Arbitration ID | Control Field | Data Field | CRC | ACK | EOF|
--- | -------------- | ------------- | ----------------- | --- | --- | ---|
|0 | 0x18F00420 | 8 (DLC=8) | 0x1C00000000000000| ... | ... | ...|
二进制为 0001 1000 1111 0000 0000 0100 0010 0000 数据帧各部分解析:
• SOF :长度1位,通常是固定的0,标志着帧的起始位置 ;
• Arbitration ID :长度29位(扩展帧、标准帧只有11位);
• Priority :长度为3位,0b110代表优先级为6;
• Reserved Bit : 长度为1位,保留位固定为0;
• Data Page :长度为1位,0表示标准PGN页面;
• Data Group Number :长度为18位,0xF004代表发动机转速;
• Source Address :长度为8位,0x20代表来源设备地址为0x20,可能代表发动机控制器;
• Control Field :DLC=8,长度为6位+2位保留位,本帧中8代表接下来的数据段长度为8字节;
• Data Field : 0x1C00000000000000,CAN中使用小端模式,所以1C00代表7168,转速单位通常为1/8 RPM,因些数据解析最终结果为 7168 / 8 = 896 RPM;
• CRC :由协议生成多项式计算得出,长度15位(检验码)+1位(固定分隔符1);
• ACK :长度为2位,表示接收设备是否成功接收消息。如果所有设备都成功接收该帧,则会发送ACK信号;
• EOF :长度为7位,固定为逻辑1111111,标志帧的结束;
示例代码:
import can
# 初始化 CAN 总线
bus = can.interface.Bus(bustype='socketcan', channel='can0', bitrate=250000)
def parse_arbitration_id(arbitration_id):
"""
解析 CAN Arbitration ID
:param arbitration_id: 29 位的 Arbitration ID
:return: 解析后的优先级、PGN/DGN 和 SA
"""
# 提取优先级(高 3 位)
priority = (arbitration_id >> 26) & 0x07
# 提取 PGN/DGN(中间 18 位)
pgn = (arbitration_id >> 8) & 0x3FFFF
# 提取 Source Address(低 8 位)
source_address = arbitration_id & 0xFF
return priority, pgn, source_address
def process_message(msg):
"""
处理接收到的 CAN 消息
:param msg: CAN 消息
"""
arbitration_id = msg.arbitration_id
data = msg.data
# 解析 Arbitration ID
priority, pgn, source_address = parse_arbitration_id(arbitration_id)
print(f"Received CAN Message:")
print(f" Arbitration ID: {hex(arbitration_id)}")
print(f" Priority: {priority}")
print(f" PGN/DGN: {hex(pgn)}")
print(f" Source Address: {hex(source_address)}")
print(f" Data: {data.hex()}")
# 示例:处理特定 PGN 的消息
if pgn == 0xF004: # 假设 PGN 0xF004 表示发动机转速
engine_speed = int.from_bytes(data[:2], byteorder='little') / 8.0 # 假设数据前 2 字节为转速
print(f" Engine Speed: {engine_speed} RPM")
# 监听 CAN 消息
print("Listening for CAN messages...")
while True:
msg = bus.recv()
if msg is not None:
process_message(msg)
• 小端模式:数据存储按内存低地址存储数据低字节方式开始存储
• 大端模式:数据存储按内存低地址存储数据高字节方式开始存储
例如,一个 16 位的整数 0x1234,在小端模式下的存储顺序为:
|地址|数据|
|0x00|0x34|(低字节)
|0x01|0x12|(高字节)
大端模式则刚好相反:
|地址|数据|
|0x00|0x12|(高字节)
|0x01|0x34|(低字节)
通过资料查找及学习,掌握RV-C通讯协议