汽车OBD初级开发入门

2023-11-16

我所认识的OBD

直观的从名称上来说是英文On-Board Diagnostics的缩写,中文翻译为“车载诊断系统”。书面上的解释就是处理汽车相关故障的诊断系统。对于硬件接口如下图
OBD插座
针对不同车型,汽车上的OBD接口位置会有所不同
汽车OBD接口位置
而目前对于OBD接口的商用一般是作为GPS tracker即gps定位器,在汽车OBD上主要引出的接口包含了12V的电源、CAN总线、K线,L线等等如下图所示
OBD接口定义
对于实现与汽车内部诊断系统通信,就是通过这几条总线进行通信。我所理解的OBD从嵌入式的角度来说的话就是:外部器件与汽车内部系统通信的接口。

从何开始学习OBD

当我们认识了OBD相关概念之后,可是对于毫无经验的开发者来说,到底该如何下手,该先学习什么内容。我们要了解汽车内部的数据系统,那必须要学习的就是怎么和汽车进行通信,这时候就很明确了,那就是通过OBD接口的通信总线来打通外部与汽车内部的数据通信,而OBD包含的通信接口包含有CAN总线、K线以及L线,我这里主要是讲解CAN相关应用。

stm32的CAN总线

如果学习过单片机的朋友,谈到CAN总线相比OBD应该会更熟悉一些,对于CAN总线现在都是集成到芯片内部的,比较常用的就是stm32,对于使用者来说,不用太关心CAN总线的电路实现,我们只要能通过配置CAN总线进行通信就行了。在连接CAN总线通信的时候需要注意的是,在通信回路中需要并一个120欧的电阻,至于为什么需要电阻可以参考这篇博文:CAN总线为什么要有两个120Ω的终端电阻。关于CAN总线的理论基础,在网上都有很好的总结大家可以自行查找。我这里直接讨论在STM32中该如何配置CAN总线。首先调试CAN总线,可以先配置成回环模式进行调试,通过是否通信来判断can总线的相关初始化是否正确。对于can的初始化的流程,
1、配置CAN的IO口,在stm32中一般CAN的IO口是复用的,所以这里在配置的时候需要注意一下
2、打开CAN总线的时钟,同时开始i配置CAN相关的寄存器数据,在这里很重要的一点就是要配置通信模式和波特率,这会关系到CAN的通信。
3、在初始化完之后,还需要配置CAN的滤波器,配置滤波器的目的是因为在汽车通信中,由于部分汽车是没有做网关的,当你通过CAN总线去通信的时候,会返回很多无用的消息,这个时候通过配置滤波器,直接过滤掉无用的,只接收特定的想要的数据。在滤波器中包含16位的滤波器和32位的滤波器配置,这个可以根据需要配置相应的滤波器。
网上有很多相关can初始化的配置,因为我这边使用的是stm32f042的芯片,可供大家参考一下

