作者:良知猶存
轉載授權以及圍觀:歡迎添加微信: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。
更多分享,掃碼關注我