본문 바로가기
아두이노

모닝용 대시보드 코드편

by 구루가 되고픈 2020. 10. 21.

차량용 GPS 대시보드 작동모습

 

모닝용으로 제작한 GPS 대시보드의 소스코드를 요청하신분이 있어 공개합니다.

이전 투싼용 OLED 8개짜리와 큰 차이는 없습니다.

 

첫번째 코드는 GPS신호에서 방향값에 따라 NEWS 방향을 표시하고 각 통계를 내서 가로바 그래프 행태로 그리는 코드입니다.

u8glib 라이브러리를 사용하는데, 화면에 원하는 디자인을 표시하다보니 아주 복잡한 코드가 되었고, 코드의 해석보다는 본인이 원하는 스타일로 하나하나 디자인 하시는게 좋지 않을까 생각되네요.

 

#include "U8glib.h"
#include "SoftwareSerial.h"
#include "TinyGPS.h"

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);
TinyGPS gps;
SoftwareSerial ss(14, 16);
float alt, spd, cur, pre_cur;
float cn = 0, ce = 0, cs = 0, cw = 0, csum = 0;
byte bscale;
byte bp = 57; // 정중앙 news가 찍히는 글자 위치


void setup()
{
Serial.begin(9600);
ss.begin(9600);

Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
Serial.println();

u8g.firstPage();
do {
u8g.setFont(u8g_font_chikita);
u8g.drawStr(10, 34, "GPS SIGNAL SEARCHING...");
} while(u8g.nextPage());
}

void loop()
{
bool newData = false;

// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (ss.available())
{
char c = s
if (gps.encode(c))
newData = true;
}
}

if (newData)
{
alt = gps.f_altitude();
cur = gps.f_course();
spd = gps.f_speed_kmph();

if (spd > 2) // 속도가 2이상일 경우 방향값 증가
{
if ((cur >= 0) && (cur <= 45))
cn++;
else if ((cur >= 46) && (cur <= 135))
ce++;
else if ((cur >= 136) && (cur <= 225))
cs++;
else if ((cur >= 226) && (cur <= 315))
cw++;
else if ((cur >= 316) && (cur <= 360))
cn++;
else{}

pre_cur = cur; // 이전값 변수에 현재 방위값 저장
}
else
cur = pre_cur; // 이전값을 저장

Serial.print(" ALT=");
Serial.print(alt);
Serial.print(" COURSE=");
Serial.print(cur);
Serial.print(" KM=");
Serial.println(spd);
disp();
}

/*
alt = random(100);
cur = random(359);
spd = random(120);

if (spd > 2) // 속도가 2이상일 경우 방향값 증가
{
if ((cur >= 0) && (cur <= 45))
cn++;
else if ((cur >= 46) && (cur <= 135))
ce++;
else if ((cur >= 136) && (cur <= 225))
cs++;
else if ((cur >= 226) && (cur <= 315))
cw++;
else if ((cur >= 316) && (cur <= 360))
cn++;
else {}

pre_cur = cur; // 이전값 변수에 현재 방위값 저장
}
else
cur = pre_cur; // 이전값을 저장

Serial.print(" ALT=");
Serial.print(alt);
Serial.print(" COURSE=");
Serial.print(cur);
Serial.print(" KM=");
Serial.println(spd);
disp();
delay(1000);
*/
}