/****************************************************************************************
**函数信息(information):void CAN_GPIOConfig(void)
**功能描述(description):CAN所用IO引脚配置
**输入参数(Arguments)  :None
**输出参数(Returns)    :None
**调用提示(reference)  :	
*****************************************************************************************/
void CAN_GPIOConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA ,ENABLE);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE); //使能SYSCFG,
	
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource11 ,GPIO_AF_4);	
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_4);			//复用CAN功能
	
	SYSCFG->CFGR1 |= PA11_PA12_RMP;			//配置打开PA11_PA12功能
	
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11;           
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;        
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;           
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;        
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    
    GPIO_Init(GPIOA, &GPIO_InitStructure);	
}
/****************************************************************************************
**函数信息(information):void CAN1_Config32BitFilter(u32 id1, u32 id2, u32 mid1, u32 mid2)
**功能描述(description):CAN扩展帧滤波器设置
**输入参数(Arguments)  :id1,id2 校验码   mid1,mid2 屏蔽码
**输出参数(Returns)    :None
**调用提示(reference)  :	
*****************************************************************************************/
void CAN1_Config32BitFilter(u32 id1, u32 id2, u32 mid1, u32 mid2)
{
	CAN_FilterInitTypeDef  CAN_FilterInitStructure;
	NVIC_InitTypeDef  NVIC_InitStructure;
	
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;  
	CAN_FilterInitStructure.CAN_FilterIdHigh = id1>>13;
	CAN_FilterInitStructure.CAN_FilterIdLow = (id1<<3)|4;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = mid1>>13;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = (mid1<<3)|4;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);
	CAN_FilterInitStructure.CAN_FilterNumber = 1;
	CAN_FilterInitStructure.CAN_FilterIdHigh = id2>>13;
	CAN_FilterInitStructure.CAN_FilterIdLow = (id2<<3)|4;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = mid2>>13;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = (mid2<<3)|4;
	CAN_FilterInit(&CAN_FilterInitStructure);

	//中断优先级NVIC设置
    NVIC_InitStructure.NVIC_IRQChannel         = CEC_CAN_IRQn;  //CAN中断
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;          //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd      = ENABLE;     //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);   
	
	CAN_ITConfig(CAN, CAN_IT_FMP0, ENABLE);       

}
/****************************************************************************************
**函数信息(information):void CAN1_Config16BitFilter(u16 id1, u16 id2, u16 mid1, u16 mid2)
**功能描述(description):CAN标准帧滤波器设置
**输入参数(Arguments)  :id1,id2 校验码   mid1,mid2 屏蔽码
**输出参数(Returns)    :None
**调用提示(reference)  :	
*****************************************************************************************/
void CAN1_Config16BitFilter(u16 id1, u16 id2, u16 mid1, u16 mid2)                                                                             
{                                                                                                                         
	CAN_FilterInitTypeDef  CAN_FilterInitStructure;                                                                       
	NVIC_InitTypeDef  NVIC_InitStructure;
	
	CAN_FilterInitStructure.CAN_FilterNumber=1;                                                                           
	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;                                                         
	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;                                                        
	CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;                                                                      
	CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;                                                                       
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mid1<<5;                                                                  
	CAN_FilterInitStructure.CAN_FilterMaskIdLow=mid2<<5;                                                                   
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;                                                           
	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;                                                                                                                                                                                       
	CAN_FilterInit(&CAN_FilterInitStructure);
	
	//中断优先级NVIC设置
    NVIC_InitStructure.NVIC_IRQChannel         = CEC_CAN_IRQn;  //CAN中断
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;          //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd      = ENABLE;     //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);   
	
	CAN_ITConfig(CAN, CAN_IT_FMP0, ENABLE);       
}

/****************************************************************************************
**函数信息(information):u8* Send_CANFrame(CanTxMsg* TxMessage,u8 CANStype,ErrorStatus* err)
**功能描述(description):发送一帧CAN数据
**输入参数(Arguments)  :
**输出参数(Returns)    :None
**调用提示(reference)  :	
*****************************************************************************************/
__IO ErrorStatus RxFlay;
void Send_CANFrame(CanTxMsg* TxMessage,u8 CANStype,ErrorStatus* err)
{
	u32 i;
	RxFlay = ERROR;
	TxMessage->IDE = CANStype;
	TxMessage->DLC = 8;
//	USARTx_SendMData(&(TxMessage->Data[0]),9);
	CAN_Transmit(CAN, TxMessage);

	for (i = 0;i < 1500;i++)	
	{
		delay_ms(1);
		if (RxFlay == SUCCESS) 
			break;
	}
	*err = RxFlay;
}
//can口接收数据查询
//buf:数据缓存区;	 
//返回值:0,无数据被收到;
//		 其他,接收的数据长度;
u8 CAN1_Receive_Msg(u8 *buf)
{		   		   
 	u32 i;
	CanRxMsg RxMessage;
    if( CAN_MessagePending(CAN,CAN_FIFO0)==0)return 0;		//没有接收到数据,直接退出 
    CAN_Receive(CAN, CAN_FIFO0, &RxMessage);//读取数据	
    for(i=0;i<RxMessage.DLC;i++)
    buf[i]=RxMessage.Data[i];  
	return RxMessage.DLC;	
}
/****************************************************************************************
**函数信息(information):void CEC_CAN_IRQHandler(void)
**功能描述(description):CAN中断接收函数
**输入参数(Arguments)  :
**输出参数(Returns)    :None
**调用提示(reference)  :	
*****************************************************************************************/
void CEC_CAN_IRQHandler(void)
{
	u8 data[8],i,j;
	u32 tmp;
	CanRxMsg   RbufMege;                      //CAN  receive message
	memset(&RbufMege,0,sizeof(CanRxMsg)); //先清空CAN数据接收缓存区
	CAN_Receive(CAN, CAN_FIFO0, &RbufMege);
}

