Kwp2000協議的應用(程序後續篇)

​作者:良知猶存

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

總述

    接上上篇文章Kwp2000協議的應用(硬件原理使用篇),本篇繼續對基於PID解析數據,如何依據J1979的標準進行解析數據

 

    先給昨天的文章補上一張故障碼對照表,昨天分析瞭如何讀取故障碼,但是如何把16bit的hex數據轉爲我們可以解釋的故障碼,一般各大廠家的維修手冊會有顯示,第二就是ECU的協議手冊裏面會進行描述故障碼對應的hex數據。

 

下面就是部分故障碼展示:

 

 

四、繼續讀取ECU常用數據

 

 

通過服務ID:0x01 讀取整車狀態數據:

從上面可以看到支持的整車的數據的ID 有0x20 0x40 0xC0打頭的整段ID

 

或者我們也可以通過向ECU發送相應格式的數據,用來解析能夠支持的PID有哪些。

 

 

TEST->ECU  (設備端發往ECU請求讀取轉速的數據)hex:C2 33 F1 01 0C F3

 

讀取代碼如下:僅供參考

__packed typedef struct{  u8 fmt;                   u8 tgt;                   u8 src;                 u8 sid;               }KlineSend;u8 KLineReadrpm(void)/*讀發動機轉速*/{  KLIN_RecOK = 0;  u8* p1;  KlineSend *p = (KlineSend*)malloc(20);    p->fmt = 0xC2;  p->tgt = 0x33;  p->src = 0xF1;  p->sid = 0x01;  p1=(u8*)&(p->sid);  *++p1= 0x0C;  *++p1=CheckSum((u8*)p, sizeof(KlineSend)+1);  SendBuf_KLin((u8*)p, sizeof(KlineSend)+2);  free(p);  return 0;}

 

 

 

ECU ->TEST (ECU 應答設備轉速的回覆)德爾福hex ::C4 F1 11 41 0C 0000 13

 

BOSH ECU迴應數據格式  hex:C4 F1 11 41 0C 0000 13

 

雖然數據內容有些不同,但是都是符合kwp2000的數據格式,這樣對我們來說我們只需要把握數據整體是否能用,再解析關鍵字即可,不需要一種ECU寫一套代碼。

其中解析方式可以參照當前協議中ID支持的標準解析方式,我開發的PID都符合J1979的解析方式,所以我就按照如下表進行解析數據。

 

 

汽車現在有新的解析標準,大家可以自行查找,這裏給大家描述的是一種方法,至於最終開發的產品,請嚴格按ECU所符合的標準來操作。

 

同理:車速的讀取信息

tester ->德爾福ECU  hex:C2 33 F1 01 0D F4

德爾福ECU-> tester  hex:83  F1 10 41 0D 23 F5

讀取關鍵詞車速爲 0x23

 

BOSH ECU迴應格式爲 hex:C3 F1 11 41 0D 00 13

讀取關鍵詞車速爲 0x00

 

 

解析判斷代碼如下:

u8 ReceiveReadCommData(u8 *p,u8 len){  u16 EngRpm,carSpeed;  switch(*++p)//關鍵字判斷  {    case 0x0C:    {      EngRpm=((*(((u8*)p)+1))*256+(*(((u8*)p)+2)))/4;      break;    }      case 0x0D:    {      carSpeed=*(((u8*)p)+1);      break;    }    default:      break;      }  return 0;}

 

    但是有些時間我們會遇到讀取過來的數據無法使用,那麼我們第一要判斷的就是否是服務ID不支持,雖然上面可以看到很多ID的解析方式,甚至ECU都會迴應你正確的格式,但是有些時候外部接線以及其他原因,我們獲得的數據是無法使用的。

    比如車速,如果ECU沒有此項功能,ECU則會回覆0x12否定代碼,示例如下:

tester->:C233F1010DF4

ECU  ->: 83F1117F011217

但是有些時候,因爲一些原因該功能ECU支持信息回覆,但是實際上ECU上硬線並沒有連接,所以需要我們及時分辨:

 

 

 

五、讀取一體的函數結構

加上昨天現在有幾個ID的讀取了,昨天沒有分享讀取的總函數,現在展示一下讀取執行的總函數:僅供參考

KlinSendTimTypeDefTab KlineSendTimTab[KlineTask] ={  { 0, 0, 3   ,  *Tester        },            //用來與ECU保持長連接  { 0, 0, 1   ,  *KLineReadrpm  },  { 0, 0, 1   ,  *KLineReadSpeed},  { 0, 0, 15  ,  *ReadDTC       },  { 1, 0, 20  ,  *KLineDtcClear },            };u8 KlineScan(void){    if(KlinRcvLen()>3)    {             KlineAnalyz(KlinRcvBuff(), KlinRcvLen());//調用串口接收函數       memset((u8*)KlinRcvBuff(),0x00, 0xff);    }    KLIN_RecOK = 0;    KlinClsRecvd();  }  if (KlineSendIndFlag.flag == 0)  {    if (KlineSendIndFlag.init == 1)    {            printf("Klin_init\r\n");      KlineFastInit();      KlineSendIndFlag.count = 0;      KlineSendIndFlag.src = 600;      KlineSendIndFlag.flag = 1;            (KlineSendIndFlag.cnt > 8)? (KlineSendIndFlag.cnt =0):(KlineSendIndFlag.cnt++);      if(KlineSendIndFlag.cnt>3&&KlineSendIndFlag.cnt<6)      {          KlineSendIndFlag.init =1;          KlineSendIndFlag.count = 0;          KlineSendIndFlag.flag =0;          KlineSendIndFlag.sta=0;/*判斷爲0*/      }      else{          KlinComInit();        }                }    else    {      for (char i = 0; i < sizeof(KlineSendTimTab)/sizeof(KlinSendTimTypeDefTab); i++)      {        if (KlineSendTimTab[i].flag == 0)        {          KlineSendTimTab[i].flag = 1;          KlineSendTimTab[i].count = 0;//計算接收時間長度          KlineSendTimTab[i].p() ;          KlineSendIndFlag.flag  = 1;              KlineSendIndFlag.count = 0;              if(KlineSendIndFlag.cnt)KlineSendIndFlag.cnt =0;  /*轉爲0*/                      break;        }      }    }  }  return 0;}

 

 

 這就是我分享的kwp2000解析,還有很多細節操作,實際開發和文字描述上還是差距很多,如有需要歡迎大家聯繫我與我交流,添加我的微信:become_me。

 

 

更多分享,掃碼關注我

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