void disp()
{
csum = cn + ce + cs + cw;

// 4개 값을 비교해서 최대 스케일 정하기 (모두 25%일때 차트가 작아지는거 방지)
float max1 = max(cn/csum, ce/csum);
float max2 = max(cs/csum, cw/csum);
float max3 = max(max1, max2);

if (max3 > 0.9)
bscale = 70;
else if ((max3 > 0.8) && (max3 <= 0.9))
bscale = 77;
else if ((max3 > 0.7) && (max3 <= 0.8))
bscale = 87;
else if ((max3 > 0.6) && (max3 <= 0.7))
bscale = 100;
else if ((max3 > 0.5) && (max3 <= 0.6))
bscale = 116;
else if ((max3 > 0.4) && (max3 <= 0.5))
bscale = 140;
else if ((max3 > 0.3) && (max3 <= 0.4))
bscale = 175;
else if (max3 <= 0.3)
bscale = 233;
else {}

byte n = bscale*(cn/csum);
byte e = bscale*(ce/csum);
byte s = bscale*(cs/csum);
byte w = bscale*(cw/csum);

u8g.firstPage();
do {
u8g.drawFrame(0, 2, 128, 30);
u8g.drawLine(19, 0, 19, 5);
u8g.drawLine(64, 0, 64, 5);
u8g.drawLine(63, 0, 63, 5);
u8g.drawLine(65, 0, 65, 5);
u8g.drawLine(109, 0, 109, 5);

u8g.setFont(u8g_font_chikita);
u8g.drawStr(0, 43, "NOR");
u8g.drawStr(0, 50, "EST");
u8g.drawStr(0, 57, "SOU");
u8g.drawStr(0, 64, "WST");

// 여러개를 그리면 에러가 발생해서 좌표값이 화면을 벗어나지 않는 경우에만 표시하도록 제어
u8g.setFont(u8g_font_profont29r);
if ((bp-cur) > -10 && (bp-cur) < 138)
u8g.drawStr(bp-cur, 28, "N");
if ((bp-cur+90) > -10 && (bp-cur+90) < 138)
u8g.drawStr(bp-cur+90, 28, "E");
if ((bp-cur+180) > -10 && (bp-cur+180) < 138)
u8g.drawStr(bp-cur+180, 28, "S");
if ((bp-cur+270) > -10 && (bp-cur+270) < 138)
u8g.drawStr(bp-cur+270, 28, "W");
if ((bp-cur+360) > -10 && (bp-cur+360) < 138)
u8g.drawStr(bp-cur+360, 28, "N");

u8g.drawBox(20, 38, n, 5);
u8g.drawBox(20, 45, e, 5);
u8g.drawBox(20, 52, s, 5);
u8g.drawBox(20, 59, w, 5
} while(u8g.nextPage());
}

 

두번째 코드는 주행거리와 주행시간을 표시하는 코드입니다.

이 코드에서의 포인트는 1초에 한번씩 속도를 체크해서 2km 이상일 경우, 즉 주행중일 경우 속도로 초당 이동거리를 계산하는데, 이게 100% 정확친 않치만 비슷한 수준에서 이동거리가 측정이 가능합니다.

또하나 주행시간을 처음 10km를 넘어갈때부터 카운트한다는 것입니다.

이건 GPS신호가 잡힌 상태에서도 차량이 이동을 안하고 있는 경우도 있을수 있기 때문에 처음 10KM 넘기전까진 주행시간을 카운트하지 않는 것입니다.

10KM를 넘겨 카운트한 이후에는 교차로, 횡당보도 등에 정차한 경우라도 계속 시간은 카운트 됩니다.

 

#include "U8glib.h"
#include "SoftwareSerial.h"
#include "TinyGPS.h"

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);
TinyGPS gps;
SoftwareSerial ss(14, 16);
float alt, spd, cur, distance;
int cnt, runtime;
unsigned long s_time = 0, pre_time = 0, cur_time = 0;
String timeStr;

void setup()
{
Serial.begin(9600);
ss.begin(9600);

u8g.firstPage();
do {
u8g.setFont(u8g_font_chikita);
u8g.drawStr(10, 34, "GPS SIGNAL SEARCHING...");
} while(u8g.nextPage());
}

void loop()
{
bool newData = false;
cur_time = millis();

while (ss.available())
{
char c = ss.read();
if (gps.encode(c))
newData = true;
}

if (newData)
{
alt = gps.f_altitude();
cur = gps.f_course();
spd = gps.f_speed_kmph();
}

if (cur_time - pre_time >= 1000)
{
if (spd >= 2)
distance = distance + (spd / 3600);

if (s_time == 0 && spd > 10)
s_time = millis();

if (s_time == 0)
runtime = 0;
else
runtime = (millis() - s_time) / 1000;

int h = runtime/3600;
int hmod = runtime%3600;
int m = hmod/60;
int s = hmod%60;
String hr = String(h);
String mt = String(m);
String sc = String(s);
timeStr = "";
timeStr.concat(hr);
timeStr.concat(":");
if (m<10)
timeStr.concat("0");
timeStr.concat(mt);
timeStr.concat(":");
if (s<10)
timeStr.concat("0");
timeStr.concat(sc);

pre_time = cur_time;
Disp();

Serial.print(" runtime : ");
Serial.println(runtime);
Serial.print(" h : ");
Serial.print(hr);
Serial.print(" m : ");
Serial.print(mt);
Serial.print(" s : ");
Serial.println(sc);
}
}