需要注意的是如果CAN数据要中断接收的话,需要打开CAN的中断。

OBD的标准协议

要进行OBD数据的通信,那么必须要知道通信的通信协议,简而言之就是要获取数据的数据报文是什么,我发一条报文下去,它会返回相应的数据,我们对数据进行解析就可以获得我们最终的数据。而到底发送什么数据报文通信才会返回相应的数据,这就需要了解OBD协议的,而在OBD的通信协议中包含了不同总线的通信协议,也是世界通用的标准协议。
1、故障码标准ISO-15031。
2、通讯协议标准ISO-941,ISO-14230,ISO-15765,SAEJ1850
我这边主要讨论CAN总线在OBD中的协议ISO-15765。
首先我们必须要熟悉OBD通信的应用层,我们只需要看ISO-15031-5就行了,里面包含了OBD通信中的9种模式,每种模式需要获取的数据不一样如下:
Mode 1: 请求动力系当前数据

Mode 2: 请求冻结祯数据

Mode 3: 请求排放相关的动力系诊断故障码

Mode 4: 清除/复位排放相关的诊断信息

Mode 5: 请求氧传感器监测测试结果

Mode 6: 请求非连续监测系统OBD测试结果

Mode 7: 请求连续监测系统OBD测试结果

Mode 8: 请求控制车载系统,测试或者部件

Mode 9: 读车辆和标定识别号
其次,我们还需要ISO-15765-3里面包含了标准帧和扩展帧的使用方式和具体的数据流。通过这两个的组合我们就可以知道我们要发什么样的数据流去获取数据。
下面具体的数据流是什么,我推荐可以看一下这篇博文:ISO 15765 学习笔记

