Kwp2000协议的应用(程序原理篇)

简介: Kwp2000协议的应用(程序原理篇)

作者:良知犹存

转载授权以及围观:欢迎添加微信:becom_me

总述

   接上篇文章Kwp2000协议的应用(硬件原理使用篇),本篇针对kwp2000协议标准的服务ID详细介绍,以及针对程序实现应答机制,进行介绍。


三、通讯实现过程详解

KWP2000有两种启动方式,5波特率启动和高速启动方式,5波特率基本不使用了,并且我使用过程中是高速初始化的方式,所以下面就按照高速初始化的方式介绍:

4edc953e2c684bbe819ffa954c899c08.png

在向ECU发送C1 33 F1 81 66 的启动数据之前,还需要进行KWP通信的握手,这时候就需要用到快速初始化,用来告诉ECU有设备准备接入。4edc953e2c684bbe819ffa954c899c08.png

Tidle 我在程序实现设置为400ms,>= 300ms

TiniL 我在程序实现设置为25ms, 24~26ms范围内

Twup 我在程序实现设置为50ms,49ms~51ms

注意:由于高速初始化需要对TX引脚进行置高置低,所以IO配置成推挽输出比较好,所以发送数据的时候使用模拟串口配置TX引脚进行数据的发送。

下面代码展示是堵塞执行,其实已经用状态机实现了,类似的延时状态机之前文章已经描述过,因为篇幅的原因,此处就不多做赘述,需要的人可以看我之前的文章。程序堵塞的优化方法(一)解决程序堵塞的优化方法(二)

u8 KlineFastInit(void)
{
  KLin_RX_CLOSE();/*关闭接收引脚*/
  K_OUT_HIGH;       /*TX引脚输出置高*/
  Delay_ms(400);  /*保持拉高400ms*/    
  K_OUT_LOW;    /*TX引脚输出拉低*/
  Delay_ms(25);/*保持拉低25ms*/
  K_OUT_HIGH; /*TX引脚输出置高*/
  Delay_ms(25);/*保持拉高25ms*/ 
  KLin_RX_OPEN();/*打开接收引脚*/
  Start_CommunicationKLin();/*向K-line发送 C1 33 F1 81 66 进行启动 */
  }

Tres 进行发送与接收之间的判断,通过这个时间可以判断ECU的回应情况,而不至于MCU出现长等待情况,如果出现该时间内数据没有回应,MCU端可以进行ECU重新建立通信的初始化过程。

正常情况下一些ECU回复信息 hex:83 F1 11 C1 E9 8F BE4edc953e2c684bbe819ffa954c899c08.png

注意了:KB1 KB2 就是我们需要提取的关键词,用来判断ECU是否回复积极响应,不过日本产的三国ECU的关键词是0xE98F,而德尔福和博世ECU的回复关键词是0xEF8F。

BOSH的回复信息 hex:C3 F1 11 C1 EF 8F 04

不过都一样,整条信息最后一位符合累加校验,我们把数据确认是可以用的之后,直接进行关键词判断,对于德尔福、BOSH的接收的信息的不一致,就可以在软件层面忽略,解析判断代码如下:

u8 ReceiveECUStartCommunication(u8 *p, u8 len)
{
  p++;//移动八位  显示第二位数据的地址
  if ((BigtoLittle16(*(u16*)(p)) == 0xEF8F)||
  (BigtoLittle16(*(u16*)(p)) == 0xE98F))//关键字判断 通过大小端转化函数
  {
      printf("Kline-StartCommunication!\r\n");
  }
  return 0;
}

通讯一旦建立之后我们就可以进行对ECU读取想要的数据。比如读或者删除整车故障码,车辆编号,水温,车速,转速,油压等各种车身上提供的传感器数据。.

这是对应的服务ID,通过ID这个关键词我们可以进行读取所需的不同种类的车身信息

4edc953e2c684bbe819ffa954c899c08.png

如我要读取车身的故障码,由上图可知故障码属于ID:0x03的服务ID类中

4edc953e2c684bbe819ffa954c899c08.png

这时候我就向ECU发送数据 hex:C1 33 F1 03 E8

__packed typedef struct{
  u8 fmt;                 
  u8 tgt;                 
  u8 src;               
  u8 sid;               
}KlineSend;
u8 ReadDTC(void)
{ 
  KlineSend *p = (KlineSend*)malloc(20);
  p->fmt = 0xC1;
  p->tgt = 0x33;
  p->src = 0xF1;
  p->sid = 0x03;
  //cheksum = 0xE8
  ((u8*)p)[sizeof(KlineSend)] = CheckSum((u8*)p, sizeof(KlineSend));
  SendBuf_KLin((u8*)p, sizeof(KlineSend)+1);
  free(p);
  return 0;
}

4edc953e2c684bbe819ffa954c899c08.png

假设回来数据为 hex:87 F1 11 43 0562 0000 0000 33

(BOSH ECU 回传数据大致为 hex>:C7 F1 11 43 0118 0107 0000 2D )故障码信息是随意写的