void Disp()
{
u8g.firstPage();
do {
u8g.drawLine(0, 32, 128, 32);

u8g.setFont(u8g_font_chikita);
u8g.drawStr(0, 7, "D");
u8g.drawStr(1, 14, "I");
u8g.drawStr(0, 21, "S");
u8g.drawStr(0, 28, "T");
u8g.drawStr(0, 42, "T");
u8g.drawStr(1, 49, "I");
u8g.drawStr(0, 56, "M");
u8g.drawStr(0, 63, "E");
u8g.drawStr(114, 27, "KM");

u8g.setFont(u8g_font_profont29r);
if (distance < 10)
u8g.setPrintPos(62,24);
else if (distance >= 10 && distance < 100)
u8g.setPrintPos(46,24);
else
u8g.setPrintPos(30,24);
u8g.print(distance, 1);

u8g.setPrintPos(15,60);
u8g.print(timeStr);

} while(u8g.nextPage());
}

 

세번째 코드는 고도값과 속도를 세로형 차트로 그려주는 코드입니다.

GPS의 고도값은 오차가 매우 심하기 때문에 대략적으로 참고만 하여야 하고, 세로형으로 그려주는것은 디자인의 문제라 참고만 하시면 되겠습니다.

 

#include "U8glib.h"
#include "SoftwareSerial.h"
#include "TinyGPS.h"

// U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK);
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);
TinyGPS gps;
SoftwareSerial ss(14, 16);
float alt, spd, cur, spd_avg;
int cnt;
float spd10, spd20, spd30, spd40, spd50, spd60, spd70, spd80, spd90, spd100, spd101;
float s10, s20, s30, s40, s50, s60, s70, s80, s90, s100, s101;
byte b10, b20, b30, b40, b50, b60, b70, b80, b90, b100, b101;
unsigned long spd_sum, pre_time = 0, cur_time = 0;

void setup()
{
Serial.begin(9600);
ss.begin(9600);

Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
Serial.println();

u8g.firstPage();
do {
u8g.setFont(u8g_font_chikita);
u8g.drawStr(10, 34, "GPS SIGNAL SEARCHING...");
} while(u8g.nextPage());
}

