Free Code Knop OLED I2C u8g2
In this article I share the program code that you can use to display the Knop OLED SSD1306 I2C Arduino SimulID using SimulIDE and the u8g2 Library.
The original tutorial and source used ug8lib, but according to the source description of the ug8lib library, it is no longer being developed in the future, so it only uses u8g2.
Therefore, based on the upir project, I tried to convert the program code that had been created using the u8g2 library. Please use the following program code:
//Original source by Upir https://www.youtube.com/watch?v=NPfaLKKsf_Q&ab_channel=upir
//Convert to u8g2 library by Chippiko.com
#include <Arduino.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
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; // x pos for pixel
float pixel_y = 0; // y pos for pixel
float line_x = 0; // x pos for line end
float line_y = 0; // y pos for line end
float text_x = 0; // x pos for text
float text_y = 0; // y pos for text
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 = 92; // radius for pixel tickmarks
int radius_line = 87; // radius for line end
int radius_text = 75; // radius for text
int angle; // angle for the individual tickmarks
int tick_value; // numeric value for the individual tickmarks
byte precalculated_x_radius_pixel[180]; // lookup table to prevent expensive sin/cos calculations
byte precalculated_y_radius_pixel[180]; // lookup table to prevent expensive sin/cos calculations
unsigned long millis_time; // fps
unsigned long millis_time_last; // fps
int fps; // actual FPS value
static const unsigned char upir_logo[] U8X8_PROGMEM = {
0x75, 0xfd, // ░░░█░█░███░█░███
0x55, 0xf4, // ░░░█░█░█░█░░░█░█
0x35, 0xed, // ░░░█░█░██░░█░██░
0x13, 0xf5 // ░░░██░░█░░░█░█░█
};
void setup() {
u8g2.setColorIndex(1); // set color to white
u8g2.begin();
u8g2.enableUTF8Print();
for (int i = 0; i < 180; i++) { // pre-calculate x and y positions into the look-up tables
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() {
u8g2.firstPage(); // required for u8g library
do { // --//--
u8g2.setColorIndex(1); // set color to white
u8g2.setFont(u8g_font_6x10r); // set smaller font for tickmarks
// calculate tickmarks
for (int i = -48; i <= 48; i = i + 3) { // only try to calculate tickmarks that would end up be displayed
angle = i + ((potentiometer_value * 3) / 10) % 3; // final angle for the tickmark
tick_value = round((potentiometer_value / 10.0) + angle / 3.0); // get number value for each tickmark
//pixel_x = sin(radians(angle)) * radius_pixel + center_x; // calculate the tickmark pixel x value
//pixel_y = -cos(radians(angle)) * radius_pixel + center_y; // calculate the tickmark pixel y value
pixel_x = precalculated_x_radius_pixel[angle + 90]; // get x value from lookup table
pixel_y = precalculated_y_radius_pixel[angle + 90]; // get y value from lookup table
if (pixel_x > 0 && pixel_x < 128 && pixel_y > 0 && pixel_y < 64) { // only draw inside of the screen
if (tick_value >= 0 && tick_value <= 100) { // only draw tickmarks between values 0-100%, could be removed when using rotary controller
if (tick_value % 10 == 0) { // draw big tickmark == lines + text
line_x = sin(radians(angle)) * radius_line + center_x; // calculate x pos for the line end
line_y = -cos(radians(angle)) * radius_line + center_y; // calculate y pos for the line end
u8g2.drawLine(pixel_x, pixel_y, line_x, line_y); // draw the line
text_x = sin(radians(angle)) * radius_text + center_x; // calculate x pos for the text
text_y = -cos(radians(angle)) * radius_text + center_y; // calculate y pos for the text
itoa(tick_value, buffer, 10); // convert integer to string
string_width = u8g2.getStrWidth(buffer); // get string width
u8g2.drawStr(text_x - string_width / 2, text_y, buffer); // draw text - tickmark value
}
else { // draw small tickmark == pixel tickmark
u8g2.drawPixel(pixel_x, pixel_y); // draw a single pixel
}
}
}
}
// draw the big value on top
u8g2.setFont(u8g_font_8x13r); // set bigger font
dtostrf(potentiometer_value / 10.0, 1, 1, buffer); // float to string, -- value, min. width, digits after decimal, buffer to store
sprintf(buffer, "%s%s", buffer, "%"); // add some random ending character
string_width = u8g2.getStrWidth(buffer); // calculate string width
u8g2.setColorIndex(1); // set color to white
u8g2.drawRBox(64 - (string_width + 4) / 2, 0, string_width + 4, 11, 2); // draw background rounded rectangle
u8g2.drawTriangle( 64 - 3, 11, 64 + 4, 11, 64, 15); // draw small arrow below the rectangle
u8g2.setColorIndex(0); // set color to black
u8g2.drawStr(64 - string_width / 2, 10, buffer); // draw the value on top of the display
// draw upir logo
u8g2.setColorIndex(1);
u8g2.drawXBMP(112, 0, 13, 4, upir_logo);
// display FPS, could be commented out for the final product
//u8g2.setColorIndex(1); // set color to white
//u8g2.setFont(u8g_font_5x7r); // set very small font
//itoa(fps, buffer, 10); // convert FPS number to string
//u8g2.drawStr(0,10,buffer); // draw the FPS number
} while ( u8g2.nextPage() ); // required for u8g library
potentiometer_value = map(analogRead(A0), 0, 1023, 1000, 0); // read the potentiometer value, remap it to 0-1000
millis_time_last = millis_time; // store last millisecond value
millis_time = millis(); // get millisecond value from the start of the program
fps = round(1000.0 / (millis_time * 1.0 - millis_time_last)); // calculate FPS (frames per second) value
}
To be able to know how this program code works, you can at least watch the original video. In this video you will learn how pixel movement occurs.
To be able to see how this works on the simulIDE application, please watch the following video.
Hopefully this Knop OLED SSD1306 I2C Arduino SimulIDE & u8g2 Library article is useful.