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








 게시판 검색





 
 
회원등록 비번분실


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

      거래은행 바로가기
 
 Sensor Applications
아듀이노 공개소스
작성자 avrtools™        
작성일 2008/10/12
Link#1 (Down:297)
ㆍ추천: 0  ㆍ조회: 5830   
  아듀이노 OBD-II PID 처리함수
참조  : http://opengauge.googlecode.com/svn/trunk/obduino/ 
제목 : OBDuino SOurce

이 자료는 OpenGauge OBDuino의 소스중에서 OBD-II를 호출하는 상위 함수들의 기능을 설명한다.
함수들은 ISO9141 인터페이스의 PID 송수신용 함수 get_pid()의 상위함수이다.

물론 PID 송수신 함수 get_pid()도 최하위 실행함수인 iso_write_byte()와 iso_read_byte()를 호출한다. 
예를 들면, loop() --->accu_trip() ---> get_pid() --> iso_write_byte(), iso_read_byte() 등의 하위 함수 실행한다.
 
다시 설명하면, accu_trip()은 loop()와 get_pid()의 중간에서, 가시적인 데이터를 처리를 하는 함수이다.
대부분의 주함수에서는 직접적인 계산이나 복잡하게 여러 함수들을 직접 처리하지 않고,
일반적으로 기능별로 분류된, 몇 개의 함수를 순서대로 호출하는, 매우 단순한 방법을 사용한다.
예를 들면, PID 초기화, 주행거리 계산, 조작검출 및 화면설정, LCD표시 등으로 기능별로 분류된 함수를 호출한다.

------------------------------------------------------------------------------------------------------------------
각종 PID의 처리 함수

void accu_trip(void)  // 주행거리를 계산하는 함수, loop()의 실행과정에서 반드시 한번씩 호출해야 한다.
{
  static byte min_throttle_pos =255;   // 대기상태(idle)의 가속기위치(throttle position)
  byte throttle_pos;    // 현재의 가속기 위치
  byte open_load;      // 가속기 위치가 0 이면, open loop상태이다.
  char str[STRLEN];
  unsigned long time_now, delta_time;

  time_now = millis();  // 현재시간을 구함 (경과 시간을 위함)
  delta_time = time_now - old_time;  // 현재시간 -과거시간 =경과시간 
  old_time = time_now;                    // 다음 경과시간을 위해, 현재시간을 과거시간으로 저장 
  
  vss =get_pid(VEHICLE_SPEED, str);  // 차량속도를 ECU에서 읽는다 [m]
  if (vss>0) params.trip_dist +=((float)vss *(float)delta_time) /3600.0;  // 주행거리 +(현재속도 *경과시간)
  if (! has_rpm)  // if engine is stopped, we can get out now            // 엔진회전이 0 이면 오류상태이다.
  {
    maf=0;
    return;
  }

  throttle_pos =get_pid(THROTTLE_POS, str);   // 가속기 위치를 받는다
  if (throttle_pos <255) min_throttle_pos =255;      // 가속기위치의 최저값을 제한 (DFCO)
  open_load =(get_pid(FUEL_STATUS, str)&0x0400)?1:0;  // 연료상태를 읽는다
  if (throttle_pos <(255 +4) && open_load) maf =0;  // 감속이면 연료를 끊고, 혼합공기량(MAF)은 0
  else
  {
    if ((1L <<(32-MAF_AIR_FLOW) & pid01to20_support) != 0)    // 감속이 아니면 MAF를 지원하는지 확인
    {
      maf =get_pid(MAF_AIR_FLOW, str);       // 가속상태이면 MAF를 읽는다. 
    }
   
    else                                                    // 감속이면 회전수, 흡기압력,공기온도를 읽어서 근사 MAF를 계산한다
    {
      long imap, rpm, map, iat;
     
      rpm =get_pid(ENGINE_RPM, str);          // 추가설명 #1 
      map =get_pid(MAN_PRESSURE, str);
      iat =get_pid(INT_AIR_TEMP, str);
      imap =(rpm *map)/ (iat +273);
      maf =(imap * params.vol_eff * params.eng_dis * 29) /10000;  // 추가설명 #2
    }
    params.trip_fuel +=((float)maf *(float)delta_time) /1073100.0;  // 추가설명 #3
  }
}
 
