0xCAFEDECAF/VanBus
GitHub: 0xCAFEDECAF/VanBus
VanBus 是一个用于读写 PSA 车辆 VAN 总线数据包的 Arduino 库。
Stars: 74 | Forks: 14
PSA (标致、雪铁龙) VAN 总线读写器(适用于 Arduino-ESP8266 和 ESP32)
读取和写入 PSA 车辆 VAN 总线上的数据包。
[](https://github.com/0xCAFEDECAF/VanBus/releases/latest/)
[](https://github.com/0xCAFEDECAF/VanBus/releases/latest/)
[](https://www.ardu-badge.com/VanBus)
[](https://www.arduino.cc/)
[](https://github.com/0xCAFEDECAF/VanBus/actions/workflows/arduino-lint.yml)
[](https://github.com/0xCAFEDECAF/VanBus/actions/workflows/compile.yml)
## 📝 目录
- [描述](#description)
- [原理图](#schematics)
- [构建您的项目](#building)
- [使用](#usage)
- [概述](#general)
- [功能函数](#functions)
- [待完成工作](#todo)
- [许可证](#license)
## 🎈 描述
此模块允许您在您的标致或雪铁龙车辆的 ["VAN" 总线] 上接收和发送数据包。
在 2000 年代初期,PSA 集团(标致和雪铁龙)使用 VAN 总线作为
各种舒适性相关设备之间的通信协议。后来,大约在 2005 年,他们开始在其新车型中使用 CAN 总线协议替代此协议,然而某些车型直到 2009 年仍在使用 VAN 总线。
[此概述](https://github.com/morcibacsi/PSAVanCanBridge#compatibility) 列出了据称
配备 VAN(舒适)总线的车辆。
此库支持 ESP8266 / ESP8285 和 ESP32 平台。
## 🔌 原理图
通常可以在您主机(汽车音响)的 ISO "A" 接口模块的引脚 2 和 3 上找到 VAN 总线。参见
http://web.archive.org/web/20230315215552/https://en.wikipedia.org/wiki/Connectors_for_car_audio 以及
https://github.com/morcibacsi/esp32_rmt_van_rx#schematics 。
有多种方式将基于 ESP8266/ESP32 的开发板连接到您车辆的 VAN 总线:
1. 使用 [MCP2551] 收发器,将其 CANH 和 CANL 引脚连接到车辆的 VAN 总线。
由于 MCP2551 具有 5V 逻辑,需要一个 5V ↔ 3.3V [电平转换器] 将收发器的 CRX / RXD / R 引脚通过电平转换器连接到您的 ESP8266/ESP32 开发板的 GPIO 引脚。对于发送数据包,还需将收发器的 CTX / TXD / D 引脚通过电平转换器连接到您的 ESP8266/ESP32 开发板的 GPIO 引脚。
搭载 MCP2551 收发器的开发板可以在例如
[这里](https://domoticx.net/webshop/can-bus-classic-20b-transceiver-module-5v-uart-mcp2551/) 或
[这里](https://nl.aliexpress.com/item/1005004475976642.html) 订购。
使用 [Wemos D1 mini](基于 ESP8266)的示例原理图:

使用 [LilyGO TTGO T7 Mini32](基于 ESP32)的示例原理图:

2. 使用 [SN65HVD230] 收发器,将其 CANH 和 CANL 引脚连接到车辆的 VAN 总线。
SN65HVD230 收发器已具备 3.3V 逻辑,因此可以直接将收发器的 CRX / RXD / R 引脚连接到您的 ESP8266/ESP32 开发板的 GPIO 引脚。对于发送数据包,还需将收发器的 CTX / TXD / D 引脚连接到您的 ESP8266/ESP32 开发板的 GPIO 引脚。
搭载 SN65HVD230 收发器的开发板可以在例如
[这里](https://domoticx.net/webshop/can-bus-classic-20b-transceiver-module-33v-uart-sn65hvd230-vp230/),
[这里](https://domoticx.net/webshop/can-bus-classic-20b-transceiver-module-33v-uart-sit65hvd230dr-tvs-esd-protection-domoticx-experience-ect01-v1/) 或
[这里](https://eu.robotshop.com/products/waveshare-can-board-sn65hvd230) 订购。

3. 最简单的原理图是完全不使用收发器,而是使用两个 4.7 kOhm 电阻将 VAN 数据线连接到地。将您的 ESP8266/ESP32 开发板的 GPIO 引脚连接到由这两个电阻形成的 1:2 [分压器]。这仅用于接收数据包,不用于发送。结果可能有所不同。

## 🚀 构建您的项目
在继续此项目之前,请确保检查以下所有先决条件。
### 安装 Arduino IDE
参见 [Arduino IDE](https://www.arduino.cc/en/software)。我目前使用的是
[版本 1.8.19](https://downloads.arduino.cc/arduino-1.8.19-windows.exe),但其他版本
可能也能正常工作。
### 基于 ESP8266 的开发板
一个基于 ESP8266 的开发板示例是 [Wemos D1 mini]。
#### 1. 在 Arduino IDE 中安装开发板支持包
对于基于 ESP8266 的开发板,您需要安装
[ESP8266 开发板支持包](https://arduino-esp8266.readthedocs.io/en/stable/installing.html)。
我目前使用的是 [版本 3.1.2](https://github.com/esp8266/Arduino/releases/tag/3.1.2),但其他版本
似乎也能正常工作(我测试过 2.6.3 ... 3.1.2 版本)。
按照 [此教程](https://randomnerdtutorials.com/how-to-install-esp8266-board-arduino-ide/) 安装
ESP8266 开发板支持包。
#### 2. 安装 VAN Bus 库
在 Arduino IDE 中,转到 "Sketch" 菜单 → "Include Library" → "Manage Libraries..." 并安装
[车辆局域网 (VAN) 总线数据包读写器](https://github.com/0xCAFEDECAF/VanBus) 库。提示:
在搜索框中输入 "vanbus"。
有关使用 Arduino 库管理器的更多说明,您可以浏览:
* 此 [Arduino 教程](https://docs.arduino.cc/software/ide-v1/tutorials/installing-libraries),以及
* 此 [Adafruit 的说明](https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use/library-manager)
#### 3. 开发板设置
在 Arduino IDE 中,转到 "Tools" 菜单,并选择:
* CPU 频率:160 MHz
以下是经过测试可正常工作的开发板设置图片:

### 基于 ESP32 的开发板
一个基于 ESP32 的开发板示例是 [LilyGO TTGO T7 Mini32]。
#### 1. 在 Arduino IDE 中安装开发板支持包
对于基于 ESP32 的开发板,您需要安装 ESP32 开发板支持包。
我目前使用的是 [版本 3.3.5](https://github.com/espressif/arduino-esp32/releases/tag/3.3.5),但其他版本
可能也能正常工作。(我测试过版本 1.0.6, 2.0.17 和 3.3.5。)
按照 [此教程](https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/)
安装 ESP32 开发板支持包。或者,转向
[此页面](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html) 获取说明。
#### 2. 安装 VAN Bus 库
参见上文 ['安装 VAN Bus 库' 部分](#install_library)。
#### 3. 开发板设置
在 Arduino IDE 中,转到 "Tools" 菜单,并选择:
* CPU 频率:240 MHz
以下是经过测试可正常工作的开发板设置图片:

## 🧰 使用
### 概述
将以下行添加到您的 ```.ino``` 草图中:
```
#include
```
对于接收和发送数据包:
1. 将以下行添加到您的初始化代码块 ```void setup()``` 中:
```
int TX_PIN = D3; // GPIO pin connected to VAN bus transceiver input
int RX_PIN = D2; // GPIO pin connected to VAN bus transceiver output
TVanBus::Setup(RX_PIN, TX_PIN);
```
2. 例如,将以下行添加到您的主循环 ```void loop()``` 中:
```
TVanPacketRxDesc pkt;
if (VanBus.Receive(pkt)) pkt.DumpRaw(Serial);
uint8_t rmtTemperatureBytes[] = {0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x70};
VanBus.SyncSendPacket(0x8A4, 0x08, rmtTemperatureBytes, sizeof(rmtTemperatureBytes));
```
如果您只想接收数据包,可以通过直接使用 ```VanBusRx``` 对象节省几百个宝贵的字节:
1. 将以下行添加到您的初始化代码块 ```void setup()``` 中:
```
int RX_PIN = D2; // GPIO pin connected to VAN bus transceiver output
VanBusRx.Setup(RX_PIN);
```
2. 将以下行添加到您的主循环 ```void loop()``` 中:
```
TVanPacketRxDesc pkt;
if (VanBusRx.Receive(pkt)) pkt.DumpRaw(Serial);
```
### ```VanBus``` 对象
```VanBus``` 对象提供以下方法:
用于接收和发送数据包的接口:
1. [```void Setup(uint8_t rxPin, uint8_t txPin)```](#setup)
2. [```void DumpStats(Stream& s, bool longForm = true)```](#dumpstats)
用于接收数据包的接口:
3. [```bool Available()```](#available)
4. [```bool Receive(TVanPacketRxDesc& pkt, bool* isQueueOverrun = NULL)```](#receive)
5. [```uint32_t GetRxCount()```](#getrxcount)
6. [```int QueueSize()```](#queuesize)
7. [```int GetNQueued()```](#getnqueued)
8. [```int GetMaxQueued()```](#getmaxqueued)
9. [```void SetDropPolicy(int startAt, bool (*isEssential)(const TVanPacketRxDesc&) = 0)```](#setdroppolicy)
用于发送数据包的接口:
10. [```bool SyncSendPacket(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)```](#syncsendpacket)
11. [```bool SendPacket(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)```](#sendpacket)
12. [```uint32_t GetTxCount()```](#gettxcount)
#### 1. ```void 设置(uint8_t rxPin, uint8_t txPin)```
在 GPIO 引脚 ```rxPin``` 上启动接收器监听。发射器将在 GPIO 引脚 ```txPin``` 上发送。
#### 2. ```void 导出统计(Stream& s, bool longForm = true)```
将一些数据包统计信息转储到传递的流中。向 `longForm` 参数传递 **false** 将生成简短形式。
#### 3. ```bool 可用()```
如果接收队列中有可用的 VAN 数据包,则返回 ```true```。
#### 4. ```bool 接收(TVanPacketRxDesc& pkt, bool* isQueueOverrun = NULL)```
如果可用,从接收队列中复制一个 VAN 数据包。否则,返回 ```false```。
如果向 'isQueueOverrun' 传递了有效指针,则会报告并清除任何队列溢出条件。
#### 5. ```uint32_t 获取接收计数()```
返回自开机以来接收的 VAN 数据包数量。计数器可能会溢出回绕。
#### 6. ```int 队列大小()```
返回在数据包丢失之前可以排队的 VAN 数据包数量。
#### 7. ```int 获取已排队数量()```
返回当前已排队的 VAN 数据包数量。
#### 8. ```int 获取最大排队数量()```
返回曾经排队的最高 VAN 数据包数量。
#### 9. ```void 设置丢弃策略(int startAt, bool (*isEssential)(const TVanPacketRxDesc&) = 0)```
为接收队列开始填满时实现一个简单的数据包丢弃策略。
如果接收队列中有 ```startAt``` 个或更多数据包排队,则会丢弃数据包,除非该数据包被标识为“重要”。要标识此类数据包,请通过 ```isEssential``` 参数传递一个函数指针。传递的函数在中断上下文中调用,因此它*必须*具有 ```ICACHE_RAM_ATTR``` 属性。
示例:
```
bool ICACHE_RAM_ATTR IsImportantPacket(const TVanPacketRxDesc& pkt)
{
return
pkt.DataLen() >= 3 &&
(
pkt.Iden() == CAR_STATUS1_IDEN // Right-hand stalk button press
|| (pkt.Iden() == DEVICE_REPORT && pkt.Data()[0] == 0x8A) // head_unit_report, head_unit_button_pressed
);
} // IsImportantPacket
#define RX_PIN D2
#define VAN_PACKET_QUEUE_SIZE 60
VanBusRx.Setup(RX_PIN, VAN_PACKET_QUEUE_SIZE);
VanBusRx.SetDropPolicy(VAN_PACKET_QUEUE_SIZE * 8 / 10, &IsImportantPacket);
```
以上示例将在接收队列包含 48 个或更多数据包时丢弃传入的数据包,除非它们被 ```IsImportantPacket``` 识别。
#### 10. ```bool 同步发送数据包(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)```
发送一个数据包进行传输。如果数据包成功发送,则返回 ```true```。
#### 11. ```bool 发送数据包(uint16_t iden, uint8_t cmdFlags, const uint8_t* data, size_t dataLen, unsigned int timeOutMs = 10)```
将一个数据包排队进行传输。如果数据包成功排队,则返回 ```true```。
#### 12. ```uint32_t 获取发送计数()```
返回自开机以来提供用于发送的 VAN 数据包数量。计数器可能会溢出回绕。
### VAN 数据包
在 VAN 总线上,电信号与 CAN 相同。然而,CAN 和 VAN 在线路上使用不同的数据编码,这使得在 VAN 总线上使用 CAN 接口成为不可能。
背景阅读:
- [关于 VAN 的 Wiki 页面](https://en.wikipedia.org/wiki/Vehicle_Area_Network)
- [VAN 线路协议 - Graham Auld - 2011 年 11 月 27 日](http://graham.auld.me.uk/projects/vanbus/lineprotocol.html)
- [数据手册集合 - Graham Auld](http://graham.auld.me.uk/projects/vanbus/datasheets/)
- [关于增强型曼彻斯特编码的讲座(法语) - Alain Chautar - 2003 年 6 月 30 日](http://www.educauto.org/files/file_fields/2013/11/18/mux1.pdf)
- [关于 VAN 总线访问:冲突与仲裁的讲座(法语) - Alain Chautar - 2003 年 10 月 10 日](http://www.educauto.org/sites/www.educauto.org/files/file_fields/2013/11/18/mux2.pdf)
- [关于帧格式的讲座(法语) - Alain Chautar - 2004 年 1 月 22 日](http://www.educauto.org/files/file_fields/2013/11/18/mux3.pdf)
- [工业网络 CAN / VAN - 硕士课程 - Marie-Agnès Peraldi-Frati - 2008 年 1 月](http://www.i3s.unice.fr/~map/Cours/MASTER_STIC_SE/COURS32007.pdf)
- [De CAN à CANopen en passant par VAN(法语) - Jean Mercklé - 2006 年 3 月](http://ebajic.free.fr/Ecole%20Printemps%20Reseau%20Mars%202006/Supports/J%20MERCKLE%20CANopen.pdf)
- [Les réseaux VAN - CAN(法语) - Guerrin Guillaume, Guers Jérôme, Guinchard Sébastien - 2005 年 2 月](http://igm.univ-mlv.fr/~duris/NTREZO/20042005/Guerrin-Guers-Guinchard-VAN-CAN-rapport.pdf)
- [Le bus VAN, vehicle area network: Fondements du protocole(法语) 平装本 – 1997 年 6 月 4 日](https://www.amazon.com/bus-VAN-vehicle-area-network/dp/2100031600)
- [用于 Saleae USB 逻辑分析仪的车辆局域网 (VAN 总线) 分析仪 - Peter Pinter](https://github.com/morcibacsi/VanAnalyzer/)
- [带串行接口的 Atmel TSS463C VAN 数据链路控制器](http://ww1.microchip.com/downloads/en/DeviceDoc/doc7601.pdf)
- [用于 Xsara Picasso 和 Xsara 的多路复用 BSI 工作原理 - VAN 协议](https://web.archive.org/web/20221115101711/http://milajda22.sweb.cz/Manual_k_ridici_jednotce.pdf#page=17)
以下方法可用于通过 ```VanBusRx.Receive(...)``` 获取的 ```TVanPacketRxDesc``` 数据包对象:
1. [```uint16_t Iden()```](#iden)
2. [```uint8_t CommandFlags()```](#commandflags)
3. [```const uint8_t* Data()```](#data)
4. [```int DataLen()```](#datalen)
5. [```unsigned long Millis()```](#millis)
6. [```uint16_t Crc()```](#crc)
7. [```bool CheckCrc()```](#checkcrc)
8. [```bool CheckCrcAndRepair()```](#checkcrcandrepair)
9. [```void DumpRaw(Stream& s, char last = '\n')```](#dumpraw)
10. [```const char* CommandFlagsStr()```](#commandflagsstr)
11. [```const char* AckStr()```](#ackstr)
12. [```const char* ResultStr()```](#resultstr)
13. [```const TIfsDebugPacket& getIfsDebugPacket()```](#getifsdebugpacket)
14. [```const TIsrDebugPacket& getIsrDebugPacket()```](#getisrdebugpacket)
#### 13. ```uint16_t 标识符()```
返回 VAN 数据包的 IDEN 字段。
已知 IDEN 值的概述可以在以下位置找到,例如:
- http://pinterpeti.hu/psavanbus/PSA-VAN.html
- http://graham.auld.me.uk/projects/vanbus/protocol.html
#### 14. ```uint8_t 命令标志()```
返回 VAN 数据包的 4 位 "命令" FLAGS 字段。每个 VAN 数据包有 4 个 "命令" 标志:
- EXT(位 3,最高有效位):始终为 1
- RAK(位 2):1 = 请求确认
- R/W(位 1):1 = 读操作,0 = 写操作
- RTR(位 0,最低有效位):1 = 远程传输请求
详细解释(法语)可在此处第 6 和 7 页找到:
http://www.educauto.org/files/file_fields/2013/11/18/mux3.pdf#page=6 。
#### 15. ```const uint8_t* 数据()```
返回 VAN 数据包的数据字段(字节)。
#### 16. ```int 数据长度()```
返回 VAN 数据包中的数据字节数。一个 VAN 数据包中最多可以有 28 个数据字节。
#### 17. ```unsigned long 毫秒()```
数据包时间戳,单位为毫秒。
#### 18. ```uint16_t Crc()```
返回 VAN 数据包的 15 位 CRC 值。
#### 19. ```bool 检查Crc()```
检查 VAN 数据包的 CRC 值。
#### 20. ```bool 检查并修复Crc()```
检查 VAN 数据包的 CRC 值。如果不匹配,则尝试通过翻转每一位进行修复。如果数据包正常(无论是在修复前还是修复后),则返回 ```true```。
#### 21. ```void 导出原始数据(Stream& s, char last = '\n')```
将原始数据包字节转储到流中。可选择指定最后一个字符;默认为 '\n'(换行符)。
调用示例:
```
pkt.DumpRaw(Serial);
```
输出示例:
```
Raw: #0002 ( 2/15) 11(16) 0E 4D4 RA0 82-0C-01-00-11-00-3F-3F-3F-3F-82:7B-A4 ACK OK 7BA4 CRC_OK
```
转储到字符数组的示例:
```
const char* PacketRawToStr(TVanPacketRxDesc& pkt)
{
static char dumpBuffer[MAX_DUMP_RAW_SIZE];
GString str(dumpBuffer);
PrintAdapter streamer(str);
pkt.DumpRaw(streamer, '\0');
return dumpBuffer;
}
```
注意:为此,您需要安装 [PrintEx](https://github.com/Chris--A/PrintEx) 库。我测试过
版本 1.2.0 。
#### 22. ```const char* 命令标志字符串()```
将 VAN 数据包的 "命令" FLAGS 字段作为字符串返回。
注意:使用静态分配的缓冲区,因此不要在同一个 printf 调用中两次调用此方法。
#### 23. ```const char* 确认字符串()```
将 VAN 数据包的 ACK 字段作为字符串返回,可以是 "ACK" 或 "NO_ACK"。
#### 24. ```const char* 结果字符串()```
将 VAN 数据包的 RESULT 字段作为字符串返回,可以是 "OK" 或以 "ERROR_" 开头的字符串。
#### 25. ```const TIfsDebugPacket& 获取Ifs调试数据包()```
检索可用于分析帧间间隔事件的调试结构。
仅在 ```#define VAN_RX_ISR_DEBUGGING``` 未被注释时可用(参见
[```VanBusRx.h```](https://github.com/0xCAFEDECAF/VanBus/blob/756b05097e57c183f87b7879e431308daef5ce5f/VanBusRx.h#L32))。
#### 26. ```const TIsrDebugPacket& 获取Isr调试数据包()```
检索可用于分析(观察到的)位时序的调试结构。
仅在 ```#define VAN_RX_IFS_DEBUGGING``` 未被注释时可用(参见
[```VanBusRx.h```](https://github.com/0xCAFEDECAF/VanBus/blob/756b05097e57c183f87b7879e431308daef5ce5f/VanBusRx.h#L33))。
## 👷 待完成工作
### 未来
目前该库仅支持 125 kbit/s 的 VAN 总线。需要添加对不同速率的支持,如 62.5 kbit/s,这可以作为可选参数传递给 ```VanBusRx.Setup(...)```。
## 📖 许可证
此库是开源的,并根据 [MIT 许可证](http://opensource.org/licenses/MIT) 授权。
您可以随心所欲地使用它,但欢迎贡献!
## 另请参阅
- [VAN 实时连接](https://github.com/0xCAFEDECAF/VanLiveConnect) - 您 PSA 车辆(标致、雪铁龙)的实时数据直接来自 VAN 总线,显示在您的智能手机或平板电脑上。
- [ESP32 RMT 外设车辆局域网 (VAN 总线) 读取器]标签:Arduino, ESP32, ESP8266, PSA车辆, VAN总线, 传感器网络, 嵌入式系统, 开源硬件, 总线协议, 数据包读写, 标致雪铁龙, 汽车电子, 物联网, 车载网络, 车载诊断, 车辆通信