Vous êtes sur la page 1sur 5

AVR 2004 Design Contest - Entry A3805

A Fuel-Consumption Gauge for Your GM Car


Real-time Data from Your Engine Computer
With the new and improved price of gasoline here in the U.S. many of us that own large SUVs
want to know our fuel consumption efficiency while we are driving. Some newer vehicles display
this “real time” data on a dashboard display, but those of us with older cars were out of luck…until
now. If you drive a 1996 or newer “gas guzzler” made by General Motors you probably can make
your own easy-to-read miles per gallon (MPG) display.
This project and its accompanying design files unlock the secrets of one of the five onboard
diagnostic busses mandated by the U.S. OBD-II standard, namely SAE J1850 VPW, first used by
General Motors, now found in a number of vehicle models, including those from Chevrolet, GMC,
Buick, Pontiac, Saturn, Toyota, Chrysler, Isuzu and Daewoo. The project demonstrates how to use
an inexpensive Atmel ‘8515 AVR microcontroller to collect real-time vehicle speed and air-flow
data from an engine computer using the J1850 VPW bit-serial bus and display that information as a
fuel consumption rate in miles per gallon (MPG) using an “analog display” made from an off-the-
shelf, electronic tachometer with a modified meter face-plate. Bill of materials costs are under $50,
most of that going to the electronic tachometer.
The article shows how a microcontroller-based design can be connected safely to the “power
supply from hell”, the 12VDC automotive battery bus, and provide a simple, robust connection to a
vehicle’s SAE J1850 VPW bus, while still tolerating ground and power-supply short circuits, as
well as reversed battery voltage. This “magic” is performed without the need for special
automotive bus interface chips. Simple transistors, diodes, resistors, and capacitors are all that are
needed.
Through the use of embedded C-code the mysteries of the J1850 VPW protocol are revealed and a
gateway to the real-time data stored in your engine computer is opened. We also see how
emulating the instruction-by-instruction behavior of the AVR microcontroller can be used to speed
firmware development. Finally, we show how to acquire an inexpensive junkyard “brain” for your
favorite vehicle, so you can experiment with an engine computer in the lab, before doing the same
in your driveway...or on the highway!

6/30/2004 2:50 PM
Listings
Listing 1 - Vpw_send:
unsigned char vpw_send( // returned status: 0 = error, 1 = OK
unsigned char *buf, // buffer to be sent via J1850 VPW
unsigned char n // number of bytes to sent from buf
){
unsigned char bits, ch, timer0, period;

wait_vpw_idle(); // wait for idle J1850 bus


timer0_start(T0_CK8); // this clears timer0 count
vpw_active(); // send SOF pulse
timer0 = VPW_SOF_CNT8;
while (timer0_get() != timer0) ;
while(n--) { // sent next byte in buffer
ch = *buf++;
bits = 8;
while (bits--) { // send each bit in the byte
if (bits & 1) {
vpw_passive();
period = (ch & 0x80) ? VPW_LONG_CNT8 : VPW_SHORT_CNT8;
timer0 += period / 2; // set to delay 1/2 of period
while (timer0_get() != timer0) ; // wait for switch
timer0 += period - (period / 2); // wait rest of period
while (timer0_get() != timer0) {
if (is_vpw_active()) return 0; // collision!!
}
} else {
vpw_active();
timer0 += (ch & 0x80) ? VPW_SHORT_CNT8 : VPW_LONG_CNT8;
while (timer0_get() != timer0) ;
}
ch <<= 1;
}
}
vpw_passive(); // output EOD "symbol"
timer0 += VPW_EOD_CNT8;
while (timer0_get() != timer0) ; // wait for EOD complete
return 1;
}

Listing 2 - Vpw_recv:
unsigned char vpw_recv( // returned no. bytes received
unsigned char *buf, // buffer to receive into buf
unsigned char max // max. bytes to receive
){
unsigned char n, bits, ch, delay, state;
unsigned int num100usec;

num100usec = 0;
again:
timer0_start(T0_CK8);
while (!is_vpw_active()) {
if (timer0_get() == US2T0CNT8(100)) {
++num100usec;
timer0_start(T0_CK8);

Page 2
if (num100usec > 1000) { // exit if >100 msec
return 0;
}
}
}
// expect SOF
timer0_start(T0_CK8);
while (is_vpw_active()) {
if (timer0_get() == VPW_SOF_MAX_CNT8 ) goto again;
}
delay = timer0_get();
timer0_start(T0_CK8);
state = is_vpw_active();
if (delay < VPW_SOF_MIN_CNT8) goto again;
for (n = 0; n < max; ++n) {
bits = 8;
ch = 0;
while (bits--) {
ch <<= 1;
while (is_vpw_active() == state) {
if (timer0_get() == VPW_SOF_MAX_CNT8 ) return n;
}
delay = timer0_get();
timer0_start(T0_CK8);
state = is_vpw_active();
if (delay <= VPW_BIT_MIN_CNT8) goto finis;
if (delay > VPW_BIT_MAX_CNT8) goto finis;
ch |= (delay > VPW_BIT_MID_CNT8) ? 1 : 0;
}
*buf++ = ch ^ 0x55;
}
return n;
}