추가설명 #1
우리는 혼합공기량(MAF)가 없다, 그러나 공기압력(MAP)은 있다.
혼합공기량(No MAF)이 없으면, 
공기압력(MAP)과 절대온도를 사용하면 혼합공기량(MAF)에 근접한다.
IMAP = RPM * MAP / IAT
MAF = (IMAP/120) *(VE/100) *(ED) *(MM)/(R)
MAP - 분배관 절대압력 [kPa]
IAT - 흡기 절대온도 [Kelvin]
R - 연료의 상수 8.314472 [J/(mol.K]
MM - 공기의 평균 분자량  28.9644 [g/mol]
VE - %로 측정된 연료의 체적효율
ED - 엔지 배기용량 [liters]
원리는 정밀한 연료의 체적효율이 요구된다.

추가설명 #2
100으로 나누기 위해 (MAF*100)을 적용한다.

엔진의 배기용량 dL은 10으로 나눈다.
28.9644/(120*8.314472*10)= 약 0.0029 혹은 29/10000


추가설명 #3
MAF 응답을 trip에 더한다, 연료는 mL/s를 사용한다. 
MAF는 air/s의 gram을 준다. MAF 값은 100으로 나누엇다.
14.7 (a/f ratio)로 나누면 of fuel/s의 주입량(grams)이 된다.
이것을 730으로 나누면 L/s로 된다.
이것을 다시 1000 으로 곱하면 mL/s로 된다,
1000 으로 나누는 이유는 delta_time이 ms이기 때문이다.

------------------------------------------------------------------------------------------------------------------
PID를 지원하는지 확인한다.
 
void check_supported_pid(void)
{
  unsigned long n;
  char str[STRLEN];
 
  pid01to20_support =get_pid(PID_SUPPORT20, str);
  pid21to40_support =get_pid(PID_SUPPORT40, str);
  if(pid21to40_support ==-1) pid21to40_support =0;      // 만일 차량이 PID를 지원하지 않으면 -1을 가지고 나간다.

  pid41to60_support =get_pid(PID_SUPPORT60, str);
  if(pid41to60_support ==-1) pid41to60_support =0;
}
 
------------------------------------------------------------------------------------------------------------------
엔진고장 표시등의 상태와 고장번호(DTC 코드)를 읽는다

void check_mil_code(void) 
{
  unsigned long n;
  char str[STRLEN];
  byte nb;
  byte cmd[2];
  byte buf[6];
  byte i, j, k;

  n =get_pid(MIL_CODE, str);
  if( (1L <<31 & n) !=0)       // 4바이트에서 최상위 비트가 1 이면 MIL이 켜져있다
  {
    nb =(n >>24) & 0x7F;    // MIL 응답을 24비트 우시프트하고 비트7을 지운다, MIL 표시등이 켜져있다
    lcd_cls();
    lcd_print_P(PSTR("CHECK ENGINE ON"));           // 고장상태를 표시하고
    lcd_gotoXY(0,1);
    sprintf_P(str, PSTR("%d CODE(S) IN ECU"), nb);  // 고장코드를 표시한다
    lcd_print(str);
    delay(2000);
 
    cmd[0] =0x03;                 // MIL이 켜있으면, DTC 코드를 요청한다 
    iso_write_data(cmd, 1);    // ECU로 DTC를 요청하는 PID 0x03을 송신한다
    for(i=0; i<nb /3; i++)         // 6 바이트 응답은 3개의 DTC 코드이다
    {
      iso_read_data(buf, 6);    // DTC 코드를 읽는다
      lcd_gotoXY(0,1);            // 움직이기 전에 LCD에 매뉴를 쓴다.
      lcd_print(str);
      delay(5000);
      return;
 
      k=0;                              // DTC 코드를 문자로 바꾼다
      for(j =0; j <3; j++)            // 6바이트 코드에 3조의 DTC가 들어있다
      {
        switch(buf[j*2] & 0xC0) // 0,2,4 번째 바이트(각조의 상위 바이트)의 비트7과 비트6은 문자 P,C,B,U 이다
        {
        case 0x00:
          str[k]='P';  // powertrain
          break;
        case 0x40:
          str[k]='C';  // chassis
          break;
        case 0x80:
          str[k]='B';  // body
          break;
        case 0xC0:
          str[k]='U';  // network
          break;
        }
        k++;
        str[k++]='0' + (buf[j*2] & 0x30) >>4;    // 나머지 14 비트는 4자리 숫자의 DTC 번호이다
        str[k++]='0' + (buf[j*2] & 0x0F);
        str[k++]='0' + (buf[j*2 +1] & 0xF0) >>4;
        str[k++]='0' + (buf[j*2 +1] & 0x0F);
      }
      str[k]=0x00;        // 0x00 =NULL           // 고장이 없으면 표시값은 0 이다.
      lcd_print(str);
      lcd_gotoXY(0, 1);  //다음 표시줄로 간다
    }
  }
}

------------------------------------------------------------------------------------------------------------------
MAF와 MPG를 계산한다
 
void get_cons(char *retbuf)
{
  long cons;
  char decs[16];

  if(params.useMetric)                             // Km/h 로 표시 
  {
    if (vss <params.perHourSpeed) cons =(maf *3355L) /10000L;  // 부동소숫점으 사용하지 않는다
    else cons =(maf *3355L) /(vss *100L);   // 10000*100을 하면 100 자리가 된다
    int_to_dec_str(cons, decs, 2);
    sprintf_P (retbuf, PSTR("%s %s"), decs, (vss<params.perHourSpeed)?"L":"" );  // 특수문자를 표시 
  }

  else                                                    // Mile/h 로 표시 
  {
    if ((vss *1609L) /1000L < params.perHourSpeed) cons =maf /114L; // [gallon/hour]
    else if (maf !=0) cons =(vss *7107L) /maf;
    else cons =0;
    int_to_dec_str(cons, decs, 1);
    sprintf_P(retbuf, PSTR("%s %s"), decs, ((vss *1609L) /1000L <params.perHourSpeed) ?"GPH":"MPG" );
  }
}

MAF
MAF*100로 들어온 값인 MAF를 100으로 나누어야 하지만, 계산정도를 위해서 100으로 나누지 않는다.
MAF를 14.7로 나누면 [air/fuel] fuel/s량 g의 비율이 되고, 730 [g/L]로 나누면 [L/s]로 된다.
이 값을 3600으로 곱하면 [L/h] 이다.  공식은 (3600 *MAF) / (14.7 *730 *VSS)  = maf *0.3355 /vss [L/km]
이제 100을 곱하면 마지막 표시값 L/100 km로 된다.

MPG
6.17 [pounds/gallon] = 454 g/pound,
공식은 14.7 *6.17 *454 * (VSS *0.621371) / (3600 *MAF /100) 이다.
마지막으로 10을 곱한다

 
------------------------------------------------------------------------------------------------------------------
주행거리를 계산한다.
 
void get_trip_cons(char *retbuf)
{
  float trip_cons; 
  char decs[16];

  if(params.useMetric)                // Km
  {
    // mL/m을 L/100로 바꾼다, 1000으로 나누면 L 그리고 100000을 곱하면 100 km가 된다.
    if(params.trip_dist ==0.0) trip_cons =0.0;   // 100을 곱해서 정도를 100 자리로 한다
    else trip_cons =(params.trip_fuel/params.trip_dist)*10000.0;
    int_to_dec_str((long)trip_cons, decs, 2);
    sprintf_P(retbuf, PSTR("%s "), decs);   // Km/L 표시
  }

  else                                       // Mile
  {
    // m/mL을 MPG로 바꾸려면, 3.78541178을 곱해서 gallon으로 만들고, 621371을 곱하면 mile로 된다
   if(params.trip_fuel ==0.0) trip_cons=0.0;        // 10을 곱한다
    else trip_cons =(params.trip_dist/params.trip_fuel) *23.52;
    int_to_dec_str((long)trip_cons, decs, 1);
    sprintf_P(retbuf, PSTR("%s MPG"), decs);        // MPG 표시
  }
}

void get_trip_dist(char *retbuf)
{
  float cdist;                              // 주행거리 변수 
  char decs[16];

  cdist =params.trip_dist/100.0;   // 주행거리를 0.1Km로 바꾼다.
  if (! params.useMetric) cdist *=0.621731;     // Mile이면 변환한다.
  int_to_dec_str((long)cdist, decs, 1);
  sprintf_P (retbuf, PSTR("%s %s"), decs, params.useMetric?"":"mi" );
}

------------------------------------------------------------------------------------------------------------------
주함수
void loop()                     // 무한 반복하는 주 함수
{
  char str[STRLEN];

  has_rpm =(get_pid(ENGINE_RPM, str) >0) ?1:0;   // 엔진이 움직이는지 get_pid() 함수를 실행하여 검사
  if(engine_started ==0 && has_rpm !=0)                 // 최초 작동인지를 점검하여 상태를 저장한다
  {
    engine_started =1;
    param_saved =0;
  }
 
  if(param_saved==0 && engine_started!=0 && has_rpm==0)  // 저장된 기록이 없으면, 파라메터를 저장,
  {
    params_save();
    param_saved =1;
    engine_started =0;
 
    lcd_cls();
    lcd_print_P(PSTR("TRIP SAVED!"));           // "주행거리 저장" 을 LCD에 표시한다
    delay(2000);
  }
 
  accu_trip();      // vss와 maf를 읽어서 trip을 계산 (PID함수를 실행하는 이 함수는, 주기적으로 실행해야 한다)
  for(byte cur_corner =0; cur_corner<NBCORNER; cur_corner++)  // NBCONER에 저장된 항목의 수 만큼 표시한다
    display(cur_corner, params.screen[active_screen].corner[cur_corner]);  //설정에서 선택된 항목을 LCD에 표시한다
  test_buttons();  // 누름단추 작동을 처리한다 (이 함수도 주기적으로 실행해야 한다)
}                       // 주함수의 끝, loop()의 처음부터 다시 실행한다.

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


AVRTOOLS™
   
윗글 아듀이노 MPGduino의 제작
아래글 아듀이노 OBD-II PID 송수신 함수
    N         제목    글쓴이 작성일 조회 추천
61 비접점식 QTouch 방식 근접검출 스위치 leeky 2016/01/21 (목) 1064 0
60 Arduino 고속 오실로스코프 #3 avrtools™ 2012/03/29 (목) 18167 0
59 아날로그 8ch 데이터 로거 avrtools™ 2012/03/29 (목) 3053 0
58 Arduino DMX512 송신기 제작 avrtools™ 2012/03/15 (목) 3205 0
57 nRF24L01 무선모듈의 사용방법 avrtools™ 2012/03/07 (수) 6493 0
56 초음파 거리 측정기의 제작 avrtools™ 2011/09/18 (일) 5270 0
55 3축 가속도 센서 ADXL335 avrtools™ 2011/09/09 (금) 3796 0
54 Arduino Uno USBserial 펌웨어의 변경 avrtools™ 2011/08/27 (토) 3318 0
53 Arduino MIDI의 소개 avrtools™ 2011/08/19 (금) 3702 0
52 Arduino 고속 Oscillo Scope #2 avrtools™ 2011/08/12 (금) 3338 0
51 Arduino Uno 및 USB2serial Uno의 소개 [2] avrtools™ 2011/07/30 (토) 3618 0
50 Arduino IDE에서 AVRISP-mkII 사용방법 avrtools™ 2010/10/22 (금) 8288 0
49 아듀이노 초음파 거리측정 및 응용 avrtools™ 2010/03/14 (일) 4364 0
48 M328-USB의 비밀 온도센서 avrtools™ 2010/01/02 (토) 3773 0
47 M168-mini로 만드는 USBasp avrtools™ 2009/10/10 (토) 5713 0
46 OBDuino ISO9141 소스의 설명 avrtools™ 2009/10/08 (목) 4438 0
45 아듀이노 0017 업그레이드 avrtools™ 2009/08/18 (화) 3949 0
44 Arduino 0015 업그레이드 avrtools™ 2009/06/01 (월) 3650 0
43 CC2500 Zigbee RF Modem #1 [4] avrtools™ 2008/11/20 (목) 6976 0
42 아듀이노 소프트웨어 Ver 0012 avrtools™ 2008/09/23 (화) 4143 0
41 Arduino 소프트웨어 설치방법 avrtools™ 2008/08/31 (일) 5832 0
40 아듀이노 PC 카메라 제작 avrtools™ 2008/10/28 (화) 7478 0
39 아듀이노 AVR-ISP V2의 제작 [6] avrtools™ 2008/10/22 (수) 8627 0
38 아듀이노 J1850-PWM 스캐너 avrtools™ 2008/10/15 (수) 4682 0
37 아듀이노 MPGduino의 제작 avrtools™ 2008/10/11 (토) 5175 0
36 아듀이노 OBD-II PID 처리함수 avrtools™ 2008/10/12 (일) 5830 0
35 아듀이노 OBD-II PID 송수신 함수 avrtools™ 2008/10/09 (목) 9919 0
34 아듀이노 ODB-II 스캐너 제작 [9] avrtools™ 2008/10/04 (토) 17973 0
33 아듀이노 AC전원 THD 측정 [2] avrtools™ 2008/09/30 (화) 7024 0
32 아듀이노 소프트방식 16Bit ADC avrtools™ 2008/09/23 (화) 5744 0
31 아듀이노 초음파 모듈의 제작. avrtools™ 2008/09/22 (월) 5112 0
30 아듀이노 Wii 프로세싱 avrtools™ 2008/09/20 (토) 4319 0
29 아듀이노 초음파 거리측정 avrtools™ 2008/09/20 (토) 6307 0
28 아듀이노 8x5 초소형 전광판 avrtools™ 2008/09/11 (목) 4878 0
27 아듀이노 4선식 터치패널 avrtools™ 2008/09/10 (수) 4816 0
26 아듀이노 2색 8x8 LED avrtools™ 2008/09/10 (수) 5139 0
25 아듀이노 24x6 LED 전광판 avrtools™ 2008/09/10 (수) 5686 0
24 아듀이노 8x8 LED 프로세싱 avrtools™ 2008/09/10 (수) 4265 0
23 아듀이노 32x16 RGB 전광판 avrtools™ 2008/09/06 (토) 13887 0
22 아듀이노 맥박검출기 avrtools™ 2008/09/03 (수) 9842 0
21 아듀이노 적외선 거리센서 avrtools™ 2008/09/01 (월) 6142 0
20 아듀이노 DMX 수신장치 [7] avrtools™ 2008/08/31 (일) 7091 0
19 아듀이노 AVR-ISP 만들기 avrtools™ 2008/08/30 (토) 4344 0
18 아듀이노 POV #3 avrtools™ 2008/08/30 (토) 3633 0
17 아듀이노 POV #2 avrtools™ 2008/08/30 (토) 3404 0
16 AVR 병렬포트 굽기장치 avrtools™ 2008/08/30 (토) 5484 0
15 아듀이노 DMX 송신기 avrtools™ 2008/08/28 (목) 5328 0
14 아듀이노 부트로더의 개조 [1] avrtools™ 2008/08/28 (목) 5988 0
13 아듀이노 병렬포트 굽기장치 avrtools™ 2008/08/26 (화) 4394 0
12 아듀이노 POV #1 avrtools™ 2008/08/26 (화) 3655 0
11 아듀이노 MIDI 드럼 leeky 2008/08/24 (일) 4984 0
10 아듀이노 SD/MMC 카드 avrtools™ 2008/08/24 (일) 9966 0
9 아듀이노 MIDI 플륫 avrtools™ 2008/08/24 (일) 3837 0
8 아듀이노 RGB LED avrtools™ 2008/08/23 (토) 5254 0
7 아듀이노 USB 오실로스코프 [2] leeky 2008/08/21 (목) 6817 0
6 가속도계 ADXL202 응용소스 avrtools™ 2008/08/20 (수) 5132 0
5 아듀이노 가속도센서 avrtools™ 2008/08/18 (월) 5170 0
4 아듀이노 RC서보 제어 avrtools™ 2008/08/17 (일) 5463 0
3 아듀이노 910-ISP 만들기 avrtools™ 2008/08/16 (토) 5032 0
2 아듀이노 온도센서, XBee 송수신 avrtools™ 2008/08/15 (금) 7912 0
1 아듀이노 기본명령 avrtools™ 2008/08/07 (목) 7054 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