最后修改:
J2534(通常称为 Pass-Thru)是由 SAE(汽车工程师学会)制定的标准,它解决了一个重要问题:让同一款诊断软件能够与不同制造商的诊断适配器协同工作。
核心理念:
设想您要编写一款汽车诊断程序。如果没有 J2534 标准,您就必须为每一种希望支持的适配器(K-Line、CAN 适配器等)编写独立的代码。这既复杂又昂贵。
J2534 标准定义了统一的 API(程序接口),适配器制造商必须在其驱动程序中实现该接口。该标准仅将此 API 定义为 Windows 平台的 DLL 库
对开发者而言,这意味着:
PassThruOpen、PassThruReadMsg)。因此,J2534 是您的应用程序与诊断适配器之间的“桥梁”,它隐藏了具体硬件的复杂性,让您能够专注于诊断逻辑。
许多开发者除 Windows 之外还希望使用其他平台。除了 Windows 平台的标准 DLL,我们还提供面向 Linux、macOS 以及移动平台 Android 和 iOS 的库。
必须明确,J2534 是传输层标准。它负责通过所选物理接口(CAN、K-Line 等)完成所有数据字节的收发工作。
然而,J2534 标准并不定义:
这些仍属于您应用程序的任务。作为开发者,您必须知道应当发送哪些字节才能请求例如故障码或当前参数,以及如何解析控制单元的响应。
为此,您需要掌握诊断应用层协议的知识,例如:
J2534 DLL 会把您的字节送达 ECU,但这些字节是什么、收到响应后如何处理,则由您的程序决定。
J2534 标准是规范汽车诊断的庞大标准家族中的一部分。为深入理解,建议参阅官方文档。
ScanDoc 适配器实现的并非完整的 J2534-1 标准,以及 J2534-2 的部分扩展,同时还具有用于增强功能的专有函数。
J2534 标准定义了一组物理层和传输层协议,通过它们与汽车 ECU 进行数据交换。下面介绍 ScanDoc 适配器支持的每个协议。
用于现代汽车诊断的主要协议。ISO 15765(也称为 ISO-TP)在 CAN 总线之上实现了传输层:它会自动将长报文分段为 CAN 帧、进行流控制(Flow Control)并从多个帧重组响应。
正是这一协议被用于在 CAN 总线上进行 UDS(ISO 14229)和 OBD-II 诊断。如果您的任务是发送诊断请求并接收 ECU 的响应,请使用 ISO15765。
CAN_29BIT_ID 标志FLOW_CONTROL_FILTER(每通道最多 16 个)ISO15765_ADDR_TYPE 标志// 以 500 kbit/s 通过 ISO 15765 连接
PassThruConnect(deviceID, ISO15765, 0, 500000, &channelID);
CAN 协议提供对不带传输层的原始 CAN 帧流的访问。每条报文即一个 CAN 帧(最多 8 字节数据)。适配器不执行分段和重组——您按原样收发帧。
当您需要直接操作 CAN 总线时,请使用该协议:监控流量、发送单独的帧、处理基于 CAN 的非标准协议。
CAN_29BIT_ID 标志PASS_FILTER 和 BLOCK_FILTER(每种类型最多 10 个)// 以 500 kbit/s、29 位 ID 连接 CAN
PassThruConnect(deviceID, CAN, CAN_29BIT_ID, 500000, &channelID);
基于 K 线的诊断协议,广泛应用于 2000 年代的汽车(尤其是欧洲车型)。支持两种连接初始化方式:5 波特(慢速)和快速(fast init)。初始化完成后,按与 ECU 协商的速率进行通信。
用于 KWP2000 经销商级诊断以及基于 K 线的 OBD-II 诊断。
PassThruIoctl 进行 5 波特(FIVE_BAUD_INIT)或快速(FAST_INIT)初始化ISO9141_K_LINE 标志:若设置,则仅通过 K 线进行初始化(不使用 L 线)SET_CONFIG 配置// 以 10400 波特通过 ISO 14230 连接,仅 K 线
PassThruConnect(deviceID, ISO14230, ISO9141_K_LINE, 10400, &channelID);
较早的 K 线协议,由 ISO 9141-2 标准定义。用于老旧汽车的 OBD-II 诊断(视地区而定,约为 2004-2008 年之前)。仅支持 5 波特初始化。
FIVE_BAUD_INIT 进行 5 波特初始化// 以 10400 波特通过 ISO 9141 连接
PassThruConnect(deviceID, ISO9141, 0, 10400, &channelID);
采用可变脉宽调制(Variable Pulse Width)的协议,曾用于 General Motors 汽车的 OBD-II 诊断。通过单根导线以 10.4 kbit/s 的速率工作。
// 通过 J1850 VPW 连接
PassThruConnect(deviceID, J1850VPW, 0, 10400, &channelID);
采用脉宽调制(Pulse Width Modulation)的协议,曾用于 Ford 汽车的 OBD-II 诊断。通过两根导线以 41.6 kbit/s 的速率工作。
// 通过 J1850 PWM 连接
PassThruConnect(deviceID, J1850PWM, 0, 41600, &channelID);
从您的应用程序操作 J2534 适配器通常遵循以下流程:
每家 J2534 适配器制造商都以 DLL 文件的形式提供其 API 实现。安装驱动时,关于该 DLL 的信息(文件路径)会写入 Windows 注册表。
您的应用程序应当:
LoadLibrary 函数(在 Windows 中)将相应的 DLL 加载到内存。在加载 DLL 并获取函数指针之后,一次典型的诊断会话如下所示:
PassThruOpen() 函数以初始化与物理设备的通信。作为响应,您将获得 DeviceID——此会话的唯一标识符。
// 示例
unsigned long deviceID;
long result = PassThruOpen(NULL, &deviceID);
PassThruConnect() 以按特定协议(例如用于 CAN 总线的 ISO15765)建立与车辆的逻辑通信通道。您需要指定协议、速率及其他参数。作为响应,您将获得 ChannelID。
// 示例
unsigned long channelID;
result = PassThruConnect(deviceID, ISO15765, 0, 500000, &channelID);
PassThruStartMsgFilter() 函数。
数据交换过程是异步的,并基于队列:
PassThruWriteMsg() 函数并不会立即将报文发送到总线。相反,它会将一条或多条报文放入发送队列并立即返回控制权。适配器驱动会在条件允许时自行从队列中发送这些报文。PassThruReadMsg() 函数用于从该队列中取出报文。重要提示:J2534 库是单线程的。这意味着对同一通道的所有函数调用(PassThruWriteMsg、PassThruReadMsg 等)都必须严格按顺序执行。在上一个函数执行完成之前,不能调用另一个函数。试图从不同线程对同一通道同时调用函数将导致不可预测的行为。
PassThruDisconnect() 关闭通道。
// 示例
result = PassThruDisconnect(channelID);
PassThruClose() 以释放设备。
// 示例
result = PassThruClose(deviceID);
这一循环是任何 J2534 应用程序的基础。后续章节将详细介绍每个 API 函数及其参数。
每个 J2534 API 函数都会返回一个状态码。执行成功时始终返回 STATUS_NOERROR(值为 0)。任何其他值都表示某个具体错误(例如 ERR_TIMEOUT、ERR_INVALID_CHANNEL_ID 等)。
在每次函数调用之后检查返回值至关重要。
有一个特殊的错误码——ERR_FAILED。这是一个通用的、非特定的错误。仅在此情况下才应调用 PassThruGetLastError() 函数,以从驱动获取对问题更详细的文本描述。
// 正确的错误处理示例
long result = PassThruConnect(deviceID, ISO15765, 0, 500000, &channelID);
if (result != STATUS_NOERROR)
{
printf("PassThruConnect 出错。代码: %ld\n", result);
// 如果是通用错误,则请求详细信息
if (result == ERR_FAILED)
{
char errorDescription[80];
PassThruGetLastError(&errorDescription[0], 80);
printf(" 附加信息: %s\n", errorDescription);
}
// 此处可以放置处理其他错误代码的逻辑
// switch (result) { case ERR_TIMEOUT: ... }
return; // 中断执行
}
J2534 标准每个函数的详细说明已整理至函数参考。