CCP通信协议:主从式,主设备通过CAN总线与多台从设备相连,主设备室测量标定系统 ,从设备是需要标定的ECU,主设备首先与其中一个从设备建立逻辑连接,主、从设备之间的所有的数据传递均由主机控制,从设备执行主设备命令后返回包含命令响应值或错误代码等信息的报文,同时从设备可以根据主设备通过控制命令设置的列表信息来定时地向主设备传送变量信息,数据的传递是由主设备初始化并且从设备来执行的,并且是由固定的循环采样频率或者事件触发的。
主设备通过USB-CAN接口与从设备连接,符合CAN2.0协议。
通信过程中,所有报文均为8个字节,包括命令、数据、数据长度、地址等信息
该通信协议参照CCP协议,可以与INCA等标定软件接口。
CAN通信:采用两个报文数据对象 CRO和DTO (命令接收对象)(命令发送对象)每个对象根据其数据流向,都有一个唯一的ID标示符进行标示,ID标识符可以由用户自己设定。
命令接收对象(CRO):
用于传递指令代码和内部功能码或主、从设备之间交换的存储区数据
表1
CMD (1 Byte): | 命令代码。 |
CTR (1 Byte): | 命令计数器。 |
Parameter and Data(6 Byte): | 参数和数据场,命令相关的数据或参数 |
数据接收对象(DTO):
数据传输对象(DTO)指由从设备反馈的报文。DTO根据报文首字节PID的值可以由三种形式,见表2:
PID值 | 数据传输类型 | 备注 |
0xFF | CRM(Command Return Message) | 由从设备发送,反馈CRO命令的报文 |
0xFE | Event Message | 当从设备检测到内部发生错误机制时,由从设备自行向主设备发送,报告其当前的运行状态,并请求主设备暂停当前工作进程以处理发生的错误 |
0-0xFD | DAQ-DTO(Data Acquisition-DTO) | 用于DAQ模式,由从设备定期向主设备发送。 根据对象描述表(ODT),确定需要上传的变量 |
CRM-Event Message报文帧格式
表3:场说明
PID(1 Byte) | 其值代表了DTO的类型 |
ERR(1 Byte) | 命令返回错误代码 |
CTR(1 Byte) | 命令计数器,与接收的相等。 |
Parameter and Data Field | 参数和数据场,命令相关的数据或参数 |
(2). DAQ-DTO(Data Acquisition-DTO)的报文帧:
3. 协议命令列表及说明(标注绿色字体部分逐步补充完整)
3.1 命令列表:
命令名称 | 代码 | 说明 |
CONNECT | 0x01 | 创建一个ECU的连接 |
0x02 | 设置MTA地址 | |
0x03 | 下载最多5个字节数据到ECU | |
DNLOAD_6 | 0x23 | 下载6个字节数据到ECU |
UPLOAD | 0x04 | 从ECU上载最多5个字节数据 |
SHORT_UP | 0x0F | 从ECU上载最多5个数据(不用MTA) |
DISCONNECT | 0x07 | 断开到该ECU的连接 |
GET_DAQ_SIZE | 0x14 | 得到指定DAQ列表大小 |
SET_DAQ_PTR | 0x15 | 选中某指定DAQ列表中某ODT的某元素 |
WRITE_DAQ | 0x16 | 设定该元素指定的地址 |
START_STOP | 0x06 | 开始/停止采集指定的DAQ列表 |
EXCHANGE_ID | 0x17 | 得到该ECU的标识符 |
GET_SEED | 0x12 | 得到计算密钥的种子(SEED) |
UNLOCK | 0x13 | 要求ECU释放某种功能 |
SET_S_STATUS | 0x0C | 设置当前会话状态 |
GET_S_STATUS | 0x0D | 得到当前会话状态 |
BUILD_CHKSUM | 0x0E | 计算指定区域的校验和 |
CLEAR_MEMORY | 0x10 | 清除某内存区域 |
0x18 | FLASH编程(最多5个字节) | |
PROGRAM_6 | 0x22 | FLASH编程(6个字节) |
MOVE | 0x19 | 从MTA0处拷贝指定长度的字节到MTA1处 |
TEST | 0x05 | 测试当前在线的从设备 |
GET_ACTIVE_CAL_PAGE | 0x09 | 得到当前标定页(RAM or FLASH) |
DIAG_SERVICE | 0x20 |
|
ACTION_SERVICE | 0x21 |
|
3.2命令返回错误代码
代码 | 描述 | 种类 | 状态改变 |
0x00 | 正确接收,无错误 |
|
|
0x01 | DAQ处理器过载 |
|
|
0x10 | 命令处理器忙 |
|
|
0x11 | DAQ处理器忙 |
|
|
。。。 | 待续 |
|
|
3.3命令详细说明
3.3.1CONNECT命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x01) |
1 | 字节 | 命令计数器 |
2 | 字 | 站地址 |
4-7 | 字节 | 填0(不关心) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
程序:connect命令
UINT8 Connect(UINT16 wStationAddr) {
UINT8pbCROData[8];
pbCROData[0] = CC_CONNECT;
pbCROData[1] = m_bCTR ++;
// intel format
pbCROData[2] = (UINT8)(wStationAddr &0xFF);
pbCROData[3] = (UINT8)(wStationAddr >> 8);
// don't care
pbCROData[4] = 0x00;
pbCROData[5] = 0x00;
pbCROData[6] = 0x00;
pbCROData[7] = 0x00;
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 don't care
if (CRC_OK == pbDTOData[1]) {
m_bConnected = TRUE;
}
return pbDTOData[1];
}
3.3.2SET_MTA命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x02) |
1 | 字节 | 命令计数器 |
2 | 字节 | 存贮器传输地址(MTA0,MTA1) |
3 | 字节 | 地址扩展 |
4-7 | 无符号长整形 | 地址 |
数据传送对象(DTO):
0 | 字节 | 命令代码(0x01) |
1 | 字节 | 命令计数器 |
2 | 字 | 站地址 |
4-7 | 字节 | 填0(不关心) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
3.3.2SET_MTA命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x02) |
1 | 字节 | 命令计数器 |
2 | 字节 | 存贮器传输地址(MTA0,MTA1) |
3 | 字节 | 地址扩展 |
4-7 | 无符号长整形 | 地址 |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
UINT8SetMTA(UINT8 bMTANumber, UINT8 bAddrExt, UINT32 dwAddr) {
UINT8pbCROData[8];
pbCROData[0]= CC_SET_MTA;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bMTANumber;
pbCROData[3] = bAddrExt;
pbCROData[4] = (UINT8)(dwAddr >> 24);
pbCROData[5] = (UINT8)(dwAddr >> 16);
pbCROData[6] = (UINT8)(dwAddr >> 8);
pbCROData[7] = (UINT8)(dwAddr >> 0);
UINT8bRlt;
UINT8pbDTOData[8];
// if (CRC_OK != (bRlt = SendMessage(pbCROData, pbDTOData,TRANSMIT_TIMEOUT))) {
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, 2000))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 don't care
return pbDTOData[1];
}
3.3.3 DNLOAD命令:
数据类型 | 描述 | |
0 | 字节 | 命令代码(0x03) |
1 | 字节 | 命令计数器 |
2 | 字节 | 需下传的数据长度 |
3-7 | 字节 | 数据 |
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3 | 字节 | MTA0扩展位 |
4-7 | 字节 | 执行后MTA0地址(即地址加上长度) |
UINT8Download(UINT8 &bSize, PUINT8 pbData, UINT8 &bExtAddr, UINT32&dwAddr) {
UINT8pbCROData[8];
UINT8i;
pbCROData[0] = CC_DNLOAD;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bSize;
if ((NULL == pbData)) {
return CRC_CMD_SYNTAX;
}
if (bSize > 5) {
bSize = 5;
}
for (i = 0; i < bSize; i ++) {
pbCROData[3 + i] = pbData[i];
}
for (; i < 5; i ++) {
pbCROData[3 + i] = 0x00;
}
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3 MTA0 extension (after post-increment)
// 4..7 MTA0 address (after post-increment)
bExtAddr = pbDTOData[3];
dwAddr= (((UINT32)pbDTOData[4]) << 24) ||
(((UINT32)pbDTOData[5]) << 16) ||
(((UINT32)pbDTOData[6]) << 8) ||
(((UINT32)pbDTOData[7]) << 0);
return pbDTOData[1];
}
3.3.4UPLOAD命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x04) |
1 | 字节 | 命令计数器 |
2 | 字节 | 需上传的数据长度 |
3-7 | 字节 | 填0 |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 上传的数据 |
UINT8 Upload(UINT8 &bSize, PUINT8 pbData) {
UINT8pbCROData[8];
UINT8i;
if ((NULL == pbData)) {
return CRC_CMD_SYNTAX;
}
if (bSize > 5) {
bSize = 5;
}
pbCROData[0]= CC_UPLOAD;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bSize;
// don't care
pbCROData[3] = 0x00;
pbCROData[4] = 0x00;
pbCROData[5] = 0x00;
pbCROData[6] = 0x00;
pbCROData[7] = 0x00;
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 requested data bytes
for (i = 0; i < bSize; i ++) {
pbData[i] = pbDTOData[3 + i];
}
return pbDTOData[1];
}
3.3.5 SHORT UPLOAD命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x0F) |
1 | 字节 | 命令计数器 |
2 | 字节 | 需上传的数据长度 |
3 | 字节 | 地址扩展 |
4-7 | 字节 | 地址 |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 上传的数据 |
3.3.6DISCONNECT命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x07) |
1 | 字节 | 命令计数器 |
2 | 字节 | 0x00 暂时断开, 0x01 断开 |
3 | 字节 | 不关心 |
4-5 | 字节 | 站地址(低位在前) |
6-7 | 字节 | 填0(不关心) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
UINT8 ShortUpload(UINT8 bSize, UINT8 bAddrExt, UINT32dwAddr, PUINT8 pbData) {
UINT8pbCROData[8];
UINT8i;
if ((NULL == pbData)) {
return CRC_CMD_SYNTAX;
}
if (bSize > 5) {
bSize = 5;
}
pbCROData[0] = CC_SHORT_UPLOAD;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bSize;
pbCROData[3] = bAddrExt;
pbCROData[4] = (UINT8)(dwAddr >> 24);
pbCROData[5] = (UINT8)(dwAddr >> 16);
pbCROData[6] = (UINT8)(dwAddr >> 8);
pbCROData[7] = (UINT8)(dwAddr >> 0);
UINT8bRlt;
UINT8pbDTOData[8];
if(CRC_OK != (bRlt = SendPackage(pbCROData, pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 requested data bytes
for (i = 0; i < bSize; i ++) {
pbData[i] = pbDTOData[3 + i];
}
return pbDTOData[1];
}
3.3.7GET_DAQ_SIZE命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x14) |
1 | 字节 | 命令计数器 |
2 | 字节 | DAQ表号(0,1…) |
3 | 字节 | 填0(不关心) |
4-7 | 字节 | CAN 识别号(可选,暂不使用) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3 | 字节 | 该DAQ列表中ODT的数目 |
4 | 字节 | 该列表中第一个ODT表PID值 |
5-7 | 字节 | 填0(不关心) |
UINT8pbCROData[8];
pbCROData[0] = CC_GET_DAQ_SIZE;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bListNum;
// don't care
pbCROData[3]= 0x00;
pbCROData[4] = (UINT8)(dwCANId >> 24);
pbCROData[5] = (UINT8)(dwCANId >> 16);
pbCROData[6] = (UINT8)(dwCANId >> 8);
pbCROData[7] = (UINT8)(dwCANId >> 0);
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3 DAQ list size (= number of ODTs in this list)
// 4 Fisrt PID of DAQ list
// 5..7 don't care
bDAQListSize = pbDTOData[3];
bFirstPID = pbDTOData[4];
return pbDTOData[1];
}
3.3.8SET_DAQ_PTR命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x15) |
1 | 字节 | 命令计数器 |
2 | 字节 | DAQ表号(0,1…) |
3 | 字节 | QDT表号(0,1…) |
4 | 字节 | ODT表里的元素(0,1…) |
5-7 | 字节 | 填0(不关心) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
UINT8pbCROData[8];
pbCROData[0] = CC_SET_DAQ_PTR;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bListNum;
pbCROData[3] = bODTNum;
pbCROData[4] = bElementNum;
pbCROData[5]= 0x00;
pbCROData[6] = 0x00;
pbCROData[7] = 0x00;
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 don't care
return pbDTOData[1];
3.3.9WTITE_DAQ命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x16) |
1 | 字节 | 命令计数器 |
2 | 字节 | DAQ表中元素的长度(1,2,4) |
3 | 字节 | 表中元素的扩展地址 |
4-7 | 字节 | 表中元素的地址 |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
UINT8 pbCROData[8];
pbCROData[0] = CC_WRITE_DAQ;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bElementSize;
pbCROData[3] = bAddrExt;
pbCROData[4] = (UINT8)(dwAddr >> 24);
pbCROData[5] = (UINT8)(dwAddr >> 16);
pbCROData[6] = (UINT8)(dwAddr >> 8);
pbCROData[7] = (UINT8)(dwAddr >> 0);
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 don't care
return pbDTOData[1];
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x06) |
1 | 字节 | 命令计数器 |
2 | 字节 | 停止:0x00;启动:0x01;准备:0x02 |
3 | 字节 | DAQ 列表数 |
4 | 字节 | 该DAQ列表中最后一张ODT表数 |
5 | 字节 | 触发事件数 |
6-7 | 字 | 发送速率分频系数 |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
UINT8 pbCROData[8];
pbCROData[0] = CC_START_STOP;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bMode;
pbCROData[3] = bDAQNum;
pbCROData[4] = bLastODTNum;
pbCROData[5] = bEventChannelNo;
pbCROData[6] = (UINT8)(wTransmissionRatePrescaler >> 8);
pbCROData[7] = (UINT8)(wTransmissionRatePrescaler >> 0);
UINT8bRlt;
UINT8pbDTOData[8];
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, TRANSMIT_TIMEOUT))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 don't care
return pbDTOData[1];
3.3.11CLEAR_MEMORY命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x10) |
1-7 | 字节 | 填0(不关心) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
3.3.12PROGRAM命令:
命令接收对象(CRO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0x18) |
1-7 | 字节 | 填0(不关心) |
数据传送对象(DTO):
位(bit) | 数据类型 | 描述 |
0 | 字节 | 命令代码(0xFF) |
1 | 字节 | 命令返回代码 |
2 | 字节 | 命令计数器 |
3-7 | 字节 | 填0(不关心) |
4、标定实现(举例)
建立完善的匹配标定具体流程为:与底层ECU进行连接,监控、在线标定,上载和下载map图,断开连接等操作。对于匹配标定的2个最主要的任务,就是在线标定和实时监控,它是通过协议命令的组合,来实现的,下面举例说明如何实现:
4.1监控命令解析:(假设有n张DAQ列表,每张列表中有m张ODT表)
序号 | 上位机 | CCP | CAN | 备注 |
1 | 设置监控变量列表,选择采样速率 |
|
| (.A2L) |
2 |
| GET_DAQ_SIZE | 发送 | 重复n次 |
3 |
| CRM-DTO | 接收 | 重复n次 |
4 |
| SET_DAQ_PTR | 发送 | list 0~list m-1 |
5 |
| CRM-DTO | 接收 | list 0~list m-1 |
6 |
| WRITE_DAQ | 发送 | list 0~list m-1 |
7 |
| CRM-DTO | 接收 | list 0~list m-1 |
8 |
| START_STOP | 发送 | list 0~list n-1 |
9 |
| CRM-DTO | 接收 | list 0~list n-1 |
10 |
| START_STOP_ALL | 发送 | 开始监控 |
11 |
| CRM-DTO | 接收 |
|
12 |
| DAQ-DTO | 接收 | 接收多次 |
13 | 显示 |
|
| 解码显示 |
14 |
| START_STOP_ALL | 发送 | 停止显示 |
15 |
| CRM-DTO | 接收 |
|
4.2 在线标定
标号 | 上位机 | CCP | CAN | 备注 |
1 | 修改数据 |
|
| 可能有n次 |
2 |
| SET_MTA | 发送 |
|
3 |
| CRM-DTO | 接收 |
|
4 |
| DNLOAD | 发送 |
|
5 |
| CRM-DTO | 接收 |
|
6 |
| SHORT_UP | 发送 |
|
7 |
| CRM-DTO | 接收 |
|
SETMTA 命令:
UINT8SetMTA(UINT8 bMTANumber, UINT8 bAddrExt, UINT32 dwAddr) {
UINT8pbCROData[8];
pbCROData[0]= CC_SET_MTA;
pbCROData[1] = m_bCTR ++;
pbCROData[2] = bMTANumber;
pbCROData[3] = bAddrExt;
pbCROData[4] = (UINT8)(dwAddr >> 24);
pbCROData[5] = (UINT8)(dwAddr >> 16);
pbCROData[6] = (UINT8)(dwAddr >> 8);
pbCROData[7] = (UINT8)(dwAddr >> 0);
UINT8bRlt;
UINT8pbDTOData[8];
// if (CRC_OK != (bRlt = SendMessage(pbCROData, pbDTOData,TRANSMIT_TIMEOUT))) {
if (CRC_OK != (bRlt = SendPackage(pbCROData,pbDTOData, 2000))) {
return bRlt;
}
// Response
// 0 Packet ID: 0xFF
// 1 Command Return Code
// 2 Command Counter = CTR
// 3..7 don't care
return pbDTOData[1];
}