-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathOBD2TripComputer.ino
182 lines (153 loc) · 5.03 KB
/
OBD2TripComputer.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <OBD.h>
#include <TFT_HX8357.h>
#include "Free_Fonts.h"
#include "Graph.h"
TFT_HX8357 tft = TFT_HX8357();
Graph graph = Graph();
COBD obd = COBD();
#define TFT_GREY 0x5AEB
#define BT_PWR 20 // Used to power up/down the BT module
#define BT_ENABLE 21 // Not really used for anything in my experience but here for completeness
#define BT_STATE 17 // The "state" pin of the HC-06. Is pulled high when the module is connected
// Initialize some values
int rpm = 0, ect = 0, speed = 0, maf = 0, load = 0;
int prevRpm = 1, prevEct = 1, prevSpeed = 1;
double cons = 0;
double cons1 = 0, cons2 = 0, consavg = 0;
unsigned long mpoints = 0;
void initialize();
void setup() {
pinMode(BT_STATE, INPUT);
pinMode(BT_PWR, OUTPUT);
pinMode(BT_ENABLE, OUTPUT);
// Start the serial debugging port
Serial.begin(38400);
// Initialize the TFT
tft.init();
tft.setRotation(1);
// Try to initialize a BT and OBD-2 connection
initialize();
}
void loop() {
int errors = 0;
if (obd.readPID(PID_RPM, rpm, 1)) {
if (rpm != prevRpm) {
prevRpm = rpm;
char buf[15];
sprintf(buf, "RPM: %i ", rpm);
tft.drawString(buf, 0, (4 * tft.fontHeight(4)), 4);
}
} else {
errors++;
}
if (obd.readPID(PID_COOLANT_TEMP, ect, 1)) {
if (ect != prevEct) {
prevEct = ect;
char buf2[15];
sprintf(buf2, "ECT: %i C ", ect);
tft.drawString(buf2, 0, (5 * tft.fontHeight(4)), 4);
}
} else {
errors++;
}
if (obd.readPID(PID_SPEED, speed, 1)) {
if (speed != prevSpeed) {
prevSpeed = speed;
char buf3[18];
sprintf(buf3, "SPD: %i KM/h ", speed);
tft.drawString(buf3, 0, (6 * tft.fontHeight(4)), 4);
}
} else {
errors++;
}
if (speed > 0) {
obd.readPID(PID_MAF_FLOW, maf, 1);
obd.readPID(PID_ENGINE_LOAD, load, 1);
/*
* Calculate consumption. This is done using the following formula:
* FuelFlow (Litres/Hour) = a * (Airflow (g/s) * Load (%)) + b
* Where A and B are calibration coefficients, AirFlow is taken from the ECU (MAF sensor) and Load is calculated/approximated by the ECU.
* A and B can be obtained by measuring the actual FuelFlow and comparing with the results of this formula with A and B both zero.
*
* This formula (and the calibration values) were taken from https://www3.epa.gov/ttn/chief/conference/ei20/session8/aalessandrini.pdf Page 11
*/
cons = (double)((0.0023 * ((double) maf * (double) load) + 0.55) / speed) * 100;
if (cons1 == 0) {
cons1 = cons;
mpoints++;
} else if (cons2 == 0) {
cons2 = cons;
consavg = (cons1 + cons2) / 2;
mpoints++;
} else {
consavg = ((consavg * mpoints) + cons) / (mpoints + 1);
mpoints++;
}
/*
* So consumption is calculated in Litres/Hour (L/h) from the above equation (a * (Airflow (g/s) * Load(%)) + b)
* Calculating Liters/100KM or KM/Litre is trivial now:
* Consumption (L/100KM) = (Consumption (L/h) / Speed (KM/h)) * 100
* Consumption (KM/L) = 100 / Consumption (L/100KM)
*/
int consX = tft.textWidth("CONS: ", 4);
int consY = 7 * tft.fontHeight(4);
int avgX = tft.textWidth("AVG: ", 4);
int avgY = 8 * tft.fontHeight(4);
tft.drawString("CONS: L/100KM", 0, consY, 4);
tft.drawFloat((float) cons, 2, consX, consY, 4);
tft.drawString("AVG: L/100KM", 0, avgY, 4);
tft.drawFloat((float) consavg, 2, avgX, avgY, 4);
graph.plot((uint16_t) cons);
} else {
tft.drawString("CONS: ---------- L/100KM", 0, (7 * tft.fontHeight(4)), 4);
graph.plot(0);
}
if (digitalRead(BT_STATE) == 0 || errors > 2) {
tft.fillScreen(TFT_BLACK);
initialize();
}
}
void initialize() {
// Clear the screen
int xpos = 0;
int ypos = tft.fontHeight(GFXFF) * 2;
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
// Initializes the graph's axes
graph.init(0, (8 * tft.fontHeight(4)), tft.width(), tft.height(), tft);
tft.setCursor(xpos, ypos);
tft.setCursor(0, 0);
tft.print("Initializing Bluetooth: ");
// Power up the HC-06 module
digitalWrite(BT_ENABLE, HIGH);
digitalWrite(BT_PWR, HIGH);
delay(1000);
// Wait for a BT connection
while (digitalRead(BT_STATE) == 0) {
delay(5);
}
tft.println("OK ");
// Start the OBD-2 serial connection and try to connect to the ECU
obd.begin();
bool success = false;
while (!success) {
tft.setCursor(xpos, ypos);
tft.print(F("OBD-II Connection initializing: "));
success = obd.init(PROTO_KWP2000_FAST); // This should be the protocol your car uses, or empty for auth-search
if (success) {
tft.println("OK ");
} else {
tft.println("ERROR");
}
// If we lose the BT connection, re-init
if (digitalRead(BT_STATE) == 0) {
tft.fillScreen(TFT_BLACK);
initialize();
}
}
// We're connected! Request the used protocol from the ELM-327
char proto[32];
obd.sendCommand("ATDP\r", proto, sizeof(proto) * 12);
tft.print(F("OBD-II Connection initialized: "));
tft.println(proto);
}