Listing 3 - Crc8buf:
unsigned char crc8buf(
unsigned char *buf, // buffer with bytes to be checksumed
unsigned char len // number of bytes
){
unsigned char val, i, chksum;

chksum = 0xff; // start with all one's


while (len--) {
i = 8;
val = *buf++;
while (i--) {
if (((val ^ chksum) & 0x80) != 0) {
chksum ^= 0x0e;
chksum = (chksum << 1) | 1;
} else {
chksum = chksum << 1;
}
val = val << 1;
}
}
return ~chksum;
}

Page 3
System Block Diagram

Page 4
8 7 6 5 4 3 2 1

~9-15 VDC
(70 V VBATF 12V 5V
(15mA constant current) spikes) F1 R4 D5 U3
P3 U5 1 2 3 1 5V
VBAT I O
4 LIGHT 3 2

GND
LAMP 3 COIL I O RXE110 10 1N4001

ADJ
COIL 2 MPWR Z1 C6
VBAT + C1 + C2 C3
1 R18 TL750L05CLP
GND LM317LZ 75 (TO-92)

2
D 0.1uF, 25V 10uF, 25V 10uF, 15V 0.1uF D
ERZ-V07D220

1
(TO-92)

R19 3
LON 2 Q4 12V
1 2N3904 U4
P1 10K 3 1 8V
I O 8V
1 VBAT

GND
VBAT VBAT
2 R8 10K 3 Q1
ISO-K 3 1 3 C10 2 2N3906
ISO-L VBATF +
4 NJM78L08A 1 (TO-92)
GND 5 Q5 R21 (TO-92)
10uF, 15V R6 10K

2
J1850- 6 J1850+ 2N3906 10K
J1850+ (TO-92)
D4

2
R20
1 2
OBD-II Port R10 3 C4
510 VPW_OUT 2 Q2 1N4001
R22 3 1 2N3904 22pF
C P5 MON 2 Q6 10K R11
(TO-92)
C
3 RX* 1 2N3904
RX 2 TX* 10K (TO-92)
TX 1 10K
GND R9
J1850+
P4 R2 1K 10
4 LED0
LEDG 3 LED1 R13
LEDR 2 SW1 5V 30K 1%
SW 1 R1 1K U1 R15
GND VPW_OUT 2 44 VPW_IN
RPM 3 PB0 (T0) VCC 43 LON 5V (Vin/4)
R12 10K VPW_REF 4 PB1 (T1) PA0 (AD0) 42 MON 10K
P2 VPW_IN 5 PB2 (AIN0) PA1 (AD1) 41 C9
1 5V LED0 6 PB3 (AIN1) PA2 (AD2) 40 R16
GND 2 MOSI PB5 7 PB4 (SS*) PA3 (AD3) 39 22pF 10K 1%
B MOSI 3 MISO PB6 8 PB5 (MOSI) PA4 (AD4) 38 R14
B
MISO 4 SCK PB7 9 PB6 (MISO) PA5 (AD5) 37 47K 1% (Vref = 3.5V/4)
SCK 5 RESET* RESET* 10 PB7 (SCK) PA6 (AD6) 36
RESET RX* 11 RESET* PA7 (AD7) 35 VPW_REF
U2 TX* 13 PD0 (RXD) ICP 33
1 SW1 14 PD1 (TXD) ALE 32
3 RST 15 PD2 (INT0) OC1B 31 C5 R5
GND 2 LED2 16 PD3 (INT1) PC7 (A15) 30 R17 COIL
VCC 5V PD4 PC6 (A14) VBATF
LED1 17 29 10K 1% 0.1uF
MCP130-460DI/TO 18 PD5 (OC1A) PC5 (A13) 28 R7 510 3
(TO-92)
19 PD6 (WR*) PC4 (A12) 27 RPM 2 Q3
7.3728 MHz XTAL2 20 PD7 (RD*) PC3 (A11) 26 1 2N3904
XTAL1 21 XTAL2 PC2 (A10) 25 10K (TO-92)

Y1 22 XTAL1 PC1 (A9) 24


GND PC0 (A8)
1 3 AT90S8515-8JC (PLCC-44)
or ATmega8515
A ZTT-7.37MT C:\AVRFIRM\SAMPLES\OBD-II\ARTICLE\ORCAD\GMCMPG2.DSN A
2

TO-92 C7 C8 R3 D3 Title
LED2 1 2 J1850 VPW (GMC) MPG Display Controller
E B C
1 2 3 22pF 22pF 1K Size Document Number Rev
(not used) (not used) YEL LED A 2.0
Copyright 2002 by B.D. Lightner
Date: Monday, June 28, 2004 Sheet 1 of 1
8 7 6 5 4 3 2 1

Vous aimerez peut-être aussi