4、ELM327通信协议解析:AT指令集详解

好,咱们进入第四章。这一章可以说是整个OBD远程监控系统的“翻译官”环节。你想想看,你的单片机或者电脑,怎么跟车上的ECU(发动机控制单元)对话?靠的就是ELM327这个芯片,以及它背后那套AT指令集。

我个人习惯把ELM327理解成一个“黑盒子”。你给它发一串字符,它帮你翻译成CAN总线或K线信号发给车。车回数据了,它再翻译成你能看懂的ASCII码吐出来。说白了,它就是个人肉翻译机。

4.1 AT指令集详解:让ELM327“开口说话”

AT指令,全称是Attention指令。最早用在Modem上,后来被ELM327继承了下来。每条指令都以“AT”开头,回车符结尾。我刚开始接触时,总觉得这玩意儿跟老式拨号上网似的,哈哈。

4.1.1 最常用的三条指令:ATZ、ATSP、ATRV

ATZ:复位指令。相当于给ELM327重启一次。我在项目中遇到过,有时候ELM327跟ECU握手失败,卡死了。发一条ATZ,立马恢复。嗯,这招很管用。

ATSP:设置协议指令。SP是Set Protocol的缩写。车上的OBD协议有好几种:ISO 9141-2、ISO 14230-4(KWP2000)、ISO 15765-4(CAN)等等。ATSP后面跟数字,比如ATSP 0是自动检测,ATSP 5是CAN 11bit ID(标准帧),ATSP 6是CAN 29bit ID(扩展帧)。

我的小技巧: 如果你不确定车用哪种协议,先发ATSP 0让ELM327自动检测。但自动检测很慢,大概要3-5秒。我一般直接发ATSP 5,因为现在大部分车都是CAN总线了。如果没响应,再换ATSP 6。

ATRV:读取电压指令。RV是Read Voltage的缩写。这条指令返回ELM327的供电电压,也就是OBD接口第16脚的电压。正常应该在12V-14.5V之间。如果低于11V,说明电瓶亏电了。我曾经帮朋友排查过一辆车,启动困难,一测ATRV只有10.2V,果然是电瓶不行了。

指令 功能 返回示例 说明
ATZ 复位 ELM327 v1.5 重启芯片,清除所有设置
ATSP 5 设置CAN协议 OK 设置成CAN 11bit ID标准帧
ATRV 读取电压 12.6V 返回OBD接口供电电压

4.1.2 其他常用AT指令

  • ATE0 / ATE1:关闭/开启回显。ATE0关闭回显,你发什么它不回显什么,只返回数据。我习惯用ATE0,省得看一堆重复字符。
  • ATL0 / ATL1:关闭/开启换行。ATL0关闭换行,所有数据挤在一行。ATL1开启换行,每条响应单独一行。看个人喜好。
  • ATH0 / ATH1:关闭/开启响应头。ATH0关闭响应头,只返回数据部分。ATH1开启响应头,会返回类似“7E8 06 41 01 00 00 00 00”这样的完整帧。我一般用ATH0,解析起来简单。
  • ATDP:显示当前协议。返回当前使用的协议名称,比如“AUTO, ISO 15765-4 (CAN 11/500)”
注意: 有些ELM327的盗版芯片(比如CH340G方案的)对AT指令支持不完整。我曾经买过一个便宜的,ATRV死活返回不了电压。后来换了正版FTDI芯片的,一切正常。所以,硬件选型上别太省。

4.2 OBD-II请求帧结构:Service ID / PID

好了,ELM327已经设置好了。接下来我们要发真正的OBD请求了。OBD-II的请求帧结构很简单,就两个核心东西:Service ID(服务ID)和PID(参数ID)。

Service ID:代表你要做什么操作。比如Mode $01是请求当前数据,Mode $02是请求冻结帧数据,Mode $03是请求故障码,Mode $04是清除故障码等等。

PID:代表你要查哪个具体参数。比如PID $0C是发动机转速,PID $0D是车速,PID $11是节气门位置等等。

请求格式是:AT+[Service ID] [PID]。但注意,ELM327的AT指令里,发OBD请求不需要加“AT”前缀,直接发十六进制字符串就行。

举个例子:我想查发动机转速。Service ID是01,PID是0C。那么我发送:01 0C(注意中间有空格,ELM327会自动解析)。

请求帧结构总结:
格式:[Service ID] [PID]
示例:01 0C → 请求发动机转速
示例:01 0D → 请求车速
示例:01 11 → 请求节气门位置

4.3 响应帧解析:Mode $01 - $0A

车收到请求后,会返回一串十六进制数据。这串数据怎么读?我刚开始也懵,后来发现规律很简单。

以请求发动机转速为例。我发送01 0C,ELM327返回类似:41 0C 1A F8

解析规则:

  • 第一个字节:41。这个“4”代表响应,“1”代表Mode 01。所以41 = 响应Mode 01。
  • 第二个字节:0C。这就是PID,告诉你这是转速数据。
  • 第三、四个字节:1A F8。这是实际数据。转速的计算公式是:(A*256 + B) / 4。其中A=0x1A=26,B=0xF8=248。所以转速 = (26*256 + 248) / 4 = (6656 + 248) / 4 = 6904 / 4 = 1726 RPM。

嗯,1726转,怠速偏高了一点,但还算正常。

其他常用Mode的响应格式类似:

Mode 功能 响应首字节 数据格式说明
$01 请求当前数据 41 PID + 数据,按PID公式计算
$02 请求冻结帧数据 42 PID + 数据,格式同Mode 01
$03 请求故障码 43 返回DTC码,如P0101
$04 清除故障码 44 成功返回OK,无数据
$05 请求氧传感器测试 45 传感器ID + 数据
$06 请求车载监控测试 46 TID + 数据
$07 请求待定故障码 47 同Mode 03,但只显示待定码
$08 请求控制操作 48 用于执行特定操作(慎用)
$09 请求车辆信息 49 VIN码、校准ID等
$0A 请求永久故障码 4A 同Mode 03,但只显示永久码

4.4 常见错误码处理

跟车打交道,不可能每次都顺利。ELM327会返回一些错误码,告诉你哪里出问题了。我整理了几个最常见的:

  • NO DATA:没数据。说明ECU没响应。原因可能是:协议没设对、车没上电、或者ELM327跟ECU之间的线路有问题。我遇到过最奇葩的一次,是OBD接口的针脚氧化了,接触不良。拿酒精擦一擦就好了。
  • BUS BUSY:总线忙。说明CAN总线正在被其他设备占用。等一会儿重试就行。我一般加个100ms的延时再发。
  • BUS ERROR:总线错误。说明CAN总线有硬件故障,比如终端电阻坏了、或者CANH/CANL短路了。这个比较麻烦,需要查硬件。
  • ?:问号。说明ELM327不认识你发的指令。检查一下AT指令拼写有没有错,或者是不是发了不支持的指令。
  • UNABLE TO CONNECT:无法连接。说明ELM327跟ECU握手失败。先发ATZ复位,再重新设置协议试试。
避坑指南: 我曾经在项目里遇到一个坑:ELM327返回“NO DATA”,但车明明在跑。查了半天,发现是ATSP设成了自动检测,但自动检测超时时间太短。后来我改成ATSP 5(强制CAN协议),问题解决。所以,如果你确定车是CAN总线,别用自动检测,直接指定协议。

好了,这一章的内容就这些。AT指令是基础,OBD请求帧是核心,响应解析是技能,错误码处理是经验。把这四块吃透了,ELM327这块就基本拿下了。下一章,咱们开始动手写代码,把ELM327跟单片机连起来,真正实现远程监控。