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(扩展帧)。
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)”
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复位,再重新设置协议试试。
好了,这一章的内容就这些。AT指令是基础,OBD请求帧是核心,响应解析是技能,错误码处理是经验。把这四块吃透了,ELM327这块就基本拿下了。下一章,咱们开始动手写代码,把ELM327跟单片机连起来,真正实现远程监控。