// simple project using Arduino UNO and 128x64 OLED Display,
// created by upir, 2022
// youtube channel: https://www.youtube.com/upir_upir
// FULL TUTORIAL: https://youtu.be/NPfaLKKsf_Q
// u8g fonts (fonts available for u8g library): https://nodemcu-build.com/u8g-fonts.php
// u8g documentation: https://github.com/olikraus/u8glib/wiki/userreference
// Arduino uno: http://store.arduino.cc/products/arduino-uno-rev3
// Arduino breadboard prototyping shield: https://www.adafruit.com/product/2077
// Wokwi starting project: https://wokwi.com/arduino/projects/300867986768527882
// Transparent display buy: https://a.aliexpress.com/_mKGmhKg
// Photopea (online Photoshop-like tool): https://www.photopea.com/
// image2cpp (convert images into C code): https://javl.github.io/image2cpp/
#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); // SPI communication: SCL = 13, SDA = 11, RES = 10, DC = 9, CS = 8
int potentiometer_value = 0; // value from the potentiometer
char buffer[20]; // helper buffer for converting values into C-style string (array of chars)
int string_width; // helper value for string widths
float pixel_x = 0;
float pixel_y = 0;
float line_x = 0;
float line_y = 0;
float text_x = 0;
float text_y = 0;
int center_x = 64; // x center of the knob
int center_y = 108; // y center of the knob (outside of the screen)
int radius_pixel = 98; // radius for pixel tickmarks
int radius_line = 93; // radius for line end
int radius_text = 83; // radius for text
int angle;
int tick_value;
unsigned millis_time; // fps
unsigned millis_time_last; // fps
int fps;
byte precalculated_x_radius_pixel[180];
byte precalculated_y_radius_pixel[180];
int pot2 = 0;
int roll = 0;
int roll_pxl_x=0;
int roll_pxl_y=0;
int roll_line_x = 0;
int roll_line_y = 0;
void setup() {
u8g.setFont(u8g_font_tpssb);
u8g.setColorIndex(1); // set color to white (on blk default bkgnd)
// actual angle only goes from -48 < angle < +48
// precalc x_radius(angle) & y_radius(angle) where -90 < angle < +90
// note index into lookup table is 0 < index < 180
// so index = angle + 90 & angle = index - 90
for (int i =0; i < 180; i++){
precalculated_x_radius_pixel[i] = sin(radians(i-90)) * radius_pixel + center_x;
precalculated_y_radius_pixel[i] = -cos(radians(i-90)) * radius_pixel + center_y;
}
}
void loop() {
u8g.firstPage(); // required for u8g library
do { // --//--
u8g.setColorIndex(1);
u8g.setFont(u8g_font_6x10r); // use smaller fonts for guage labels
// draw tick marks from -48 deg to +48 deg every 3 deg
for (int i=-48; i<=48; i=i+3){
angle = i + (potentiometer_value*3/10) % 3;
tick_value = round(potentiometer_value/10.0 + angle/3.0);
//pixel_x = sin(radians(angle)) * radius_pixel + center_x;
//pixel_y = -cos(radians(angle)) * radius_pixel + center_y;
pixel_x = precalculated_x_radius_pixel[angle+90];
pixel_y = precalculated_y_radius_pixel[angle+90];
if (pixel_x > 0 && pixel_x < 128 && pixel_y > 0 && pixel_y < 64){
if (tick_value >= 0 && tick_value <= 99){ // restrict gauge to 0 - 100
if (tick_value % 10 == 0){ // draw line
line_x = sin(radians(angle)) * radius_line + center_x;
line_y = -cos(radians(angle)) * radius_line + center_y;
u8g.drawLine(pixel_x, pixel_y, line_x, line_y);
text_x = sin(radians(angle)) * radius_text + center_x;
text_y = -cos(radians(angle)) * radius_text + center_y;
itoa(tick_value, buffer, 10);
string_width = u8g.getStrWidth(buffer);
u8g.drawStr(text_x - string_width/2, text_y, buffer);
}
else { // draw small tickmark
u8g.drawPixel(pixel_x,pixel_y);
}
}
}
}
// draw the big value on the top
//u8g.setFont(u8g_font_8x13r);
dtostrf(potentiometer_value/10.0,1,1,buffer);
//sprintf(buffer, "%s%s", buffer, "%");
string_width = u8g.getStrWidth(buffer);
u8g.setColorIndex(1); // white - box will get draw in white
//u8g.drawRBox(64-(string_width+4)/2, 0, string_width+4, 11, 2);
//u8g.drawRBox(5, 0, string_width+4, 11, 2);
//u8g.drawTriangle(64-3, 11, 64+4, 11, 64, 15);
u8g.drawTriangle(64-4, 4, 64+5, 4, 64, 9);
//u8g.setColorIndex(0); // black - text in the box will black (on white bkgnd of the box)
//u8g.drawStr(64-string_width/2, 10, buffer);
u8g.drawStr(96, 8, buffer);
// display fps
/***
u8g.setColorIndex(1); // set color to white cuz it's getting drawn on default blk bknd
u8g.setFont(u8g_font_5x7r); // display fps in a small font
itoa(fps, buffer, 10); // convert base10 integer to string
u8g.drawStr(0,10,buffer);
****/
//u8g.setFont(u8g_font_5x7r);
u8g.setColorIndex(1);
// draw horiz tick marks for -30 to +30 linear gauge
// display is Xmax=128, Ymax=64 |---60---| 60x2 = ....120....
roll_pxl_y = 45; // this sets the location of the roll gauge in the y-dir
// Display actual roll value centered over 0 on the linear gauge
itoa(roll, buffer, 10);
string_width=u8g.getStrWidth(buffer);
u8g.drawStr(64 - string_width/2, roll_pxl_y-6, buffer);
for (int i=-30; i<=30; i++){ // -30 < roll < +30
// draw tickmark every 2 pixels
roll_pxl_x = map(i, -30, 30, 5, 121);
u8g.drawPixel(roll_pxl_x, roll_pxl_y);
// draw vertical tick mark every 10 deg using modulo 10 of i
if (i % 10 == 0) {
roll_line_x = roll_pxl_x;
roll_line_y = roll_pxl_y+5;
u8g.drawLine(roll_pxl_x, roll_pxl_y, roll_line_x, roll_line_y);
// label the vertical tick marks
if (abs(i)==20 || i == 0){
itoa(i, buffer, 10);
string_width = u8g.getStrWidth(buffer);
u8g.drawStr(roll_line_x - string_width/2, roll_line_y+12, buffer);
}
}
}
// drawbox below linear gauge to indicate
// wing orientation left or right of center
if (roll>=0 && roll<=30){ // drawbox right of center
// x y w h
u8g.drawBox(63, roll_pxl_y-2, roll*2, 5);
}
if (roll<0){ // drawbox left of center
// ---- x ------ y ----w----- h
u8g.drawBox(63-abs(roll*2), roll_pxl_y-2, abs(roll*2), 5);
}
} while ( u8g.nextPage() ); // required for u8g library
potentiometer_value = map(analogRead(A0), 0, 1023, 1000, 0); // read the potentiometer value, remap it to 0-1000
pot2 = analogRead(A3);
// left 0 right
// simulate imu_roll_angle: -30 < roll < +30
roll = map(pot2, 0, 1023, -30, 30);
millis_time_last = millis_time;
millis_time = millis();
fps = round(1000.0/(millis_time*1.0 - millis_time_last));
}