1. 15765协议介绍
简单的来说,15765协议指的是
基于CAN2.0A/B 协议 (也可以叫做ISO11898协议 -链路层)
硬件接口的 应用层 通讯协议,
它用于实现通用的车辆诊断服务。
ISO11898协议参考下图。
参考搜索到的“CAN总线协议讲解”文档。
它规定了:
1、总线 CAN_H 和 CAN_L 之间要连接120欧姆电阻。
2、CAN总线为隐性时(即逻辑电平为1时)总线电压差为0V(图示默认电平都为2.5V)。
CAN总线为显性时(即逻辑电平为0时)总线电压差为2.0V左右(图示电平为3.5V和1.5V)。
3、总线通讯速度在125K到1M 比特率每秒。
2. 协议数据单元PDU
这是硬件层的。
15765中一个PDU就是一帧CAN数据。它主要包括:帧ID和(最多8个)字节数据。
帧ID分29bit的扩展帧和11bit的标准帧。
整体格式见下图,具体内容要去参考CAN2.0协议(ISO11898)。
3. 服务数据单元FDU
由1到多个PDU组成FDU,其组织方式可以简单理解为就是15765协议。
PDU有4个类型:
1)单帧
帧数量为1,也即数据不超过8个字节。
首字节表示长度,后面紧跟数据。
如 02 3E 00 //长度为2,诊断ID为0x3E 子数据为00
2)多帧首帧
帧数量大于1,也即数据超过8个字节。
首字节的前4bit为1表示为多帧首帧。
首字节左移8位 再加上次字节表示数据长度,也即数据最大为4095个字节。
如 10 08 01 02 03 04 05 06 //多帧首帧,且数据长度为8,后面6个是有效数据
3)多帧数据帧
首字节的前4bit为2表示为多帧首帧。
首字节的后4bit表示序号,第一包从1开始,后面顺序递增,递增超过15时从0开始。
10 08 01 02 03 04 05 06 //首帧
30 00 00 00 00 00 00 00 //流控帧
21 07 08 //数据帧
4)多帧流控帧
首字节的前4bit为3表示为多帧流控帧。
首字节的后4bit表示响应码,00表示正常,可以继续发送数据,否则应当停止后续发送。
第三个字节一般表示多帧发送延时,一般为00表示后续多帧数据帧之前发送间隔为0,为1表示要间隔1ms发送。
其它位置各家厂商定义不尽相同,有些甚至不用流控帧。
4. 15765组包和拆包实现
4.1 准备环境
我们准备2个设备,连接CAN高和CAN低。默认配置好和打开CAN-1M 波特率通讯。
发送数据(发起端发送ID用18FFFFFF):
{
"cmd":"get_vol",
"from":"master",
"to":"device"
}
压缩:
{"cmd":"get_vol","from":"master","to":"device"}
转Hex:7b22636d64223a226765745f766f6c222c2266726f6d223a226d6173746572222c22746f223a22646576696365227d
数据长度为47 即0x2F
响应数据(接收端响应ID用18FFFFFE):
{
"cmd":"23.89v",
"from":"device",
"to":"master"
}
压缩:
{"cmd":"23.89v","from":"device","to":"master"}
转Hex:
7b22636d64223a2232332e383976222c2266726f6d223a22646576696365222c22746f223a226d6173746572227d
数据长度为46 即0x2E
4.2 组包
由于发送数据长度大于8,需要多包方式进行组包。
首包及数据包可拆解如下:
发起端:
10 2F 7b 22 63 6d 64 22 //发送
30 00 00 00 00 00 00 00 //响应
21 3a 22 67 65 74 5f 76 //发送
22 6f 6c 22 2c 22 66 72
23 6f 6d 22 3a 22 6d 61
24 73 74 65 72 22 2c 22
25 74 6f 22 3a 22 64 65
26 76 69 63 65 22 7d 00 //空余1字节填充00
接收端:
10 2E 7b 22 63 6d 64 22 //发送
30 00 00 00 00 00 00 00 //响应
21 3a 22 32 33 2e 38 39 //发送
22 76 22 2c 22 66 72 6f
23 6d 22 3a 22 64 65 76
24 69 63 65 22 2c 22 74
25 6f 22 3a 22 6d 61 73
26 74 65 72 22 7d 00 00
发起端流程:
先发送10帧,等待30帧响应。
收到30帧正响应后,按顺序将21~26 共6包数据依次发出去。
然后再等待接收ID的10帧。收到后要立即响应30帧。
然后读取或缓存收到的2x数据帧,提取有效数据用Json API进行解析。
4.3 拆包
对于发送端的数据,组好包的数据只管发送。
处理接收时要进行逐个判断。
参考代码如下:
int ISO15765CanFrameRxDeal(uint8_t data, uint32_t id)
{
switch(data[0]&0xF0)
{
case 0x00://单帧
//单帧可以当场处理掉
break;
case 0x10://首帧
//1,提取要接收的长度
//2,根据长度或这包数申请内存buf(或者创建/清空数据队列)
//3,缓存第一包的6byte数据
//4,发送30帧响应
break;
case 0x20://数据帧
//根据包序号判断是否接收完毕
//将数据缓存到buf(或者将数据写入队列)
break;
case 0x30://流控帧
//发送完10帧后等待30帧,一般判断是不是30帧正响应即可
break;
}
}
5. J1939协议
1939和15765 硬件层面完全相同的,只不过1939规定了250K波特率通讯。
且用于商用车、卡车客车的网络通讯,是一种广播的网络形式,车上一般规定用6/14针脚-250K波特率进行通讯。
如下图,商用车中,
仪表、空调、后处理、行程记录仪、发动机、变速箱等等都要讲必要数据以广播形式发到CAN网络中。通常所见的车上仪表盘,其实就是监听和解析广播帧ID数据(车辆通信内容可以轻易破解)。
对于不同的车上模块,如何区分不同模块的数据,
第一个就是帧ID,以及PGN。
对于1939的PDU,帧ID和数据部分定义如下:
1)1939固定250K通讯,帧ID采用29bit,也即4个字节
2)帧ID第一个字节的5个有效bit中,
前3bit定义为P-仲裁优先级
第4和5bit定义为扩展数据页及数据页
3)帧ID第二个字节表示PF,即PDU格式
PF值区间为0~239(0x00~0xEF),则表明是PDU1格式,如区间为240~255(0xF0~0xFF),则表明是PDU2格式
4)帧ID第三个字节表示PS,PDU Specific
如为PUD1格式,则该场表示帧的目标地址,如为PDU2格式,则表示组扩展GE
5)帧ID第四个字节表示SA,即源地址
源地址即表示从哪来的,协议规定:00为发动机,3D为后处理,17/21为仪表,等等
那么简单的来说,PGN就是由PF和PS组成,即帧ID的第2/3字节。(完整的PGN定义由EDP+DP和PF、PS共三个字节组成,但是由于EDP和DP一般全部都为00,所以忽略了帧ID的第1字节)
实际应用场景中,就是监听车上广播ID,根据PGN规则和协议匹配对应的数据流或故障码解析规则,进而解析数据。
如商用车一般都有的0x0CF00400广播数据,其有效数据为8字节。对于PGN为 00F004。
可以根据ID直接匹配。以小端序提取其第4和5字节,除以80得到车上发动机的转速值。
同样的,1939协议中也有多帧数据,一般其内容是故障码数据,以及复杂或扩展数据。
PGN 00FECA 表示当前故障
PGN 00FECB 表示历史故障
PGN 00FECC 表示清除故障
车上多帧数据一般用两个帧ID表示,一个帧ID表示首帧,一个帧ID表示数据帧。
首帧不含有效数据,首字节一般为10或20表示不同的寻址方式,2/3字节表示长度,第4字节表示包数,5字节填充,6/7/8字节填充PGN。
数据帧首字节表示包数,剩余7字节为有效数据。