#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(13, 11, 8, 9, 10);
// small font from the U8G library, digits only
const u8g_fntpgm_uint8_t digit_small[145] U8G_FONT_SECTION("digit_small") = {
0,4,4,0,4,5,0,0,0,0,45,57,0,9,0,5,
0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,
4,0,0,3,5,5,4,0,4,96,160,160,160,192,3,5,
5,4,0,4,64,192,64,64,224,3,5,5,4,0,4,192,
32,64,128,224,3,5,5,4,0,4,224,32,64,32,192,3,
5,5,4,0,4,128,160,224,32,32,3,5,5,4,0,4,
224,128,224,32,192,3,5,5,4,0,4,64,128,192,160,224,
3,5,5,4,0,4,224,32,32,64,64,3,5,5,4,0,
4,96,160,64,160,192,3,5,5,4,0,4,224,160,96,32,
64};
/*
Fontname: Tahoma
Copyright:
Capital A Height: 0, '1' Height: 13
Calculated Max Values w= 7 h=13 x= 1 y=16 dx= 9 dy= 0 ascent=24 len=13
Font Bounding box w=11 h=12 x= 0 y=11
Calculated Min Values x= 0 y= 0 dx= 0 dy= 0
Pure Font ascent =13 descent= 0
X Font ascent =13 descent= 0
Max Font ascent =24 descent= 0
*/
const u8g_fntpgm_uint8_t tah[238] U8G_FONT_SECTION("tah") = {
0,11,12,0,11,13,0,0,0,0,45,57,0,24,0,13,
0,3,1,1,4,0,16,224,1,1,1,2,0,11,128,3,
11,11,4,0,11,32,32,32,64,64,64,64,64,128,128,128,
7,13,13,9,0,11,56,68,130,130,130,130,130,130,130,130,
130,68,56,5,13,13,9,1,11,224,32,32,32,32,32,32,
32,32,32,32,32,248,7,13,13,9,0,11,56,68,130,130,
130,2,4,8,16,32,64,128,254,7,13,13,9,0,11,56,
68,130,130,2,4,56,4,2,130,130,68,56,7,13,13,9,
0,11,8,8,16,16,32,34,66,66,130,254,2,2,2,7,
13,13,9,0,11,252,128,128,128,128,248,4,2,130,130,130,
68,56,7,13,13,9,0,11,56,68,130,128,128,184,196,130,
130,130,130,68,56,6,13,13,9,1,11,252,4,8,8,8,
16,16,32,32,64,64,64,128,7,13,13,9,0,11,56,68,
130,130,130,68,56,68,130,130,130,68,56,7,13,13,9,0,
11,56,68,130,130,130,130,70,58,2,2,130,68,56};
int value_fuel;
int value_watertemp;
int value_rpm;
int value_rpm_gauge_angle;
int value_rpm_gauge_angle_rev;
int value_charge;
const uint8_t drawing_mph[] U8G_PROGMEM = {
B00000000, B10001011, B10010010, B00000000,
B00000000, B10101010, B01010010, B00000000,
B01000000, B10001010, B00010010, B00000100,
B00110000, B10001010, B00010010, B00011000,
B00001110, B00000000, B00000000, B11100000,
B00000001, B11100000, B00001111, B00000000,
B00000000, B00011111, B11110000, B00000000
};
const uint8_t drawing_rpm[] U8G_PROGMEM = {
B00000000, B11100111, B00100010, B00000000,
B00000000, B10010100, B10110110, B00000000,
B00000000, B10010100, B10101010, B00000000,
B00000000, B11100111, B00100010, B00000000,
B01000000, B10100100, B00100010, B00000100,
B00110000, B10010100, B00100010, B00011000,
B00001110, B00000000, B00000000, B11100000,
B00000001, B11100000, B00001111, B00000000,
B00000000, B00011111, B11110000, B00000000,
};
const uint8_t drawing_rpm_overspeed[] U8G_PROGMEM = {
B00001110, B00000000,
B11100000, B00000000,
B00011100, B00000000,
B01000011, B00000000,
B00111000, B00000000,
B00000111, B00000000,
B00110000, B11000000,
B00001110, B00000000,
B00010001, B11000000,
B00001100, B00110000,
B00000011, B10000000,
B00000000, B01100000,
B00000011, B00000000,
B00000000, B10000000,
B00000001, B00000000
};
const uint8_t drawing_temp[] U8G_PROGMEM = {
B00000001, B00000000,
B00000001, B01110000,
B00000001, B00000000,
B00000001, B01110000,
B00000001, B00000000,
B00011011, B10110000,
B00100001, B00001000,
B00011100, B01110000,
B00100011, B10001000
};
const uint8_t drawing_temp_line[] U8G_PROGMEM = {
B00010000, B00000000, B00000000, B00000000, B00001000,
B00001100, B00000000, B00000000, B00000000, B00110000,
B00000011, B10000000, B00000000, B00000001, B11000000,
B00000000, B01111111, B11111111, B11111110, B00000000
};
const uint8_t drawing_left_indicator[] U8G_PROGMEM = {
B00010000, // ░░░█░░░░
B00110000, // ░░██░░░░
B01111110, // ░██████░
B11111110, // ███████░
B01111110, // ░██████░
B00110000, // ░░██░░░░
B00010000 // ░░░█░░░░
};
const uint8_t drawing_right_indicator[] U8G_PROGMEM = {
B00001000,
B00001100,
B01111110,
B01111111,
B01111110,
B00001100,
B00001000
};
const unsigned char epd_bitmap_battery [] PROGMEM = {
0x00, 0x7e, 0x42, 0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint8_t epd_bitmap_bolt [] U8G_PROGMEM = {
B00000100,
B00001100,
B00011000,
B00110000,
B01100000,
B01111110,
B00000110,
B00001100 ,
B00011000,
B00110000 ,
B00100000 };
const uint8_t rpm_gauge_piece_01[] U8G_PROGMEM = {
B11111100, B00000000,
B11111110, B00000000,
B11111110, B00000000,
B11111110, B00000000,
B01111110, B00000000,
B01111111, B00000000,
B01111111, B00000000,
B01111111, B00000000,
B00111111, B10000000,
B00111111, B10000000,
B00111111, B11000000,
B00011111, B11100000,
B00011111, B11100000,
B00001111, B11110000,
B00000111, B11111000,
B00000111, B11111000,
B00000011, B11110000,
B00000001, B11100000,
B00000001, B11000000,
B00000000, B10000000
};
const uint8_t rpm_gauge_piece_02[] U8G_PROGMEM = {
B00000000, B01000000,
B00000000, B11100000,
B00000001, B11110000,
B00000001, B11111000,
B00000011, B11111100,
B00000111, B11111100,
B00000111, B11111000,
B00001111, B11110000,
B00011111, B11100000,
B00011111, B11100000,
B00111111, B11000000,
B00111111, B10000000,
B00111111, B10000000,
B01111111, B00000000,
B01111111, B00000000,
B01111111, B00000000,
B01111110, B00000000,
B11111110, B00000000,
B11111110, B00000000,
B11111110, B00000000,
B11111100, B00000000,
B11111100, B00000000
};
const uint8_t rpm_gauge_piece_03[] U8G_PROGMEM = {
B00000000, B00000011, B11000000,
B00000000, B00111111, B11000000,
B00000001, B11111111, B11000000,
B00000111, B11111111, B11000000,
B00001111, B11111111, B11000000,
B00111111, B11111111, B11000000,
B01111111, B11111111, B10000000,
B11111111, B11111000, B00000000,
B01111111, B11000000, B00000000,
B00111111, B00000000, B00000000,
B00011110, B00000000, B00000000,
B00001000, B00000000, B00000000
};
const uint8_t rpm_gauge_piece_04[] U8G_PROGMEM = {
B11111000, B00000000, B00000000,
B11111111, B10000000, B00000000,
B11111111, B11110000, B00000000,
B11111111, B11111100, B00000000,
B11111111, B11111110, B00000000,
B11111111, B11111111, B10000000,
B00111111, B11111111, B11000000,
B00000011, B11111111, B11110000,
B00000000, B01111111, B11111000,
B00000000, B00011111, B11110000,
B00000000, B00001111, B11100000,
B00000000, B00000011, B11000000,
B00000000, B00000001, B10000000
};
const uint8_t rpm_gauge_piece_05[] U8G_PROGMEM = {
B00001100, B00000000,
B00011100, B00000000,
B00111110, B00000000,
B01111111, B00000000,
B11111111, B00000000,
B01111111, B10000000,
B00111111, B11000000,
B00111111, B11000000,
B00011111, B11100000,
B00001111, B11100000,
B00001111, B11100000,
B00000111, B11110000,
B00000111, B11110000,
B00000111, B11110000,
B00000011, B11110000,
B00000011, B11111000,
B00000011, B11111000,
B00000011, B11111000,
B00000001, B11111000,
B00000001, B11111000
};
const uint8_t rpm_gauge_piece_06[] U8G_PROGMEM = {
B00000001, B11111000,
B00000011, B11111000,
B00000011, B11111000,
B00000011, B11111000,
B00000011, B11110000,
B00000111, B11110000,
B00000111, B11110000,
B00000111, B11110000,
B00001111, B11100000,
B00001111, B11100000,
B00011111, B11100000,
B00111111, B11000000,
B00111111, B11000000,
B01111111, B10000000,
B11111111, B00000000,
B11111111, B00000000,
B01111110, B00000000,
B00111100, B00000000,
B00011100, B00000000,
B00001000, B00000000
};
long initial_start = 00000;
float angle = 0;
int potentiometer_pin = 2;
int smooth_movement = 0;
void draw(void) {
// graphic commands to redraw the complete screen should be placed here
u8g.setColorIndex(1); // white
// draw gauge from 6 pieces
if (angle >= 45 ) {
u8g.drawBitmapP( 0, 32, 2, 20, rpm_gauge_piece_01);
}
if (angle >= 90) {
u8g.drawBitmapP( 0, 10, 2, 22, rpm_gauge_piece_02);
}
if (angle >= 135) {
u8g.drawBitmapP(10, 3, 3, 12, rpm_gauge_piece_03);
}
if (angle >= 180) {
u8g.drawBitmapP(28, 3, 3, 13, rpm_gauge_piece_04);
}
if (angle >= 225) {
u8g.drawBitmapP(44,12, 2, 20, rpm_gauge_piece_05);
}
if (angle >= 270) {
u8g.drawBitmapP(44,32, 2, 20, rpm_gauge_piece_06);
}
u8g.setColorIndex(0); // black
int needle_left_x_center = 28;
int needle_left_y_center = 31;
float needle_left_x_start = -sin(angle * 3.141592654 / 180.0)*17;
float needle_left_y_start = cos(angle * 3.141592654 / 180.0)*17;
float needle_left_x_end = -sin(angle * 3.141592654 / 180.0)*32;
float needle_left_y_end = cos(angle * 3.141592654 / 180.0)*32;
needle_left_x_start += 28;
needle_left_y_start += 31;
needle_left_x_end += 28;
needle_left_y_end += 31;
needle_left_x_start = (int)(needle_left_x_start+0.5);
needle_left_y_start = (int)(needle_left_y_start+0.5);
needle_left_x_end = (int)(needle_left_x_end+0.5);
needle_left_y_end = (int)(needle_left_y_end+0.5);
//-------
float angle2 = (ceil((angle+1)/45)*45)+5;
float needle_left_x_end2 = -sin((angle2) * 3.141592654 / 180.0)*32;
float needle_left_y_end2 = cos((angle2) * 3.141592654 / 180.0)*32;
needle_left_x_end2 += 28;
needle_left_y_end2 += 31;
needle_left_x_end2 = (int)(needle_left_x_end2+0.5);
needle_left_y_end2 = (int)(needle_left_y_end2+0.5);
u8g.drawTriangle(needle_left_x_center, needle_left_y_center, needle_left_x_end, needle_left_y_end, needle_left_x_end2, needle_left_y_end2);
// white
u8g.setColorIndex(1);
int ro = 71;
//Bolt Icon
u8g.drawBitmapP( 60, 28, 1, 11, epd_bitmap_bolt);
// MPH Icon
u8g.drawBitmapP( 13, 51, 4, 9, drawing_mph);
// Battery Icon
u8g.drawBitmapP( 60, 20, 9/8, 24, epd_bitmap_battery);
// Battery Fill
int bat_fill = map(value_charge, 0, 100, 43, 24);
u8g.drawLine(61, 43, 61, bat_fill);
u8g.drawLine(62, 43, 62, bat_fill);
u8g.drawLine(63, 43, 63, bat_fill);
u8g.drawLine(64, 43, 64, bat_fill);
u8g.drawLine(65, 43, 65, bat_fill);
u8g.drawLine(66, 43, 66, bat_fill);
// Temp Icon
u8g.drawBitmapP( 56, 5, 2, 9, drawing_temp);
// Temperature Line
u8g.drawBitmapP( 44, 0, 5, 4, drawing_temp_line);
int show_left_indicator = value_fuel % 20;
if (show_left_indicator > 10) {
// turn left + turn right indicator in the corners
u8g.drawBitmapP( 0, 0, 1, 7, drawing_left_indicator);
u8g.drawBitmapP( 120, 0, 1, 7, drawing_right_indicator);
}
// WATER TEMPERATURE FILL -------------------------------------------
int temp_fill_top = map(value_watertemp, 0, 100, 48, 80);
int temp_fill_mid = max(min(79,temp_fill_top),50); // bottom line end pixel x position
int temp_fill_bot = max(min(77,temp_fill_top),53); // use the same end pixel x pos, but only go between 53-77
u8g.drawLine(48, 0, temp_fill_top, 0);
u8g.drawLine(50, 1, temp_fill_mid, 1); // top line, goes from 50 >>> 80
u8g.drawLine(53, 2, temp_fill_bot, 2); // bottom line, goes from 53 >>> 77
// ------------------------------------------------------------------
u8g.setFont(tah);
// u8g.drawStr( 19, 24, String(initial_start));
// get width of the displaye string
int speed_mph = map(angle, 45, 315, 0, 220);
speed_mph = (int)speed_mph;
String aStupidWasteOfResource = String(speed_mph);
char copy[5];
aStupidWasteOfResource.toCharArray(copy, 5);
int w = u8g.getStrWidth(copy);
// center = 27, 32
// calculate left side of speed number
int speed_pos_x = 27-(w/2);
u8g.setPrintPos(speed_pos_x+2, 37+11);
u8g.print((int)speed_mph); //Places number at centre of gauge
u8g.drawTriangle
//-----
float x_start = -sin(angle * 3.141592654 / 180.0)*17;
float y_start = cos(angle * 3.141592654 / 180.0)*17;
float x_end = -sin(angle * 3.141592654 / 180.0)*28;
float y_end = cos(angle * 3.141592654 / 180.0)*28;
x_start = 28 + x_start;
y_start = 31 + y_start;
x_end = 28 + x_end;
y_end = 31 + y_end;
x_start = (int)(x_start+0.5);
y_start = (int)(y_start+0.5);
x_end = (int)(x_end+0.5);
y_end = (int)(y_end+0.5);
// MPH needle
u8g.drawLine(x_start, y_start, x_end, y_end);
// calculate a second needle, which will be offseted by 1px to cover the fill
// the offset should be 90° from the current angle, moved by fraction of pixel
float black_x_start = x_start -sin((angle-90) * 3.141592654 / 180.0)*0.7;
float black_y_start = y_start + cos((angle-90) * 3.141592654 / 180.0)*0.7;
float black_x_end = x_end -sin((angle-90) * 3.141592654 / 180.0)*0.7;
float black_y_end = y_end +cos((angle-90) * 3.141592654 / 180.0)*0.7;
float black_x_start2 = x_start -sin((angle+90) * 3.141592654 / 180.0)*0.7;
float black_y_start2 = y_start + cos((angle+90) * 3.141592654 / 180.0)*0.7;
float black_x_end2 = x_end -sin((angle+90) * 3.141592654 / 180.0)*0.7;
float black_y_end2 = y_end +cos((angle+90) * 3.141592654 / 180.0)*0.7;
black_x_start = (int)(black_x_start+0.5);
black_y_start = (int)(black_y_start+0.5);
black_x_end = (int)(black_x_end+0.5);
black_y_end = (int)(black_y_end+0.5);
black_x_start2 = (int)(black_x_start2+0.5);
black_y_start2 = (int)(black_y_start2+0.5);
black_x_end2 = (int)(black_x_end2+0.5);
black_y_end2 = (int)(black_y_end2+0.5);
u8g.setColorIndex(0); // black color
u8g.drawLine(black_x_start, black_y_start, black_x_end, black_y_end);
u8g.drawLine(black_x_start2, black_y_start2, black_x_end2, black_y_end2);
u8g.setColorIndex(1); // white color
// MPH needle
u8g.drawLine(x_start, y_start, x_end, y_end);
char mileage[20];
snprintf(mileage, sizeof(mileage), "%06ld", initial_start);
int mileage_length = strlen(mileage); // get length of the mileage string
//digit_small
u8g.setFont(digit_small);
u8g.setPrintPos(51+2, 55+9+2);
u8g.print(mileage);
// RPM integer value -----------------------
u8g.setFont(tah);
// int value_rpm_rounded = round(value_rpm/100)*100;
char value_rpm_readout[10];
snprintf(value_rpm_readout, sizeof(value_rpm_readout), "%d", value_rpm);
int value_rpm_readout_width = u8g.getStrWidth(value_rpm_readout); // pixel width of the number, will be used to center the label
int value_rpm_readout_xpos = 99-(value_rpm_readout_width/2); // left pos of the rpm string value, 99 is the center of the right gauge
// RPM number
u8g.setPrintPos(value_rpm_readout_xpos, 37+11);
u8g.setFont(tah);
u8g.print((int)value_rpm);
// ----------------------------------------
// RPM red area
u8g.setColorIndex(1); // white color
u8g.drawBitmapP( 72, 37, 2, 15, drawing_rpm_overspeed);
//RPM bitmap
u8g.drawBitmapP( 84, 51, 4, 9, drawing_rpm);
//
if (angle > 270 ) {
u8g.drawBitmapP(ro+44,32, 2, 20, rpm_gauge_piece_06);
}
if (angle >= 225) {
u8g.drawBitmapP(ro+44,12, 2, 20, rpm_gauge_piece_05);
}
if (angle >= 180) {
u8g.drawBitmapP(ro+28, 3, 3, 13, rpm_gauge_piece_04);
}
if (angle >= 135) {
u8g.drawBitmapP(ro+10, 3, 3, 12, rpm_gauge_piece_03);
}
if (angle >= 90) {
u8g.drawBitmapP(ro+ 0, 10, 2, 22, rpm_gauge_piece_02);
}
if (angle >= 45) {
u8g.drawBitmapP(ro+ 0, 32, 2, 20, rpm_gauge_piece_01);
}
float rpm_x1 = -sin(angle * 3.141592654 / 180.0)*17;
float rpm_y1 = cos(angle * 3.141592654 / 180.0)*17;
float rpm_x2 = -sin(angle * 3.141592654 / 180.0)*28;
float rpm_y2 = cos(angle * 3.141592654 / 180.0)*28;
rpm_x1 = 99 + rpm_x1;
rpm_y1 = 31 + rpm_y1;
rpm_x2 = 99 + rpm_x2;
rpm_y2 = 31 + rpm_y2;
rpm_x1 = (int)(rpm_x1+0.5);
rpm_y1 = (int)(rpm_y1+0.5);
rpm_x2 = (int)(rpm_x2+0.5);
rpm_y2 = (int)(rpm_y2+0.5);
// MPH needle
u8g.drawLine(rpm_x1, rpm_y1, rpm_x2, rpm_y2);
// calculate a second needle, which will be offseted by 1px to cover the fill
// the offset should be 90° from the current angle, moved by fraction of pixel
float rpm_cover_x_start = rpm_x1 -sin((angle-90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_y_start = rpm_y1 + cos((angle-90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_x_end = rpm_x2 -sin((angle-90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_y_end = rpm_y2 +cos((angle-90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_x_start2 = rpm_x1 -sin((angle+90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_y_start2 = rpm_y1 + cos((angle+90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_x_end2 = rpm_x2 -sin((angle+90) * 3.141592654 / 180.0)*0.7;
float rpm_cover_y_end2 = rpm_y2 +cos((angle-90) * 3.141592654 / 180.0)*0.7;
rpm_cover_x_start = (int)(rpm_cover_x_start+0.5);
rpm_cover_y_start = (int)(rpm_cover_y_start+0.5);
rpm_cover_x_end = (int)(rpm_cover_x_end+0.5);
rpm_cover_y_end = (int)(rpm_cover_y_end+0.5);
rpm_cover_x_start2 = (int)(rpm_cover_x_start2+0.5);
rpm_cover_y_start2 = (int)(rpm_cover_y_start2+0.5);
rpm_cover_x_end2 = (int)(rpm_cover_x_end2+0.5);
rpm_cover_y_end2 = (int)(rpm_cover_y_end2+0.5);
u8g.setColorIndex(0); // black color
u8g.drawLine(rpm_cover_x_start, rpm_cover_y_start, rpm_cover_x_end, rpm_cover_y_end);
u8g.drawLine(rpm_cover_x_start2, rpm_cover_y_start2, rpm_cover_x_end2, rpm_cover_y_end2);
u8g.setColorIndex(1); // white color
// MPH needle
u8g.drawLine(rpm_x1, rpm_y1, rpm_x2, rpm_y2);
// ----------------------------------------------------------------------------------------------------------------
}
void setup() {
// put your setup code here, to run once:
u8g.setContrast(255); // set maximum contrast for the display
Serial.begin(9600); // start serial connection, used only for debugging on the PC, can be commented out once the project is complete
}
void loop() {
// put your main code here, to run repeatedly:
u8g.firstPage();
do {
draw();
// u8g.nextPage();
} while( u8g.nextPage() );
// rebuild the picture after some delay
//delay(1);
initial_start++;
int inputvalue = analogRead(A0); //Value used for protype from potentiometer
int input2 = analogRead(A1);
inputvalue = constrain(inputvalue, 0, 670);
input2 = constrain(input2, 0, 670);
//angle = constrain(inputvalue /2, 45, 315);
angle = map(inputvalue, 0, 670, 45, 315); // remap the potentiometer value from 0-670 to 45-315°. It does not go all the way to 1024 because I´m only using 3.3V
value_fuel = map(inputvalue, 0, 670, 0, 100); // fuel value, for now, take everything from one potentiometer
value_watertemp = map(inputvalue, 0, 670, 0, 100); // water temperature value, for now, take everything from one potentiometer
value_rpm = map(inputvalue, 0, 670, 0, 8000); // RPM value
value_charge = map(input2, 0, 670, 0, 100);
value_rpm_gauge_angle = map(inputvalue, 0, 670, 315, 45); // RPM gauge angle value
value_rpm_gauge_angle_rev = map(inputvalue, 0, 670, 45, 315);
}