차량의 OBD 포트를 통해 차량내 제공 하는 데이터를 요청 응답 받아 표시하는 기능을 구현하는 방법에 대해 소개해드립니다
데이터 가시성을 위해서 LCD가 포함된 M5Stack 개발 보드를 사용하였습니다
M5Stack - Modular Rapid ESP32 IoT Development Board - ESP32 dev kits
Open-source modular toolkits for IoT devices based on ESP32-updated version of ESP8266. With stackable modules, user-friendly IDE, enabling rapid and high-quality prototyping, STEM education, engineering and mechanical use.
m5stack.com
M5Stack Grey 개발보드에 적용된 ESP32 마이크로 컨트롤러는 WiFi와 Bluetooth를 지원하기에
OBD포트에 ELM327 블루투스 어댑터를 연결하여 무선데이터를 요청 응답 받는 방식으로 하드웨어를 구성합니다
OBD 데이터를 처리하기 위해 사용된 라이브러리는 아래와 같습니다
github.com/PowerBroker2/ELMduino
PowerBroker2/ELMduino
Arduino OBD-II Bluetooth Scanner Interface Library - PowerBroker2/ELMduino
github.com
LCD 화면에 엔진RPM, 속도, 엔진온도, 흡기온도를 표시합니다
(각 값의 앞에 빨간원형과 파란원형 표기는 개인의 판단에 따라 값에 대한 위험 지점에 대한 가시성을 표시합니다)
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
|
#include <Arduino.h>
#include <M5Stack.h>
#include "Free_Fonts.h"
#include "BluetoothSerial.h"
#include "ELMduino.h"
BluetoothSerial SerialBT;
#define ELM_PORT SerialBT
#define DEBUG_PORT Serial
ELM327 myELM327;
uint32_t rpm = 0;
char CONVERTED_RPM[32];
char CONVERTED_KPH[32];
char CONVERTED_ENGINETEMP[32];
char CONVERTED_INTAKETEMP[32];
int LOOP_COUNTER = 0;
int LCD_BRIGHTNESS = 150;
void setup()
{
M5.begin();
M5.Power.begin();
M5.Lcd.setBrightness(150);
M5.Lcd.setTextColor(0xE73C, TFT_BLACK);
M5.Lcd.setFreeFont(FF19);
M5.Lcd.setTextSize(1);
DEBUG_PORT.begin(9600);
DEBUG_PORT.println(" == Start Up ==");
M5.Lcd.setCursor(50, 100);
M5.Lcd.print("Connect OBD");
ELM_PORT.begin("M5BLE", true);
ELM_PORT.setPin("1234"); // ELM327 BLE 핀 넘버
if (!ELM_PORT.connect("OBD2")) // ELM327 BLE 이름
{
M5.Lcd.fillRect(50, 100, 270, 50, TFT_BLACK);
M5.Lcd.setCursor(50, 130);
M5.Lcd.print("BLE fail");
while(1);
}
if (!myELM327.begin(ELM_PORT))
{
M5.Lcd.fillRect(50, 100, 270, 50, TFT_BLACK);
M5.Lcd.setCursor(50, 130);
M5.Lcd.print("ECU fail");
while (1);
}
Serial.println("Connected to ELM327");
M5.Lcd.fillRect(0, 0, 320, 240, TFT_BLACK);
}
void printError()
{
DEBUG_PORT.print("Received: ");
for (byte i = 0; i < myELM327.recBytes; i++)
DEBUG_PORT.write(myELM327.payload[i]);
DEBUG_PORT.println();
if (myELM327.status == ELM_SUCCESS)
DEBUG_PORT.println(F("\tELM_SUCCESS"));
else if (myELM327.status == ELM_NO_RESPONSE)
DEBUG_PORT.println(F("\tERROR: ELM_NO_RESPONSE"));
else if (myELM327.status == ELM_BUFFER_OVERFLOW)
DEBUG_PORT.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
else if (myELM327.status == ELM_UNABLE_TO_CONNECT)
DEBUG_PORT.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
else if (myELM327.status == ELM_NO_DATA)
DEBUG_PORT.println(F("\tERROR: ELM_NO_DATA"));
else if (myELM327.status == ELM_STOPPED)
DEBUG_PORT.println(F("\tERROR: ELM_STOPPED"));
else if (myELM327.status == ELM_TIMEOUT)
DEBUG_PORT.println(F("\tERROR: ELM_TIMEOUT"));
else if (myELM327.status == ELM_TIMEOUT)
DEBUG_PORT.println(F("\tERROR: ELM_GENERAL_ERROR"));
delay(100);
}
void loop()
{
float tempRPM = myELM327.rpm();
rpm = (uint32_t)tempRPM;
int32_t kph = myELM327.kph();
uint32_t enginetemp = myELM327.enginetemp(); // ELMduino 라이브러리에 사용자 기능 포함
uint32_t intaketemp = myELM327.intaketemp(); // ELMduino 라이브러리에 사용자 기능 포함
if (myELM327.status == ELM_SUCCESS)
{
M5.Lcd.fillRect(10, 10, 200, 220, TFT_BLACK);
M5.Lcd.setTextDatum(MR_DATUM);
sprintf(CONVERTED_RPM, "%d", rpm);
M5.Lcd.drawString(CONVERTED_RPM, 210, 40, GFXFF);
M5.Lcd.setCursor(230, 50);
M5.Lcd.print("rpm");
sprintf(CONVERTED_KPH, "%d", kph);
M5.Lcd.drawString(CONVERTED_KPH, 210, 90, GFXFF);
M5.Lcd.setCursor(230, 100);
M5.Lcd.print("Km/h");
sprintf(CONVERTED_ENGINETEMP, "%d", enginetemp);
M5.Lcd.drawString(CONVERTED_ENGINETEMP, 210, 140, GFXFF);
M5.Lcd.setCursor(230, 150);
M5.Lcd.print("C");
sprintf(CONVERTED_INTAKETEMP, "%d", intaketemp);
M5.Lcd.drawString(CONVERTED_INTAKETEMP, 210, 190, GFXFF);
M5.Lcd.setCursor(230, 200);
M5.Lcd.print("C");
if (rpm > 5000) {
M5.Lcd.fillCircle(20, 40, 10, 0xD0C3); // 붉은 원형 표기
} else {
M5.Lcd.fillCircle(20, 40, 10, 0x33FB); // 파란 원형 표기
}
if (kph > 100) {
M5.Lcd.fillCircle(20, 90, 10, 0xD0C3);
} else {
M5.Lcd.fillCircle(20, 90, 10, 0x33FB);
}
if (enginetemp > 100) {
M5.Lcd.fillCircle(20, 140, 10, 0xD0C3);
} else {
M5.Lcd.fillCircle(20, 140, 10, 0x33FB);
}
if (intaketemp > 100) {
M5.Lcd.fillCircle(20, 190, 10, 0xD0C3);
} else {
M5.Lcd.fillCircle(20, 190, 10, 0x33FB);
}
}
else
{
M5.Lcd.fillRect(0, 0, 320, 240, TFT_BLACK);
M5.Lcd.setCursor(60, 130);
M5.Lcd.print("Connect Fail");
printError();
}
// 2초 지연 및 밝기 조절 버튼 활성
for (LOOP_COUNTER = 0; LOOP_COUNTER < 200; LOOP_COUNTER++)
{
delay(10);
M5.update();
if (M5.BtnC.wasPressed() == true) // C 버튼 클릭시
{
if (LCD_BRIGHTNESS < 240)
{
LCD_BRIGHTNESS = LCD_BRIGHTNESS + 20;
M5.Lcd.setBrightness(LCD_BRIGHTNESS);
}
else if (LCD_BRIGHTNESS == 240 || LCD_BRIGHTNESS > 240)
{
M5.Lcd.setBrightness(LCD_BRIGHTNESS);
LCD_BRIGHTNESS = 0;
}
else { }
}
}
}
|
cs |
참고로 폰트등에 사용되는 색상은 아래 사이트에서 사용자 색상을 선택하여 16비트 깊이 값을 가져오면 됩니다
ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
16 bit color generator (RGB565 color picker)
One of the previous notes was about 16 bits RGB color representation , RGB565 format . This note will be based on that note and you will b...
ee-programming-notepad.blogspot.com