u8 ReceiveECUReadDTCByStatus(u8 *p, u8 len)
{
  u8 lenth = 0;
  ++p;
  --len;//刚好的故障码长度
  for (u8 i = 0; i<3; i++)
  {
    if (*(u16*)&(p[i * 2]) != 0x0000)
    {
      lenth += 2;//两个字节为一组
    }
  }
  for (u8 i = 0; i<lenth / 2; i++)
  {
    printf(".DT_%d,0x%04X\r\n",i,BigtoLittle16(*(u16*)&((p[i * 2]))));
  }
  return 0;
}

解析逻辑执行如下:仅供参考

__packed typedef struct{
  u8 fmt;                 
  u8 tgt;                
  u8 src;              
  u8 sid;                  
}KlineSecondFORMAT;
__packed typedef struct{
  u8 sid;                
  u8(*f)(u8*, u8);        
}KlineAnalyzTypeDef;  
uint8_t CheckSum(uint8_t* data, uint8_t len)// V
{
  uint8_t i;
  uint8_t sum;
  sum = 0;
  for(i = 0; i < len; i++)
  {
    sum += data[i];
  }
  return sum;
}
KlineAnalyzTypeDef KlineAnalyzTab[] =
{
  { 0xC1, ReceiveECUStartCommunication},    //启动通讯
  { 0x43, ReceiveECUReadDTCByStatus },
};
u8 KlineAnalyz(u8 *p,u8 lenth)
{
  KlineSecondFORMAT*p1;
  p1 = (KlineSecondFORMAT*)p;
  while(lenth)
  {
    u8 len = p1->fmt & 0x3F;
    if (len != 0)
    {
      if (p[len + sizeof(KlineSecondFORMAT)-1] != CheckSum(p, len + sizeof(KlineSecondFORMAT)-1))
        return 1;//返回错误
        for (int i = 0; i < sizeof(KlineAnalyzTab) / sizeof(KlineAnalyzTypeDef); i++)
        {
          if (p1->sid == KlineAnalyzTab[i].sid)
          {
            KlineAnalyzTab[i].f(&(p1->sid), len);
            break;
          }
        }
        lenth = lenth -(len+ sizeof(KlineSecondFORMAT));
        p1=(KlineSecondFORMAT*)((u8*)p1+(len+ sizeof(KlineSecondFORMAT)));
      }
  return 0;
  }

这就是我分享的kwp2000解析,里面代码是实践过的,还有很多细节因为篇幅与时间的原因就不多写了,如果大家有什么更好的思路,欢迎分享交流哈


目录
相关文章
|
3天前
|
安全 网络协议 算法
Android网络基础面试题之HTTPS的工作流程和原理
HTTPS简述 HTTPS基于TCP 443端口,通过CA证书确保服务器身份,使用DH算法协商对称密钥进行加密通信。流程包括TCP握手、证书验证(公钥解密,哈希对比)和数据加密传输(随机数加密,预主密钥,对称加密)。特点是安全但慢,易受特定攻击,且依赖可信的CA。每次请求可能复用Session ID以减少握手。
13 2
|
2月前
|
存储 网络协议 Linux
|
芯片
一文搞懂I2C协议-硬件基础
I2C总线是由飞利浦在80年代初设计的,以允许位于同一电路板上的组件之间能够轻松通信。其大大简化了电路的设计,早期的电视机中很多地方用到了I2C这种通信方式。飞利浦半导体于2006年迁移到了NXP。I2C名称翻译为“ Inter IC”。有时,该总线称为IIC或I²C总线。I2C总结的基本的特征
919 0
|
网络安全 开发工具 数据安全/隐私保护
建立一个流式的RPC通信 | 青训营笔记
建立一个流式的RPC通信 | 青训营笔记
179 0
|
存储 缓存 负载均衡
计网 - 怎样实现 RPC 框架
计网 - 怎样实现 RPC 框架
90 0
|
数据格式
Kwp2000协议的应用(程序后续篇)
Kwp2000协议的应用(程序后续篇)
97 1
Kwp2000协议的应用(程序后续篇)
|
存储 数据采集 网络协议
Linux网络原理与编程(2)——第十二节 应用层协议(以HTTP为例)
协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的。更准确点来说,收发是按照比特位的形式进行的。
190 0
Linux网络原理与编程(2)——第十二节 应用层协议(以HTTP为例)
|
域名解析 网络协议 算法
Linux网络原理与编程(4)——第十四节 传输层协议
客户端认为连接已经建立成功了,所以就正常发数据。但是这个时候服务器并未建立连接,在收到数据之后,会向客户端发送一个含有RST的报文(reset),即希望客户端重新建立连接。
222 0
Linux网络原理与编程(4)——第十四节 传输层协议
|
网络协议 网络架构
网络通讯原理简介以及演示通讯过程
网络通讯原理简介以及演示通讯过程
152 0
网络通讯原理简介以及演示通讯过程
|
存储 算法 Java
【计网修炼手册】两种通信方式
《计算机组成原理》、《数据结构与算法》、《操作系统》、《计算机网络》不仅是大学信息科学与工程学院的核心课程,也是计算机考研专业基础综合408的考试内容。学习这些内容可能不见得像学习Java和GO一样能让你迅速找到工作,但他们作为计算机世界的基石是需要认真掌握的,这些知识是源源不断的技术浪潮中不会被淘汰的知识。
220 0