1.請求支持PID01-20
7DF 02 01 00 00 00 00 00 00------Tools To ECU 01 00:01表示SIDRQ,請求當前動力診斷信息;00表示PID((是否支持PID01-20))
7E8 07 41 00 FF FF FF FF FF------ECU To Tools (ECU #1(ECM)回覆的,41表示SIDPR,如果是表示肯定回答,00表示支持PID01到20;FF爲全支持)

2.請求支持PID21-40
7DF 02 01 20 00 00 00 00 00------Tools To ECU 01 20:01表示SIDRQ,請求當前動力診斷信息;20表示PID((是否支持PID21-40))
7E8 07 41 20 FF FF FF FF FF------ECU To Tools (ECU #1(ECM)回覆的,41表示SIDPR,如果是表示肯定回答,20表示PID((是否支持PID21-40));FF爲全支持)

3.請求支持PID41-60
7DF 02 01 40 00 00 00 00 00------Tools To ECU 01 40:01表示SIDRQ,請求當前動力診斷信息;40表示PID((是否支持PID41-60))
7E8 07 41 40 FF FF FF FF FF------ECU To Tools (ECU #1(ECM)回覆的,41表示SIDPR,如果是表示肯定回答,40表示PID((是否支持PID40-60));FF爲全支持)

4.外部測試設備向汽車請求後續的PID
7DF 02 01 01 00 00 00 00 00------Tools To ECU 01 01:第一個01表示SIDRQ,請求當前動力診斷信息;第二個01表示PID,向外發送DTC和MIL狀態數目。
7E8 07 41 01 33 44 55 66 77------ECU To Tools (// ECU #1(ECM)回覆的。41表示SIDPR;01表示PID;33表示不能發動,燃料系統,全面監控;…)

7DF 02 09 02 00 00 00 00 00------Tools To ECU 09 02:09表示SIDRQ;02表示信息類型:VIN碼
7E8 10 14 49 02 01 31 32 33------ECU To Tools(10:目前不知什麼意思, 14:表示迴應爲20字節 49:表示肯定響應 02:表示信息類型 VIN碼 01:表示第一個響應消息 31 32 33:VIN碼)
7E0 30 00 05 00 00 00 00 00------Tools To ECU (目前不知什麼意思,懷疑是連續包之類的)
7E8 21 34 35 36 37 38 39 41------ECU To Tools (21:目前不知什麼意思, 34~41:VIN碼)
7E8 22 42 43 44 45 46 47 48------ECU To Tools (22:目前不知什麼意思, 42~48: VIN碼;VIN碼全部加起來爲17字節)
知道了具体的数据流后可以根据相应9种模式到车上或者模拟器去实测一下,在国内对于CAN总线的实施是在2009年以后才开始的,所以有些老车不支持CAN总线,这个要去实测一下才知道。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

汽车OBD初级开发入门 的相关文章

随机推荐

  • 冈萨雷斯《数字图像处理》学习笔记(3)--频率域滤波(含傅里叶变换推导)

    频率域滤波所有的滤波都是通过傅里叶变换在频率域实现的 所以我们先重点提出傅里叶变换 一 傅里叶变换基础 一维傅里叶变换数学推导 首先 我们知道傅里叶级数 形如 f x a0 n 1 ancos n x bnsin n x 1 f x a 0
  • CTex基础

    CTex基础笔记 1 什么是CTex 2 CTex使用前涉及的文件 3 文档的基本结构 4 LaTex替换 5 LaTex列表与表格环境 5 1 列表环境 5 1 1 itemize环境 5 1 2 enumerate环境 5 2 表格环境
  • 机器学习:python 实现一个linear regression

    1 原理介绍 linear regression步骤 1 导入数据 2 将数据分为训练集合测试集 linear regression 分为x train x text y train y test 3 导入线性回归算法 利用训练集计算出模型
  • zh-hans_windows_xp_professional_with_service_pack_3_x86_cd_vl_x14-74070.iso镜像下载

    链接 https pan baidu com s 17J tWrQcnAU QGG uWdcIwhttps pan baidu com s 17J tWrQcnAU QGG uWdcIw 提取码 zt88
  • 远程工作高效方法(几年前帖子,私密变公开后时间就变了)

    1 要和居住环境分开 我在阳台上办公 2 制订计划 每天写到纸上 贴在墙上 3 时间调整 以前上班时 有公司上班时间 先在要调整 比如 上午九点才开始工作 在家可以7点起床 困了再睡 4 每小时是工作内容 学习内容50分钟 视频教程1个或者
  • ubuntu中使用QT同时编译pcl和opencv出现error: field ‘pa ram_k_’ has incomplete type ‘flann::SearchParams’

    问题描述 ubuntu中使用QT同时编译opencv和pcl时出现如下错误 错误原因 pcl和opencv中均包含flann库产生冲突 解决办法 将flann目前更换为flann2或者其它名字 在更改目录后 其它关联引用文件也需要更改 涉及
  • kali apt update问题

    这两天使用卡里进行升级sudo apt update 错误无法升级 sudo apt update Get 1 http mirrors neusoft edu cn kali kali rolling InRelease 30 6 kB
  • 算法笔记-DTW动态时间规整

    算法笔记 DTW动态时间规整 简介 简单的例子 定义 讨论 约束条件 步模式 标准化 点与点的距离函数 具体应用场景 分类 点到点匹配 算法笔记 DTW动态时间规整 动态时间规整 规划 Dynamic Time Warping DTW 是一
  • 戴尔如何加装固态硬盘

    这是手册中有关固态硬盘的支持规格 您可以按照这个参数进行选购 G15 5511 支持两个 M 2 2230 2280 固态硬盘 M 2 2230 固态硬盘 PCIe 3 0 x4 NVMe 高达 1 TB M 2 2280 固态硬盘 PCI
  • 2023版软件测试学习路线图(超详细自学路线)

    送福利了 超详细的软件测试学习路线图来啦 2023版是首发哟 软件测试学习路线图分为9个阶段 包含 软件测试环境配置和管理 gt 软件测试数据管理与数据库测试 gt web前端测试技术 gt 通用软件测试技术 gt Python测试开发技术
  • python openpyxl 操作excel 插入行,列

    import openpyxl wb openpyxl load workbook D 村数据 实验 xlsx ws wb Sheet1 ws insert rows 3 插入行 ws insert cols 4 插入列 wb save D
  • JAVA【基础】 IDEA导入jar包的几种方式

    目录 获取想要添加的依赖 或者jar包 maven添加依赖 手动导入jar包 最后测试一下 是否添加成功 下面多图预警 获取想要添加的依赖 或者jar包 添加依赖 或者下载jar包 都可以去maven网站下载 进入 Maven仓库 http
  • 获取windows凭证管理器明文密码

    1 运行cmdkey list查看windows保存凭证 方法1 mimikaz mimikatz vault cred 2 利用powershell尝试获取 windows 普通凭据类型中的明文密码 powershell import F
  • IPv6基础

    IPv6 1 优势 无限 地址空间 地址长度为128 bit 海量的地址空间 满足物联网等新兴业务 有利于业务演进及扩展 层次化的地址结构 相较于IPv4地址 IPv6地址的分配更加规范 利于路由聚合 缩减IPv6路由表规模 路由快速查询
  • 数的划分(递归)

    整数划分是另外的问题 题目描述 Description 将整数n分成k份 且每份不能为空 任意两种划分方案不能相同 不考虑顺序 例如 n 7 k 3 下面三种划分方案被认为是相同的 7 1 1 5 7 1 5 1 7 5 1 1 问有多少种
  • 7z怎么解压linux,7z 常用解压命令

    用命令行来执行7z的极限压缩 就是如下的命令 C 01 MyApp 7 Zip 7z exe a t7z newPack 7z F 14 newWork 7z testDoc r mx 9 m0 LZMA2 ms 10m mf on mhc
  • cmd简单游戏代码_python简单游戏应用——剪刀石头布!

    我们的基础中的基础 在前几文中已经介绍完了 其他的知识用什么学什么就对了 接下来我们做款小游戏 纵观全文 先引入了一个函数 random 随机数 单用random 这个函数 会产生一个随机的实数 范围在 0 1 若是要从自定的范围取出一个
  • 在flask框架中,设置执行完视图函数后自动将数据提交回数据库

    设置执行完视图函数后自动提交操作回数据库 app config SQLALCHEMY COMMIT ON TEARDOWN True
  • pytorch GPU版本安装

    使用驱动精灵安装 参考 pytorch GPU版本安装 尘世猫的博客 CSDN博客 pytorchgpu版本 安装cuda 高版本的cuda是可以兼容低版本的cuda的 比如我的电脑支持cuda11 0 我就可以安装cuda10 0 cud
  • 汽车OBD初级开发入门

    汽车OBD初级开发入门 我所认识的OBD 从何开始学习OBD stm32的CAN总线 OBD的标准协议 我所认识的OBD 直观的从名称上来说是英文On Board Diagnostics的缩写 中文翻译为 车载诊断系统 书面上的解释就是处理