Knop OLED SSD1306 Arduino SimulIDE u8g2

Posted on
Knop OLED SSD1306 I2C Arduino SimulIDE & u8g2 Library

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.