로그인회원등록 내글장바구니주문조회현재접속자
 상품 검색








 게시판 검색





 
 
회원등록 비번분실


온라인 입금계좌
ㆍ기업은행
ㆍ219-043192-01-028
ㆍ이건영

      거래은행 바로가기
 
 Sensor Applications
아듀이노 공개소스
작성자 avrtools™        
작성일 2008/10/09
첨부#1 DTC-CODE.txt (42KB) (Down:1732)
Link#1 (Down:2)
ㆍ추천: 0  ㆍ조회: 9786   
  아듀이노 OBD-II PID 송수신 함수
참조 : http://en.wikipedia.org/wiki/OBD-II_PIDs
제목 : OBD-II PIDs
 
PID는 무엇인가
OBD(기판 자체 진단기)의 Parameter ID는, 차량고장 진단기가 차량으로 작동상태를 요구하는 코드이다,  
SAE(자동차 협회) J2012 표준으로 정의된 DTC(고장 진단 코드)의 번호이다.
일반적으로, 자동차에서 OBD-II 커넥터로 연결하는 진단도구는 PID를 사용하여 진단한다.
 
PID 코드의 흐름
점검하는 PID 코드를 입력 -> PID를 송신 ->CAN, ISO 버스 -> ECU가 수신 -> 차량의 센서를 읽음 ->
ECU가 PID의 데이터를 송신 -> CAN, ISO 버스 -> 데이터를 수신 -> 요청한 PID의 데이터를 표시
 
SAE J1979의 PID
모든 차량은 모든 PID 코드를 지원하지는 않는다,
또한 PID는 OBD-II 에서 정의되지 않고, SAE J1979에서 정의되엇다.
 
SAE J1979 PID 코드

 Mode

PID 

응답 

 PID에 대한 응답내용

 단위

ECU로 부터 응답한 데이터의 구조 및 공식 

01

 00

4

PID가 지원되는가?

 

BIT 구조, PID 0x01~PID 0x20 

01

 01

4

고장코드와 MIL상태

 

BIT 구조, (추가 설명#1)

01

 02

8

저장된 DTC

 

 

01

 03

2

연료계통의 상태

 

BIT 구조, (추가설명 #2

01

 04

1

엔진의 부하

%

A*100/255 

01

 05

1

엔진 냉각수 온도

A-40 

01

 06

1

단시간 연료 %조절 #1

%

0.7812*(A-128) 

01

 07

1

장시간 연료 %조절 #1

%

0.7812*(A-128) 

01

 08

1

단시간 연료% 조절 #2

%

0.7812*(A-128) 

01

 09

1

장시간 연료% 조절 #2

%

0.7812*(A-128) 

01 

 0A

1

연료의 압력

 kPa

A*3 

01 

 0B

1

흡입공기의 압력

 kPA

01 

 0C

2

엔진의 분당 회전수

 rpm

((A*256)+B)/4 

01 

 0D

1

차량의 속도

 km/h

01 

 0E

1

#1 실린더 상대각도

deg

A/2-64 

01 

 0F

1

흡입공기의 온도

 ℃

A-40 

01 

 10

2

MAF 공기흐름 비율

 g/s

((256*A))=B)/100 

01 

 11

1

스로틀 위치

A*100/255 

01 

 12

1

공기의 상태

 

비트구조, (추가설명 #3

01 

 13

1

O2 센서의 유무

 

A0~A3 =#1 센서, A4~A7 =#2 센서

01 

 14

2

#1, O2 센서 1

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF) 

01 

 15

2

#1, O2 센서 2

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF)

01 

 16

2

#1, O2 센서 3

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF)

01 

 17

2

#1, O2 센서 4

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF)

01 

 18

2

#2, O2 센서 1

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF)

01 

 19

2

#2, O2 센서 2

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF)

01 

 1A

2

#2, O2 센서 3

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF)

01 

 1B

2

#2, O2 센서 4

 V, %

A*0.005(B-128)*0.7812 (@ B==0XFF) 

01 

 1C

1

OBD 표준

 