void loop()
{
bool newData = false;
cur_time = millis();

for (unsigned long start = millis(); millis() - start < 1000;)
{
while (ss.available())
{
char c = ss.read();
if (gps.encode(c)) // Did a new valid sentence come in?
newData = true;
}
}

if (newData)
{
alt = gps.f_altitude();
cur = gps.f_course();
spd = gps.f_speed_kmph();
}

if (cur_time - pre_time >= 1000)
{
if (spd > 2)
{
spd_sum = spd_sum + spd;
cnt++;
spd_avg = spd_sum / cnt;
}

if (spd > 2 && spd <= 10)
spd10++;
else if (spd > 10 && spd <= 20)
spd20++;
else if (spd > 20 && spd <= 30)
spd30++;
else if (spd > 30 && spd <= 40)
spd40++;
else if (spd > 40 && spd <= 50)
spd50++;
else if (spd > 50 && spd <= 60)
spd60++;
else if (spd > 60 && spd <= 70)
spd70++;
else if (spd > 70 && spd <= 80)
spd80++;
else if (spd > 80 && spd <= 90)
spd90++;
else if (spd > 90 && spd <= 100)
spd100++;
else if (spd > 100)
spd101++;
else {}

s10 = spd10 / cnt;
s20 = spd20 / cnt;
s30 = spd30 / cnt;
s40 = spd40 / cnt;
s50 = spd50 / cnt;
s60 = spd60 / cnt;
s70 = spd70 / cnt;
s80 = spd80 / cnt;
s90 = spd90 / cnt;
s100 = spd100 / cnt;
s101 = spd101 / cnt;

float m1, m2, m3, m4, m5, m6, m7, m8, m9, m10;
m1 = max(s10, s20);
m2 = max(s30, s40);
m3 = max(s50, s60);
m4 = max(s70, s80);
m5 = max(s90, s100);
m6 = max(m1, m2);
m7 = max(m3, m4);
m8 = max(m5, s101);
m9 = max(m6, m7);
m10 = max(m9, m8);

int bar;

if (m10 <= 0.10)
bar = 250;
else if (m10 > 0.10 && m10 <= 0.20)
bar = 125;
else if (m10 > 0.20 && m10 <= 0.30)
bar = 83;
else if (m10 > 0.30 && m10 <= 0.40)
bar = 62;
else if (m10 > 0.40 && m10 <= 0.50)
bar = 50;
else if (m10 > 0.50 && m10 <= 0.60)
bar = 41;
else if (m10 > 0.60 && m10 <= 0.70)
bar = 35;
else if (m10 > 0.70 && m10 <= 0.80)
bar = 31;
else if (m10 > 0.80 && m10 <= 0.90)
bar = 27;
else
bar = 25;

b10 = s10 * bar;
b20 = s20 * bar;
b30 = s30 * bar;
b40 = s40 * bar;
b50 = s50 * bar;
b60 = s60 * bar;
b70 = s70 * bar;
b80 = s80 * bar;
b90 = s90 * bar;
b100 = s100 * bar;
b101 = s101 * bar;

if (b10 == 0)
b10 = 1;
if (b20 == 0)
b20 = 1;
if (b30 == 0)
b30 = 1;
if (b40 == 0)
b40 = 1;
if (b50 == 0)
b50 = 1;
if (b60 == 0)
b60 = 1;
if (b70 == 0)
b70 = 1;
if (b80 == 0)
b80 = 1;
if (b90 == 0)
b90 = 1;
if (b100 == 0)
b100 = 1;
if (b101 == 0)
b101 = 1;

pre_time = cur_time;
Disp();

Serial.print(" spd=");
Serial.print(spd);
Serial.print(" cnt=");
Serial.print(cnt);
Serial.print(" max=");
Serial.print(m10);
Serial.print(" bar=");
Serial.println(bar);
Serial.print(" spd10=");
Serial.print(s10);
Serial.print(" spd20=");
Serial.print(s20);
Serial.print(" spd30=");
Serial.print(s30);
Serial.print(" spd40=");
Serial.print(s40);
Serial.print(" spd50=");
Serial.print(s50);
Serial.print(" spd60=");
Serial.print(s60);
Serial.print(" spd70=");
Serial.print(s70);
Serial.print(" spd80=");
Serial.print(s80);
Serial.print(" spd90=");
Serial.print(s90);
Serial.print(" spd100=");
Serial.print(s100);
Serial.print(" spd101=");
Serial.println(s101);
}
}

void Disp()
{
u8g.firstPage();
do {

u8g.setFont(u8g_font_chikita);
u8g.drawStr(0, 7, "A");
u8g.drawStr(1, 14, "L");
u8g.drawStr(0, 21, "T");
u8g.drawStr(0, 28, "I");
u8g.drawStr(114, 27, "M");

u8g.drawStr(16, 64, "10");
u8g.drawStr(37, 64, "30");
u8g.drawStr(59, 64, "50");
u8g.drawStr(81, 64, "70");
u8g.drawStr(103, 64, "90");

u8g.setFont(u8g_font_profont29r);

if (alt < 10)
u8g.setPrintPos(62,24); // 고도 위치 맞추기
else if (alt >= 10 && alt < 100)
u8g.setPrintPos(46,24);
else
u8g.setPrintPos(30,24);
u8g.print(alt, 1);

u8g.drawBox(5, 32+(25-b10), 8, b10);
u8g.drawBox(16, 32+(25-b20), 8, b20);
u8g.drawBox(27, 32+(25-b30), 8, b30);
u8g.drawBox(38, 32+(25-b40), 8, b40);
u8g.drawBox(49, 32+(25-b50), 8, b50);
u8g.drawBox(60, 32+(25-b60), 8, b60);
u8g.drawBox(71, 32+(25-b70), 8, b70);
u8g.drawBox(82, 32+(25-b80), 8, b80);
u8g.drawBox(93, 32+(25-b90), 8, b90);
u8g.drawBox(104, 32+(25-b100), 8, b100);
u8g.drawBox(115, 32+(25-b101), 8, b101);
} while(u8g.nextPage());
}

 

티스토리 편집기가 진짜 문제가 많아서 참 글쓰기 힘드네요.

소스코드는 탭이 날라가서 안쪽 들여쓰기가 전혀 안되었습니다.

보기 불편하시겠지만 어쩔수가 없네요. TT

 

즐거운 아두이노 생활하시기 바랍니다.