Kwp2000協議的應用(程序原理篇)

 

作者:良知猶存

轉載授權以及圍觀:歡迎添加微信:becom_me

總述

    接上篇文章Kwp2000協議的應用(硬件原理使用篇),本篇針對kwp2000協議標準的服務ID詳細介紹,以及針對程序實現應答機制,進行介紹。

 

三、通訊實現過程詳解

 

KWP2000有兩種啓動方式,5波特率啓動和高速啓動方式,5波特率基本不使用了,並且我使用過程中是高速初始化的方式,所以下面就按照高速初始化的方式介紹:

 

 

 

在向ECU發送C1 33 F1 81 66 的啓動數據之前,還需要進行KWP通信的握手,這時候就需要用到快速初始化,用來告訴ECU有設備準備接入。

 

 

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 BE

 

 

注意了: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這個關鍵詞我們可以進行讀取所需的不同種類的車身信息

 

 

例如我要讀取車身的故障碼,由上圖可知故障碼屬於ID:0x03的服務ID類中

 

 

這時候我就向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;}

 

假設回來數據爲 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解析,裏面代碼是實踐過的,還有很多細節因爲篇幅與時間的原因就不多寫了,如果大家有什麼更好的思路,歡迎分享交流哈。

 

 

更多分享,掃碼關注我

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章