비트 구조, (추가설명 #4)

01 

 1D

1

O2 센서

 

PID 13과 유사함, B1S1,B1S2 ~ B4S1,B4S2

01 

 1E

1

보조입력 상태 

 

A0 ==PTO 상태 (1==Active), A6~A0 없음 

01 

 1F

2

엔진 작동시간 

 sec

(A*256)+B 


Mode 01의 PID 0x20 ~ C4는 생략.
 

Mode

PID 

바이트

 PID에 대한 응답내용

  단위  

ECU로 부터 응답한 데이터의 구조 및 공식   

02

02

2

저장된 고장코드를 요청

 

BCD 구조, DTC-1(high), DTC-1(low)

03

 

n*6

새로운 고장코드를 요청

 

BCD 구조, 3 DTC =6 바이트,(추가설명 #5)

04

 

0

고장코드 삭제, MIL점검

 

저당된 모든 고장코드를 삭제, MIL 소등

09

02

5x5

차량 ID 번호 = VIN

 

5자x5줄, A는 플랙, B~E는 ASCII로 된 VIN

 
추가설명 #1   모드1 PID 01
응답은 4 바이트의 데이터.  첫번째 바이트는 2개의 정보를 갖는다.  
첫 바이트의 최상위 비트 A7은 MIL의 상태를 나타낸다( MIL은 계기판의 고장표시등이다)
첫 바이트의 A6~A0은 현재 ECU에 걸린 고장의 상태(status)이며,
2~4 번째 바이트는 완전하게 표시된 고장번호(DTC)이다.
 
B0 = Misfire (점화실패)
B1 = Fuel System (연료장치)
B2 = Components (제어장치)
B3 = Reserved (예약됨 =현재 없음)
C1 = Catalyst (촉매장치)
C2 = Heated Catalyst (가열된 촉매장치)
C3 = Evaporative System (증발장치)
C4 = Secondary Air System (2차 공기 장치)
C5 = Oxygen Sensor (산소검출기)
C6 = Oxygen Sensor Heater (산소검출기 가열장치)
C7 = EGR System (배기가스 재연소 장치)

추가설명 #2  모드 1 PID 03
2 바이트의 응답, 첫 바이트는 연료장치의 상태, 응답 데이터는 비트 구조이다.
A0  =연료부족, A1 =환원장치의 Downstream, A2 =외부 기압, A3, A4, A5, A6, A7 =모두 항상 0 
2번째 바이트는 연료장치 #2 혹은 첫번째 바이트의 연장이다.
 
추가설명 #3  모드1 PID 12
응답은 1 바이트,  공기장치 #2의 내용이다.
A0 = 환원장치의 Upstream 
A1 = 환원장치의 Downstrream
A2 = 외부공기 혹은 차단(off)
A3,A4,A5,A6,A7은 항상 0 이다.

추가설명 #4 모드1 PID 1C
1 바이트의 응답, OBD의 표준을 응답한다.
 
0x01 = 0000 0001 = 장치는 OBD-II 이며, CARB로 정의됨. 
0x02 = 0000 0010 = 장치는 OBD 이며,EPA로 정의됨.
0x03 = 0000 0011 = 장치는 OBD와 OBD-II 이다.
0x04 = 0000 0100 = 장치는 OBD-I 이다.
0x05 = 0000 0101 = 장치는 OBD와 호환이다.
0x06 = 0000 0110 = 장치는 EOBD 이다
 
추가설명 #5 모드3, PID 없음.
6 바이트 DTC 코드이다. 하나의 DTC 코드는 2 바이트로 다음과 같다,
응답 6 바이트는 2 바이트씩 나누어진, 5 문자로 된 3 조의 DTC 코드이다.
모드3의 DTC 응답은 예를 들면, P1115, C1048, U0158 등으로 나타낼 수 있다.
 
첫 바이트의 상위 2비트는 DTC 계통을 나타낸다.
비트 A7,A6은 00 = P, 01 = C, 10 = B, 11 = U 를 나타낸다.
U = Powertrain = 동력장치 고장이다. (2005 DTC 표준)
C = Chassis = 엔진장치의 고장이다.
B = Body = 몸체,기타 장치의 고장이다.
U = Network = 통신장치의 고장이다. (2005 DTC 표준)
비트 A5, A4는 0~3의 숫자를 나타낸다.
비트 A3,A2,A1,A0의 4비트는 100자리 0~9의 숫자를 나타낸다.
2 번째 바이트는 4 비트씩 10자리와 1자리 0~9의 숫자를 나타낸다.

즉, DTC 코드는 2 바이트씩 5 개의 문자로 변환도니다, 예를 들면 "P1115".
나머지 4 바이트는 2 바이트씩 구분되는, 2조의 "5문자의 DTC 코드" 이다. 


PID 사용 예
설명에 나오는 2자리 숫자는 진법표시기호(prefix) 0x가 생략된 16진으로 표현된 1 바이트 값이다.
(진단기에서 송신하는 PID ---> ECU에서 송신하는 응답 값)
81 ---> E9 8F                  // ECU를 깨운다
01 00 ---> B2 3F F8 11      // PID 모드 01, 번호 1, 3, 4, 5, 6, 7, b, v, d, e, f, 10, 11, 12, 13, 14, 15, 1c, 20은 같은 포맷
01 20 ---> 80 00 00 00       // PID 모드 01, 번호 21은 같은 포맷. 
02 00 00 ---> 7E 38 00 00   // PID 모드02, 번호 2 3 4 5 6 7 b c d는 같은 포맷. 
05 00 00 ---> 7F 05 11       // PID 모드 05 
06 00 ---> FF C0 80 00      // PID 모드 06, 번호 1 2 3 4 5 6 7 8 9 a 11은 같은 포맷
08 00 00 00 00 00 00 ---> 7F 08 11   // PID 모드 08
09 00 00 ---> 01 30 00 00 00            // PID 모드 09
 
01 01 ---> 01 07 69 00         // MIL 상태(status)를 읽어온다
03 -> 07 02 00 00 00 00        // 3개의 DTC를 읽어온다 (P0702)
   
01 05 ---> 3A                     // 엔진냉각수 온도 (3A =58 => 58-40 =18'c)
01 13 ---> 03                      // 산소센서 수(비트의 수) (03 =00000011 => 2개)

-----------------------------------------------------------------------------------------------------------------
DTC 코드의 예: 

일반 및 현대차의 DTC 코드는 첨부파일 #1을 참조하십시요

KIA의 OBD-II DTC 코드 (P1115 ~ P1797)
P1115 Engine Coolant Temperature Signal from ECM to TCM.
P1121 Throttle Position Sensor Signal Malfunction from ECM to TCM.
P1170 Front Heated Oxygen Sensor Stuck.
P1195 EGR Pressure Sensor (1.6L) or Boost Sensor (1.8L) Open or Short.
P1196 Ignition Switch "Start" Open or Short (1.6L).
P1250 Pressure Regulator Control Solenoid Valve Open or Short.
P1252 Pressure Regulator Control Solenoid Valve No. 2 Circuit Malfunction.
P1307 Chassis Acceleration Sensor Signal Malfunction.
P1308 Chassis Acceleration Sensor Signal Low.
P1309 Chassis Acceleration Sensor Signal High.
P1345 No SGC Signal (1.6L).
P1386 Knock Sensor Control Zero Test.
P1402 EGR Valve Position Sensor Open or Short.
P1449 Canister Drain Cut Valve Open or Short (1.8L).
P1450 Excessive Vacuum Leak.
P1455 Fuel Tank Sending Unit Open or Short (1.8L).
P1457 Purge Solenoid Valve Low System Malfunction.
P1458 A/C Compressor Control Signal Malfunction.
P1485 EGR Solenoid Valve Vacuum Open or Short.
P1486 EGR Solenoid Valve Vent Open or Short.
P1487 EGR Boost Sensor Solenoid Valve Open or Short.
P1496 EGR Stepper Motor Malfunction - Circuit 1 (1.8L).
P1497 EGR Stepper Motor Malfunction - Circuit 2 (1.8L).
P1498 EGR Stepper Motor Malfunction - Circuit 3 (1.8L).
P1499 EGR Stepper Motor Malfunction - Circuit 4 (1.8L).
P1500 No Vehicle Speed Signal to TCM.
P1505 Idle Air Control Valve Opening Coil Voltage Low.
P1506 Idle Air Control Valve Opening Coil Voltage High.
P1507 Idle Air Control Valve Closing Coil Voltage Low.
P1508 Idle Air Control Valve Closing Coil Voltage High.
P1523 VICS Solenoid Valve.
P1586 A/T-M/T Codification.
P1608 PCM Malfunction.
P1611 MIL Request Circuit Voltage Low.
P1614 MIL Request Circuit Voltage High.
P1624 MIL Request Signal from TCM to ECM.
P1631 Alternator "T" Open or No Power Output (1.8L).
P1632 Battery Voltage Detection Circuit for Alternator Regulator (1.8L).
P1633 Battery Overcharge.
P1634 Alternator "B" Open (1.8L).
P1693 MIL Circuit Malfunction.
P1743 Torque Converter Clutch Solenoid Valve Open or Short.
P1794 Battery or Circuit Failure.
P1795 4WD Switch Signal Malfunction.
P1797 P or N Range Signal or Clutch Pedal Position Switch Open or Short.


-----------------------------------------------------------------------------------------------------------------
SAE J1979의 PID 송수신 처리
참조 사이트 : http://opengauge.googlecode.com/svn/trunk/obduino/

이 자료는 OBD-II 인터페이스 중에서, K Line Interface MC33290을 사용하는 진단기에서,
ISO 9141 표준으로 K-Line 인터페이스를 초기화, 송신, 수신하는 함수에 대한 설명이다.


ISO 9141의 연결 방법 (적색은 ECU의 연결 응답)
1(300ms) -> 33(1060ms) -> 55(0.96) -> 08(0.96) -> 08(0.96) -> 7F(0.96) -> CC(0.96) [ms]
   대기     연결요청(5 bps)    응답1        응답2         응답3          연결OK      응답4
        

// 포트를 정의
#define K_IN    2
#define K_OUT   3
#define TOPLEFT  0
#define TOPRIGHT 1
#define BOTTOMLEFT  2
#define BOTTOMRIGHT 3
 
// LCD 핀의 정의
이 값을 바꾸면, 아듀이노 기판에 연결하는 LCD의 포트를 바꿀 수 있다. 
#define DIPin 4              // LCD RS 핀
#define EnablePin 5       // lCD ENB 핀

#define DB4Pin 7
#define DB5Pin 8
#define DB6Pin 12
#define DB7Pin 13

#define ContrastPin 6      // LCD의 명암을 누름단추로 조절
#define BrightnessPin 9   // LCD의 밝기를 누름단추로 조절
 
// 포트를 설정
pinMode(K_OUT, OUTPUT);  // ISO 9141 TX 핀
pinMode(K_IN, INPUT);        // ISO 9141 RX 핀

pinMode( lbuttonPin, INPUT );   // 누름 단추 3 개는 입력
pinMode( mbuttonPin, INPUT );
pinMode( rbuttonPin, INPUT );

digitalWrite( lbuttonPin, HIGH);  // 누름단추 포트용 내부 풀업 (포트핀의 풀업저항이 필요없다)
digitalWrite( mbuttonPin, HIGH);
digitalWrite( rbuttonPin, HIGH);

-----------------------------------------------------------------------------------------------------------------
파라메터, LCD를 초기화
if(params_load() ==0)    // 설정값이 없으면, 다음과 같이 초기값을 저장
{
  params.contrast =40;
  params.useMetric =1;
  params.perHourSpeed =20;
  params.vol_eff =80;  // 연료 효율 =80%, MPA을 위한 근접에 필요
  params.eng_dis =20;  // 엔진 크기 =2.0L
  params.trip_dist =0.0;
  params.trip_fuel =0.0;
  params.screen[0].corner[TOPLEFT] =FUEL_CONS;
  params.screen[0].corner[TOPRIGHT] =TRIP_CONS;
  params.screen[0].corner[BOTTOMLEFT] =ENGINE_RPM;
  params.screen[0].corner[BOTTOMRIGHT] =VEHICLE_SPEED;
  params.screen[1].corner[TOPLEFT] =TRIP_CONS;
  params.screen[1].corner[TOPRIGHT] =TRIP_DIST;
  params.screen[1].corner[BOTTOMLEFT] =COOLANT_TEMP;
  params.screen[1].corner[BOTTOMRIGHT] =CAT_TEMP_B1S1;
  params.screen[2].corner[TOPLEFT] =PID_SUPPORT20;
  params.screen[2].corner[TOPRIGHT] =PID_SUPPORT40;
  params.screen[2].corner[BOTTOMLEFT] =PID_SUPPORT60;
  params.screen[2].corner[BOTTOMRIGHT] =OBD_STD;
}

-----------------------------------------------------------------------------------------------------------------
ISO 9141 포트를 초기화
ISO 9141의 인터페이스 방법은 PID를 송수신하는 방법으로 설명됩니다.
byte iso_init()
{
  byte b;

  digitalWrite(K_OUT, HIGH);  // K핀을 300ms 동안 HIGh로 만듭니다, (ECU 대기)
  delay(300);
 
  digitalWrite(K_OUT, LOW);   // K핀을 200ms 동안 LOW로 만듭니다, 5bps 시작비트 
  delay(200);
  b =0x33;                             // 0x33 즉 00110011를 송신, 5 bps 데이터 비트 8개
  for (byte mask = 0x01; mask; mask <<= 1)  // mask값 0x01을 0x80 이 될 때 까지 8번 반복 (LSB 우선송신)
  {
    if (b & mask) digitalWrite(K_OUT, HIGH);   //  비트 1을 송신
    else digitalWrite(K_OUT, LOW);   // 비트 0을 송신
    delay(200);                               // 비트의 간격은 5 bps로 200ms 이다 (아직은 ISO 9141 송신함수를 사용할 수 없다)
  }

  digitalWrite(K_OUT, HIGH);            // 정지 비트의 송신, 200ms 이 필요, 
  delay(200);                                 // 5 bps 정지 비트
  delay(60);                                   // 60ms 추가로 대기한다 (ISO 표준 값이다) 이제 ECU와 ISO9141 통신이 가능하다.

  b =iso_read_byte();       // 이제 10400 pcs로 ECU의 데이터를 기다린다
  if (b !=0x55) return -1;    // ECU에서 응답하는 첫 데이터가 0x55 가 아니면 연결 실패다.
  delay(5);

  b=iso_read_byte();         // 첫 데이터가 0x55이면, ECU의 다음 데이터를 기다린다.
  if (b !=0x08) return -1;    // 두번째 데이터가 0x08이 아니면 연결 실패이다.
  delay(20);
 
  b =iso_read_byte();       // 두번째 데이터가 0x08 이면, ECU의 다음 데이터를 기다린다. 
  if(b!=0x08) return -1;      // 세번째 데이터가 0x08 이면, 연결이 성공, ECU로 응답을 해야 한다
  delay(25);
 
  iso_write_byte(0xF7);    // ECU의 응답이 성공이라는 확인으로 0xF7을 송신한다
  delay(25);
 
  b =iso_read_byte();       // ECU로 부터 마지막 응답 0xCC가 들어 오면 연결괸 것이다.  (연결 성공)
  if(b !=0xCC) return -1;   // ISO 9141 연결이 실패이면 -1을 가지고 나간다
  return 0;                      // ISO 9141 연결이 성공이면 0을 가지고 나간다
}
이제 ISO 9141 연결에 성공하였으므로, ISO 9141 송/수신 함수를 사용할 수 있다.

-----------------------------------------------------------------------------------------------------------------
ISO 9141 송신 함수
#define _bitPeriod 1000000L/10400L   //  ISO 9141의 1 비트 주기는 10400 bps = 1000000/10400 = 96

void iso_write_byte(byte b)
{
  int bitDelay = _bitPeriod - clockCyclesToMicroseconds(50); // 비트주기 -digitalWrite의 처리시간을 보정
  digitalWrite(K_OUT, LOW);
  delayMicroseconds(bitDelay);        // ISO 9141 연결핀 K에 LOW를 1비트 송신한다 (시작 비트)
 
  for (byte mask = 0x01; mask; mask <<= 1)  // LSB를 우선으로 8 비트를 송신 (무조건 송신)
  {
    if (b & mask) digitalWrite(K_OUT, HIGH);   // 비트 1을 1개 송신 
    else digitalWrite(K_OUT, LOW);                // 비트 0을 1개 송신
    delayMicroseconds(bitDelay);
  }
  digitalWrite(K_OUT, HIGH);                        // ISO 9141에 연결된 핀 K에 HIGH를 송신 (정지 비트) 
  delayMicroseconds(bitDelay);                  // ISO 9141는 1선으로 송수신하므로 송신할 때는 수신이 안된다.
}

-----------------------------------------------------------------------------------------------------------------
ISO 9141 수신함수
int iso_read_byte()
{
  int val = 0;
  unsigned long timeout;

  int bitDelay = _bitPeriod - clockCyclesToMicroseconds(50);  // 비트주기 -digitalWrite의 처리시간을 보정
 
  timeout =millis();
  while (digitalRead(K_IN))    // 시작 비트를 기다린다
  {
    if((millis()-timeout) > 300L) return -1;  // 300ms이 지나면 수신 불량이다.
  }

 
  if (digitalRead(K_IN) == LOW)   // 처음으로 LOW가 나타나면, 이제부터 수신이 시작된다
  {
    delayMicroseconds(bitDelay / 2 - clockCyclesToMicroseconds(50));  //
비트폭의 중간에서 수신을 시작한다.
    for (int offset =0; offset <8; offset++)    // 8 비트를 수신한다, 비트0 ~ 비트7을 수신
    {
      delayMicroseconds(bitDelay);          // 비트폭의 중간에서 비트값을 읽는다

      val |=digitalRead(K_IN) << offset;     // 읽은 비트를 변수에 저장하고, 좌로 1비트 시프트
    }
    delayMicroseconds(_bitPeriod);         // 남은 비트폭을 기다린다 (다음 바이트 수신을 위함)  
    return val;                                        // 수신한 8 비트 =1 바이트를 가지고 나간다. (수신 성공)
  }
  return -1;                                           // 수신 실패는 -1을 가지고 나간다
}

-----------------------------------------------------------------------------------------------------------------
ISO 9141 테이터 읽기
ECU에서 응답하는 ISO 9141의 데이터 패킷을 iso_read_byte()을 호출하여 읽는다
ECU의 응답 데이터 패킷은 +header + cmd + crc로 구성된다.
수신할 바이트 갯수와 저장할 버퍼를 가지고 호출해야 한다, 데이터만 buf[20]에 저장된다.

byte iso_read_data(byte *data, byte len)
{
  byte i;
  byte buf[20];
 
  // 머리문자 3 바이트: [80 + datalen] [destination = F1] [source = 01] (예: 83, F1, 01)
  // 데이터 1 + len 바이트 : [40 +cmd0] [result0], CRC,  (예: C1, E9, 8F, AE)
    for(i=0;  i<3+1+1+len;  i++)       // 수신할 바이트의 갯수는 5 + 데이터 길이 len 이다.
    buf[i] =iso_read_byte();         // ISO 9141 에서 데이터를 바이트로 읽는다
  // 머리문자 3개는 점검하지 않는다, 오류코드 0x7f와 CRC도 점검하지 않는다.
  memcpy(data, buf +4, len);      // 수신한 패킷에서, 데이터는 5번째 바이트 부터이다. 
  return len;
}

진단기가 ECU로 PID를 송신하면. (예 MODE=01,PID=00의 송신은 0x68 0x6A 0xF1 0x01 0x00 0xC4)
ECU가 진단기로 응답한다. (예 응답은 0x48 0x6B 0x41 0x01 XX XX XX XX CRC 이다, XX는 응답 데이터)
송신 머리문자 0x68 0x6A 0xF1는 진단기에서 PID를 송신할 때 추가되며,
수신 머리문자  0x48 0x6B 0x41 0x01는 ECU에서 응답할 때 추가된다. (0x41은 ECU 번호+0x40, 0x01은 요청한 PID)

-----------------------------------------------------------------------------------------------------------------
ISO 9141 테이터 쓰기

송신버퍼 data에 저장된 데이터에 송신용 머리문자 3개를 추가하고,
송신 데이터의 마지막에는 CRC를 만들어 추가한 다음에.
송신버퍼에 들아있는 모든 문자를 iso_write_byte() 함수를 반복 호출하여 송신한다.  
 
byte iso_write_data(byte *data, byte len)
{
  byte i, n;
  byte buf[20];
 
  buf[0] =0x68;  // ISO 머리문자(header)
  buf[1] =0x6A;  // 0x68 0x6A 는 OBD-II 의 요청 명령이다t
  buf[2] =0xF1;  // 진단기의 주소 (송신주소)

  for (i =0; i<len;  i++)  buf[i+3] =data[i];  // 머리문자는 3개 뒤에 데이터를 추가한다
  i +=3;             
  buf[i] =iso_checksum(buf, i);   // 송신 CRC를 만든다음 송신버퍼의 마지막에 추가한다
  n =i +1;           // 송신 바이트 갯수에 CRC를 추가한다
  for(i =0; i <n;  i++)
  {
    iso_write_byte(buf[i]);    // 1 바이트씩 송신버퍼를 ISO 9141 인터페이스로 송신한다
    delay(20);                     // 1 바이트 마다 20ms 지연시간을 준다.
  }
  return 0;
}
 
-----------------------------------------------------------------------------------------------------------------
SAE J1979의
CRC생성 함수
J1979의 CRC는 머리,,, 데이터끝 까지 0x00에 모두 더한 값이며, 덧셈에서 발행하는 자리올림은 사용하지 않고 버린다.
J1979의 CRC는 송,수신 패킷의 마지막에 추가 되어야 하며, 주로 송신 패킷에서 사용한다. 
 
byte iso_checksum(byte *data, byte len)
{
  byte i;
  byte crc;
 
  crc=0;                 // CRC의 초기값은 0 이다.
  for(i=0;  i <len;  i++) crc=crc +data[i];    // 송신버퍼에 들은 데이터를 모두 CRC에 더한다
  return crc;
}

-----------------------------------------------------------------------------------------------------------------
SAE J1979의 PID 읽기 함수
참조 사이트 : http://opengauge.googlecode.com/svn/trunk/obduino/

이 자료는 OBD-II 인터페이스 중에서, K Line Interface MC33290을 사용하는 진단기에서,
SAE J1979 표준 PID를 송신하고, 응답하는 데이터를 수신하는 PID 함수이다.
이 함수를 실행하려면, ECU로 요청하는 PID 번호 와 ECU의 응답을 저장하는 32비트 버퍼가 필요하다.
PID 번호ISO송신 함수를 실행하여 ECU로 전송되고, ISO수신 함수에서 받은 데이터는 지정된 retbuf에 저장한다.

unsigned long  pid01to20_support;
unsigned long  pid21to40_support;
unsigned long  pid41to60_support;

long get_pid(byte pid, char *retbuf) 
{
  byte i;
  byte cmd[2];   // 송신 PID를 저장하는 변수
  byte buf[10];   // 수신 데이터를 저장하는 변수
  long ret;          // 결과를 저장하는 4바이트 변수
  byte reslen;     // 결과의 길이를 저장하는 변수
  char decs[16]; // 결과를 문자로 변환하는 작업용 변수
 
  if( pid !=0x00)  // 0x00 =PID_SUPPORT20 , PID 요청값이 PID를 지원하는지 확인한다.
  {
    if( (pid <=0x20 && ( 1L <<(0x20 -pid) & pid01to20_support ) == 0 )
      ||  (pid  >0x20 && pid <=0x40 && ( 1L <<(0x40-pid) & pid21to40_support )  == 0 )
      ||  (pid  >0x40 && pid <=0x60 && ( 1L <<(0x60-pid) & pid41to60_support )  == 0 )
      ||  (pid  >LAST_PID) )
    {
      sprintf_P(retbuf, PSTR("%02X N/A"), pid);      // PID 확인결과를 "아님"으로 표시
      return -1;                                                   // 아닌 경우는 나머지를 실해하지 않고 이 함수를 끝낸다. 
    }
  }
  reslen =pgm_read_byte_near(pid_reslen+pid);  // PID 번호에 따르는 데이터의 길이를 구한다
  cmd[0] =0x01;                                              // ISO 명령은 1 바이트이다
  cmd[1] =pid;                                                // 요청된 PID값을 변수에 저장   
  iso_write_data(cmd, 2);      // ISO 송신함수를 실행, PID값을 ECU로 송신.
  iso_read_data(buf, reslen);  // ISO 수신함수를 실행, ECU에서 응답한 데이터를 수신.
 
  switch(pid)                        // SAE 표준 공식과 단위를 사용, PID 응답을 분리하고 계산한다.
  {
    case 0x0C:    // ENGINE_RPM =엔진 회전수
    ret=(buf[0]*256U+buf[1])/4U;
    sprintf_P(retbuf, PSTR("%ld RPM"), ret);
    break;
 
    case 0x10:    // MAF_AIR_FLOW =흡기관 공기속도
    ret=buf[0]*256U+buf[1];
    int_to_dec_str(ret, decs, 2);    // not divided by 100 for return value!!
    sprintf_P(retbuf, PSTR("%s g/s"), decs);
    break;
 
    case 0x0D:    // VEHICLE_SPEED =차량 속도
    ret=buf[0];
    if(!params.useMetric) ret=(ret*621U)/1000U;
    sprintf_P(retbuf, PSTR("%ld %s"), ret, params.useMetric?"":"");
    break;
   
    case 0x03:    // FUEL_STATUS =연료 상태
    ret=buf[0] *256U +buf[1];
    if(buf[0]==0x01) sprintf_P(retbuf, PSTR("OPENLOWT"));        // 엔진 온도 낮음
    else if(buf[0]==0x02) sprintf_P(retbuf, PSTR("CLSEOXYS"));  // Closed loop, 산소 센서값을 연료혼합으로 되돌린다.
    else if(buf[0]==0x04) sprintf_P(retbuf, PSTR("OPENLOAD"));  // Open loop 엔진 부하 [%]
    else if(buf[0]==0x08) sprintf_P(retbuf, PSTR("OPENFAIL"));   // Open loop 고장난 장치
    else if(buf[0]==0x10) sprintf_P(retbuf, PSTR("CLSEBADF"));  // Closed loop, 최근에 고장난 장치의 산소센서
    else sprintf_P(retbuf, PSTR("%04lX"), ret);
    break;
  
  // 다음 12개의 PID 결과는 1 바이트로 모두 [%] 형식이다.  
  case 0x04:    // LOAD_VALUE =엔진 부하
  case 0x11:    // THROTTLE_POS =가속발판 위치
  case 0x45:    // REL_THR_POS =가속발판 위치 %값
  case 0x2C:    // EGR =배기 혼합장치
  case 0x2D:    // EGR_ERROR =배기 혼합장치 오류
  case 0x2F:    // FUEL_LEVEL =연료 잔량
  case 0x47:    // ABS_THR_POS_B =미끄럼방지 가속기 위치 B
  case 0x48:    // ABS_THR_POS_C =미끄럼방지 가속기 위치 C
  case 0x49:    // ACCEL_PEDAL_D =가속 D
  case 0x4A:    // ACCEL_PEDAL_E =가속 E
  case 0x4B:    // ACCEL_PEDAL_F =가속 F
  case 0x4C:    // CMD_THR_ACTU =가속 구동값:
    ret=(buf[0] *100U) /255U;    // 0~255 범위의 결과를 [%]로 계산한다.
    sprintf_P(retbuf, PSTR("%ld %%"), ret);    // %값을 10진으로 변환하고, ret 변수에 저장
  
  // 다음 8개의 PID 응답은 [mV]로 변환한다.
  case 0x14:    // B1S1_O2_V =산소센서 1-1 전압  
  case 0x15:    // B1S2_O2_V =산소센서 1-2 전압
  case 0x16:    // B1S3_O2_V =산소센서 1-3 전압
  case 0x17:    // B1S4_O2_V =산소센서 1-4 전압
  case 0x18:    // B2S1_O2_V =산소센서 2-1 전압
  case 0x19:    // B2S2_O2_V =산소센서 2-2 전압
  case 0x1A:    // B2S3_O2_V =산소센서 2-3 전압
  case 0x1B:    // B2S4_O2_V =산소센서 2-4 전압
    ret =buf[0] *5U;  // 결과를 1000으로 나누지 않음
    if(buf[1] ==0xFF) sprintf_P(retbuf, PSTR("%ld mV"), ret);  // 첫 바이트 = 0xFF 이면, 결과를 바로 10진으로 저장
    else sprintf_P(retbuf, PSTR("%ldmV/%d%%"), ret, ((buf[1]-128)*100)/128);  // 0xFF가 아니면, 결과를 계산하고 저장
    break;             // 결과의 첫 바이트 최상위 비트가 1이 아니면, 나머지 7비트를 [%]로 계산한다. 
    
  case 0x21:    // DIST_MIL_ON =계기판의 엔진고장 등을 켠다
  case 0x31:    // DIST_MIL_CLR =계기판의 엔진고장 등을 끈다
    ret =buf[0] *256U +buf[1];  // 결과 1 바이트 2 개를, 2바이트 정수로 변환한다.
    if(!params.useMetric) ret =(ret *621U) /1000U;    // 저장된 2바이트 정수를 *621/1000으로 계산한다
    sprintf_P(retbuf, PSTR("%ld %s"), ret, params.useMetric?"":"mi");    // 10진으로 변환해서 문자로 저장한다
    break;
   
  case 0x4D:    // TIME_MIL_ON =고장표시등이 점등된 시간
  case 0x4E:    // TIME_MIL_CLR =고장 표시등이 소등된 시간
    ret=buf[0] *256U +buf[1];    // 2 바이트 정수로 변환
    sprintf_P(retbuf, PSTR("%ld min"), ret);    // 10진 문자로 변환한 시간을 분(min)으로 표시한다
    break;
   
  case 0x05:    // COOLANT_TEMP =냉각수 온도
  case 0x0F:    // INT_AIR_TEMP =흡기관 온도
  case 0x46:    // AMBIENT_TEMP =주위 온도
  case 0x3C:    // CAT_TEMP_B1S1 =환원장치 온도 #1-1
  case 0x3D:    // CAT_TEMP_B2S1 =환원장치 온도 #2-1
  case 0x3E:    // CAT_TEMP_B1S2 =환원장치 온도 #1-2
  case 0x3F:    // CAT_TEMP_B2S2 =환원장치 온도 #2-2
    if(pid >=0x3C && pid <=0x3F)  // 산소센서의 온도를 계산
      ret =(buf[0] *256U +buf[1]) /10U -40;    // 10으로 나누고 40을 뺀다음, 온도로 저장한다 .
    else ret =buf[0] -40;              // 산소센서가 아니면 40을 뺀다음, 온도로 저장한다.

    if(!params.useMetric) ret =(ret *9) /5 +32;                     // 선택한 단위가 Metric 이면 섭씨로 변환한다
    sprintf_P(retbuf, PSTR("%ld%c"), ret, params.useMetric?'C':'F');  // 10진 문자로 단위와 같이 저장한다,
    break;
   
  case 0x06:    // STF_BANK1 =단시간 연료 %조절 #1
  case 0x07:    // LTR_BANK1 =장시간 연료 %조절 #1
  case 0x08:    // STF_BANK2 =단시간 연료 %조절 #2
  case 0x09:    // LTR_BANK2 =장시간 연료 %조절 #2
    ret=(buf[0]-128) *7812;  // 첫 바이트 최상위 비트를 지우고, 7 비트(A6~A0)에 7812를 곱한다음 저장한다.
    int_to_dec_str(ret/100, decs, 2);  // 결과를 100으로 나누고, 10진 문자 2자리로 변환한다, (10000 으로 나누지 않음)
    sprintf_P(retbuf, PSTR("%s %%"), decs); 
    break;
 
  case 0x0A:    // FUEL_PRESSURE =연료분사 압력
  case 0x0B:    // MAN_PRESSURE =분기관 압력
  case 0x33:    // BARO_PRESSURE =공기 압력
    ret=buf[0];
    if(pid ==0x0A) ret *=3U;  // 만일 응답값이 FUEL_PRESSURE 이면, 3을 곱해서 저장한다.
    sprintf_P(retbuf, PSTR("%ld kPa"), ret);  // 표시하는 값은 kPa(압력의 단위) 이다
    break;
 
  case 0x0E:    // TIMING_ADV =실린더 상대 각도 [deg] (점화시기)
    ret =(buf[0] /2) -64;    // 응답값을 2로 나누고 -64를 한다음 저장한다.
    sprintf_P(retbuf, PSTR("%ld"), ret);
    break;
  
  case 0x1C:    // OBD_STD =연결된 ECU가 지원하는 OBD 표준을 나타낸다 (254 바이트)
    ret =buf[0];  // 응답으로 들어온 값으로 부터, OBD 표준에 해당하는 하나의 이름을 선택하여 표시한다
    if(buf[0] ==0x01) sprintf_P(retbuf, PSTR("OBD2CARB"));    // 응답이 0x01 이면 OBD2 CARB 표준을 지원한다.
    else if(buf[0]==0x02) sprintf_P(retbuf, PSTR("OBD2EPA"));    // 응답이 0x02 이면 OBD2 EPA 표준을 지원한다.
    else if(buf[0]==0x03) sprintf_P(retbuf, PSTR("OBD1&2"));    // 응답이 0x03 이면 OBD1과 2 표준을 지원한다.
    else if(buf[0]==0x04) sprintf_P(retbuf, PSTR("OBD1"));    // 응답이 0x04 이면 OBD1 표준을 지원한다.
    else if(buf[0]==0x05) sprintf_P(retbuf, PSTR("NOT OBD"));    // 응답이 0x05 이면 OBD를 지원하지 않는다.
    else if(buf[0]==0x06) sprintf_P(retbuf, PSTR("EOBD"));    //응답이 0x06 이면  EOBD 표준을 지원한다.
    else if(buf[0]==0x07) sprintf_P(retbuf, PSTR("EOBD&2"));    //응답이 0x07 이면  EOBD2 표준을 지원한다.
    else if(buf[0]==0x08) sprintf_P(retbuf, PSTR("EOBD&1"));//응답이 0x08 이면  EOBD1 표준을 지원한다.
    else if(buf[0]==0x09) sprintf_P(retbuf, PSTR("EOBD&1&2"));//응답이 0x09 이면  EOBD1과 2 표준을 지원한다.
    else if(buf[0]==0x0a) sprintf_P(retbuf, PSTR("JOBD"));    //응답이 0x0A 이면  JOBD 표준을 지원한다.
    else if(buf[0]==0x0b) sprintf_P(retbuf, PSTR("JOBD&2"));    //응답이 0x0B 이면  JOBD2 표준을 지원한다.
    else if(buf[0]==0x0c) sprintf_P(retbuf, PSTR("JOBD&1"));    //응답이 0x0C 이면  JOBD1 표준을 지원한다.
    else if(buf[0]==0x0d) sprintf_P(retbuf, PSTR("JOBD&1&2"));    // 응답이 0x0D이면, JOBD1과 2 표준을 지원한다.
    else sprintf_P(retbuf, PSTR("OBD:%02X"), buf[0]);  // 위 항목에서 발견하지 못한 값이면, OBD ?? 표준을 지원한다.
    break;

    default:  // 처리항목에 없는 데이터는 들어온 값을 처리없이 그대로 표시한다
    ret=0;    // (처리하지 못한 항목은, 나가는 값이 0 이다)
    for(i=0; i<reslen; i++)
    {
      ret *=256L;
      ret +=buf[i];    // 응답 1 바이트 2개를, 2 바이트 정수로 변환 
    }
    sprintf_P(retbuf, PSTR("%08lX"), ret);    // 문자로 변환하여 retbuf에 저장
    break;
  }
  return ret;         // 선택 처리된 1개 항목의 결과는 ret에 저장된다, 2 바이트 정수값을 주함수로 돌려준다
}                       // 수신된 데이터를 LCD에 표시하는 문자는 retbuf 에 저장되어 있다.

지금까지 OBD-II 인터페이스 ISO1941의 초기화, 송신, 수신, PID송신, PID수신 함수에 대해 설명하였습니다.
다음번엔 OBD-II 인터페이스 ISO9141 PID 처리함수와 주함수에 대해서 알아 보도록 하겟습니다.

이 프로그램은 무료 소프트웨어로, 신체와 재산 상의 어떤 위험과 손해를 보상하지 않습니다.
이 프로그램은 GNU 무료 소프트웨어 배포규정을 따릅니다.
Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA


AVRTOOLS™
   
윗글 아듀이노 OBD-II PID 처리함수
아래글 아듀이노 ODB-II 스캐너 제작
    N         제목    글쓴이 작성일 조회 추천
61 비접점식 QTouch 방식 근접검출 스위치 leeky 2016/01/21 (목) 852 0
60 Arduino 고속 오실로스코프 #3 avrtools™ 2012/03/29 (목) 17930 0
59 아날로그 8ch 데이터 로거 avrtools™ 2012/03/29 (목) 2925 0
58 Arduino DMX512 송신기 제작 avrtools™ 2012/03/15 (목) 3063 0
57 nRF24L01 무선모듈의 사용방법 avrtools™ 2012/03/07 (수) 6112 0
56 초음파 거리 측정기의 제작 avrtools™ 2011/09/18 (일) 5029 0
55 3축 가속도 센서 ADXL335 avrtools™ 2011/09/09 (금) 3559 0
54 Arduino Uno USBserial 펌웨어의 변경 avrtools™ 2011/08/27 (토) 3122 0
53 Arduino MIDI의 소개 avrtools™ 2011/08/19 (금) 3524 0
52 Arduino 고속 Oscillo Scope #2 avrtools™ 2011/08/12 (금) 3149 0
51 Arduino Uno 및 USB2serial Uno의 소개 [2] avrtools™ 2011/07/30 (토) 3417 0
50 Arduino IDE에서 AVRISP-mkII 사용방법 avrtools™ 2010/10/22 (금) 8092 0
49 아듀이노 초음파 거리측정 및 응용 avrtools™ 2010/03/14 (일) 4234 0
48 M328-USB의 비밀 온도센서 avrtools™ 2010/01/02 (토) 3650 0
47 M168-mini로 만드는 USBasp avrtools™ 2009/10/10 (토) 5504 0
46 OBDuino ISO9141 소스의 설명 avrtools™ 2009/10/08 (목) 4291 0
45 아듀이노 0017 업그레이드 avrtools™ 2009/08/18 (화) 3803 0
44 Arduino 0015 업그레이드 avrtools™ 2009/06/01 (월) 3491 0
43 CC2500 Zigbee RF Modem #1 [4] avrtools™ 2008/11/20 (목) 6772 0
42 아듀이노 소프트웨어 Ver 0012 avrtools™ 2008/09/23 (화) 4085 0
41 Arduino 소프트웨어 설치방법 avrtools™ 2008/08/31 (일) 5701 0
40 아듀이노 PC 카메라 제작 avrtools™ 2008/10/28 (화) 7328 0
39 아듀이노 AVR-ISP V2의 제작 [6] avrtools™ 2008/10/22 (수) 8435 0
38 아듀이노 J1850-PWM 스캐너 avrtools™ 2008/10/15 (수) 4612 0
37 아듀이노 MPGduino의 제작 avrtools™ 2008/10/11 (토) 5039 0
36 아듀이노 OBD-II PID 처리함수 avrtools™ 2008/10/12 (일) 5712 0
35 아듀이노 OBD-II PID 송수신 함수 avrtools™ 2008/10/09 (목) 9786 0
34 아듀이노 ODB-II 스캐너 제작 [9] avrtools™ 2008/10/04 (토) 17564 0
33 아듀이노 AC전원 THD 측정 [2] avrtools™ 2008/09/30 (화) 6890 0
32 아듀이노 소프트방식 16Bit ADC avrtools™ 2008/09/23 (화) 5649 0
31 아듀이노 초음파 모듈의 제작. avrtools™ 2008/09/22 (월) 4962 0
30 아듀이노 Wii 프로세싱 avrtools™ 2008/09/20 (토) 4222 0
29 아듀이노 초음파 거리측정 avrtools™ 2008/09/20 (토) 6161 0
28 아듀이노 8x5 초소형 전광판 avrtools™ 2008/09/11 (목) 4752 0
27 아듀이노 4선식 터치패널 avrtools™ 2008/09/10 (수) 4738 0
26 아듀이노 2색 8x8 LED avrtools™ 2008/09/10 (수) 5015 0
25 아듀이노 24x6 LED 전광판 avrtools™ 2008/09/10 (수) 5553 0
24 아듀이노 8x8 LED 프로세싱 avrtools™ 2008/09/10 (수) 4173 0
23 아듀이노 32x16 RGB 전광판 avrtools™ 2008/09/06 (토) 13763 0
22 아듀이노 맥박검출기 avrtools™ 2008/09/03 (수) 9644 0
21 아듀이노 적외선 거리센서 avrtools™ 2008/09/01 (월) 6053 0
20 아듀이노 DMX 수신장치 [7] avrtools™ 2008/08/31 (일) 6911 0
19 아듀이노 AVR-ISP 만들기 avrtools™ 2008/08/30 (토) 4222 0
18 아듀이노 POV #3 avrtools™ 2008/08/30 (토) 3541 0
17 아듀이노 POV #2 avrtools™ 2008/08/30 (토) 3309 0
16 AVR 병렬포트 굽기장치 avrtools™ 2008/08/30 (토) 5330 0
15 아듀이노 DMX 송신기 avrtools™ 2008/08/28 (목) 5224 0
14 아듀이노 부트로더의 개조 [1] avrtools™ 2008/08/28 (목) 5877 0
13 아듀이노 병렬포트 굽기장치 avrtools™ 2008/08/26 (화) 4284 0
12 아듀이노 POV #1 avrtools™ 2008/08/26 (화) 3558 0
11 아듀이노 MIDI 드럼 leeky 2008/08/24 (일) 4875 0
10 아듀이노 SD/MMC 카드 avrtools™ 2008/08/24 (일) 9878 0
9 아듀이노 MIDI 플륫 avrtools™ 2008/08/24 (일) 3705 0
8 아듀이노 RGB LED avrtools™ 2008/08/23 (토) 5131 0
7 아듀이노 USB 오실로스코프 [2] leeky 2008/08/21 (목) 6545 0
6 가속도계 ADXL202 응용소스 avrtools™ 2008/08/20 (수) 5001 0
5 아듀이노 가속도센서 avrtools™ 2008/08/18 (월) 5010 0
4 아듀이노 RC서보 제어 avrtools™ 2008/08/17 (일) 5337 0
3 아듀이노 910-ISP 만들기 avrtools™ 2008/08/16 (토) 4858 0
2 아듀이노 온도센서, XBee 송수신 avrtools™ 2008/08/15 (금) 7699 0
1 아듀이노 기본명령 avrtools™ 2008/08/07 (목) 6804 0
1

바구니 : 0
 보관함 : 0
오늘뷰 : 0
HOME   |   회사소개   |   제휴안내   |   회사위치   |   서비스이용 약관   |   개인정보 보호정책   |   사이트맵
17015 경기도 용인시 기흥구 동백중앙로16번길 16-25, 508호. 전화 : 031-282-3310
사업자 등록번호 : 697-47-00075 / 대표 : 이건영 / 업태 : 제조업 / 종목 : LED조명, LED전원, 제어장치.
개인정보 관리책임자 : 홈페이지 관리자 . Copyright ⓒ2016 아크레즈 (ACLEDS INC.)
HOME TOP PREVNEXT 0 0 0