Release 2016.9.7 / Update 2017.6.18

Use OLED with “u8glib” : part 3

This article is about how to draw texts and values on screen. Please read after previous and the time before last.

Wiring

Wiring is same as previous instruction. You also need variable resistor. This wiring diagram is I2C connection. Please check here if your screen is SPI connection. simple_wiring_u8g_I2C_breadboard

Review

Based on the review, I will write sketch using the variable resistor, first.

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);   // SPI connection
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

#define VOL  A0
#define VMAX 1013
int vol_val = 0;


void setup() {
  pinMode(VOL, INPUT);
  u8g.setColorIndex(1);
}


void loop() {

  vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);

  byte val = map(vol_val, 0, VMAX, 0, 127);

  u8g.firstPage();
  do {

    u8g.drawBox(0, 60, val, 3);

  } while (u8g.nextPage());
}

This sketch has been updated than the last time. And it is basic sketch in this article.

Draw characters on screen

If you want to display strings by “u8glib”,

1. Set Font
2. Set Position and cast strings

Font is kept once you set it. So if you won’t use several fonts, you can omit process 1 for each draw.

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

#define VOL  A0
#define VMAX 1013
int vol_val = 0;


void setup() {
  pinMode(VOL, INPUT);
  u8g.setColorIndex(1);
}


void loop() {

  vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);

  byte val = map(vol_val, 0, VMAX, 0, 127);

  u8g.firstPage();
  do {

    u8g.setFont(u8g_font_unifont);
    u8g.drawStr( 0, 22, "Hello World!");

    u8g.drawBox(0, 60, val, 3);

  } while (u8g.nextPage());
}

Set Font

What you need to set the font,

u8g.setFont( font name );

Font has been prepared in advance in the “u8glib” library. And it is packed in the sketch at compiling. So if you add more font, sketch size will expand. In fact, the most hard thing for using “u8glib” is how reduce font size. There is a font “u8g_font_unifont” and you can check detail here. Then watch detail of the font,

u8g_font_unifont BBX Width 16,  Height 16,  Capital A 10 Font data size: 5551

This font size is 5.5 KB, but Arduino memory size is 32 KB. So you need one-sixth size memory by one font. u8glib_size_capa

Much ingenuity is required if you want to use multiple fonts.

Font List

Available font on “u8glib” You can use any font on the page. But it’s too many font to choose one. And File size will vary greatly depending on series of the font. If you got a font which you want to use, set the font name to “u8g.setFont” arguments. If you want to use “u8g_font_8x13r” font, for example,

u8g.setFont( u8g_font_8x13r );

Now you can use it. I recommend you to use font that is attached ‘r’ to the end of the name. Because it’s much lighter.

Draw character string

To draw character string,

u8g.drawStr( x, y, character string );

It’s same as graphics drawing. But be careful that axis position of the text is lower left.

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

#define VOL  A0
#define VMAX 1013
int vol_val = 0;


void setup() {
  pinMode(VOL, INPUT);
  u8g.setColorIndex(1);
}


void loop() {

  vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);

  byte val = map(vol_val, 0, VMAX, 0, 127);

  u8g.firstPage();
  do {

    u8g.setFont(u8g_font_8x13r);
    u8g.drawStr( 0, 20, "Hello World!");

    u8g.drawBox(0, 60, val, 3);

  } while (u8g.nextPage());
}
u8glib_axis
x0、y20 is here.

Now you can see how string is drawn. If you want several fonts,

    u8g.setFont(u8g_font_unifont);
    u8g.drawStr( 0, 20, "Hello World!");
    u8g.setFont(u8g_font_8x13r);
    u8g.drawStr( 64, 20, "Goodbye World!");

Use “u8g.setFont” before you draw character.

u8glib_hello_goodbye

Once you define font, it is compiled in your sketch even if you don’t use it. Conversely, you should set “u8g.setFont” at “void setup”, if you won’t use any other font.

Draw values

I’m going to draw value by reading variable resistor, now. There are two options to draw value as character, easy way and hard way. The hard way is difficult, of course. But it’s convenient to layout.

option one

set position:u8g.setPrintPos(x, y);
draw value :u8g.print(value);

“Print” functions works as same as “Serial.print”. It’s very simple to draw values.

option two

Make your own character string by pointer. First, I will try to display 1 digit of the value.

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

#define VOL  A0
#define VMAX 1013
int vol_val = 0;


void setup() {
  pinMode(VOL, INPUT);
  u8g.setColorIndex(1);
}


void loop() {

  vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);

  char num [2] = {"0"};
  num [0] = '0' + vol_val % 10;

  u8g.firstPage();
  do {

    u8g.setFont(u8g_font_unifont);
    u8g.drawStr(95, 55, num);

  } while (u8g.nextPage());
}

u8glib_first_num

I make array num[2], then set 1 digit of value “vol_val” to it. You can get the digit by ‘%’. And I get ASCII code num by adding ‘0’ to the value. This method is very useful and important. For example, ‘0’ + 5 = ? ‘0’ means number 48 as value on ASCII code. 48 + 5 = 53 So by this method, you can convert int value to number of char. By Converting for each digit by this way, you can display value.

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

#define VOL  A0
#define VMAX 1013
int vol_val = 0;


void setup() {
  pinMode(VOL, INPUT);
  u8g.setColorIndex(1);
}


void loop() {

  vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);

  char num [5] = {"0000"};
  num [0] = '0' + (vol_val / 1000) % 10;
  num [1] = '0' + (vol_val / 100) % 10;
  num [2] = '0' + (vol_val / 10) % 10;
  num [3] = '0' + vol_val % 10;

  u8g.firstPage();
  do {

    u8g.setFont(u8g_font_unifont);
    u8g.drawStr(95, 55, num);

  } while (u8g.nextPage());
}

It will work.

u8glib_hello_val  

Summary : Simplified sketch to display the values

Finally, I wrote a simplified sketch which displays value by variable resistor.

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);

#define VOL  A0
#define VMAX 1013
int vol_val = 0;

#define DEG 4                       // digit


void setup() {
  pinMode(VOL, INPUT);
  u8g.setColorIndex(1);             // paint pixel
  u8g.setFont(u8g_font_unifont);    // choose font
}


void loop() {

  vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);   // get value of VR

  byte val = map(vol_val, 0, VMAX, 0, 127);   // map the value in screen range

  char num_array [DEG + 1];                   // array for VR
  bool space = true;                          // make space depends on digit

  for (byte i = 0 ; i < DEG ; i++)            // repeat for the digit
  {
    // Calculation for the carry digit
    long digit = 1;
    for (byte ii = 1 ; ii <= (DEG - 1 - i) ; ii++) digit *= 10;

    // get a single digit by dividing the value
    byte cur_val = (vol_val / digit) % 10;

    // get highest digit
    if ((vol_val == 0 && i == (DEG - 1)) || cur_val != 0) space = false;

    if (space) num_array [i] = ' ';       // fill array with 0 unless value is over.
    else num_array [i] = '0' + cur_val;   // fill number
  }

  num_array [DEG] = '
#include "U8glib.h"
//U8GLIB_SSD1306_128X64 u8g(4, 5, 6, 7);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);
#define VOL  A0
#define VMAX 1013
int vol_val = 0;
#define DEG 4                       // digit
void setup() {
pinMode(VOL, INPUT);
u8g.setColorIndex(1);             // paint pixel
u8g.setFont(u8g_font_unifont);    // choose font
}
void loop() {
vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);   // get value of VR
byte val = map(vol_val, 0, VMAX, 0, 127);   // map the value in screen range
char num_array [DEG + 1];                   // array for VR
bool space = true;                          // make space depends on digit
for (byte i = 0 ; i < DEG ; i++)            // repeat for the digit
{
// Calculation for the carry digit
long digit = 1;
for (byte ii = 1 ; ii <= (DEG - 1 - i) ; ii++) digit *= 10;
// get a single digit by dividing the value
byte cur_val = (vol_val / digit) % 10;
// get highest digit
if ((vol_val == 0 && i == (DEG - 1)) || cur_val != 0) space = false;
if (space) num_array [i] = ' ';       // fill array with 0 unless value is over.
else num_array [i] = '0' + cur_val;   // fill number
}
num_array [DEG] = '\0';                 // set null character to last array
u8g.firstPage();
do {
u8g.drawStr(0, 22, "Hello World!");   // draw character
u8g.drawStr(95, 55, num_array);       // draw value
u8g.drawBox(0, 60, val, 3);           // draw gauge
vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);   // get VR value on case of "while loop"
} while (u8g.nextPage());
}
'; // set null character to last array u8g.firstPage(); do { u8g.drawStr(0, 22, "Hello World!"); // draw character u8g.drawStr(95, 55, num_array); // draw value u8g.drawBox(0, 60, val, 3); // draw gauge vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL); // get VR value on case of "while loop" } while (u8g.nextPage()); }

You can display more digit value if you change define of “DEG”. Well, are you able to use u8glib now ? I hope this articles will help you. For more information about ‘u8glib’, check here.

part 2
Part 1

9 thoughts on “Use OLED with “u8glib” : part 3

    1. Thank you for comment.
      Sorry to say, code of the url seems to be for “Adafruit” library. And I haven’t learn neither the library and how to use the sensor.
      So, basically, I can’t help your project. But some rewrite of the code might be workable.

      Watch Out! I changed sensor pin 10 to 2.

      #include 
      
      U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8);  // SW SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9;
      
      int Sensorpin = 2;  // this is changed because of SPI pins
      float pulsetime = 0;
      int hertz = 0;
      
      char bar[12] = "-----------";
      char progress[12];
      
      
      void setup() {
        u8g.setColorIndex(1);  // pixel on
        u8g.setFont(u8g_font_8x13r);
      }
      
      
      void loop() {
      
        pulsetime = pulseIn(Sensorpin, HIGH) + pulseIn(Sensorpin, LOW);
        hertz = int((1000000 / pulsetime) - 50);
      
        //Serial.println(hertz);
      
        memset(progress, 0, sizeof(progress));
      
        u8g.firstPage();
        do
        {
          for (int i = 0; i < 11; i++)
          {
            strncpy (progress, bar, i);
      
            u8g.setPrintPos(4, 0);
            u8g.print(progress);
      
            u8g.setPrintPos(4, 25);
            if (hertz < 100) {
              u8g.print("E " + String(hertz));
            } else if (hertz < 10) {
              u8g.print("E 0" + String(hertz));
            } else {
              u8g.print("E" + String(hertz));
            }
          }
        } while (u8g.nextPage());
        delay(900);
      }
      

      Good luck!

  1. Thank you! Before the hertz stuff I’m really lost in here and tearing my hairs ;

    vol_val = 0.9 * vol_val + 0.1 * analogRead(VOL);
    byte val = map(vol_val, 0, VMAX, 0, 127);

    Any touch here will make my gauge bar(u8g.drawBox, val) fail! I couldn’t tell that I really understood this code. Basically I’m trying to make the gauge screen (u8g.drawBox(val)) range to accept 0v to 5v and numbers(u8g.drawStr(num)) to 0-100 %

    So I modify the code;
    vol_val = 5.0 / 1024.0 * (analogRead (VOL) + 0.5) ;
    u8g.drawBox(0, 44, val, 22);

    but no go!

    1. At first, to be sure, hertz(PWM) is not same as analog voltage. Be careful.

      The analogRead() function returns 0-1024 value depends on its system voltage. So if you use 5V arduino, you don’t have to remap value. 5V is 1024, 0V is 0.
      But, instead, you should remap the value to OLED pixel range.
      For example, if I use 128×64 pixel OLED, screen size value goes 127×63. And,

      u8g.drawBox(0, 43, analogRead (VOL) / 1024.0 * 127, 20);

      Incidentally, I recommend you use “map()” function to be much easier.

      In addition, “0.9 * vol_val + 0.1 * analogRead(VOL);” is very practical way to get stable value.

      Check here,
      https://jumbleat.com/2016/08/17/reduce_fluctuations/

  2. Hi!
    Okay I misunderstood how the sensor works. The sensor send PWM signal 50-150 hertz. So 50hz means %0 Alcohol and 150 hz means %100 alcohol. I get rid of some codes and now it works.

    http://img.photobucket.com/albums/v124/cucuman/20170501_035320.jpg

    Here is the code;

    #include “U8glib.h”

    U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8); // SW SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9

    int Sensorpin = 2;
    float pulsetime = 0;
    int hertz = 0;

    void setup() {
    u8g.setColorIndex(1);
    u8g.setFont(u8g_font_fub35n);

    }

    void loop() {

    pulsetime = pulseIn(Sensorpin, HIGH) + pulseIn(Sensorpin, LOW);
    hertz = int((1000000 / pulsetime) – 50);

    u8g.firstPage();
    do
    {

    u8g.drawBox(25,4,8,34); // dikey I
    u8g.drawBox(31,4,15,6); // yatay 1
    u8g.drawBox(31,18,15,6); // yatay 2
    u8g.drawBox(31,32,15,6); // yatay 3
    u8g.setPrintPos(49, 39);
    u8g.print(hertz);
    u8g.drawBox(0, 44, hertz, 22);

    } while (u8g.nextPage());
    delay(900);
    }

    But as you may see the bar graph doesn’t fit to screen. I’m trying to understand how u8g.drawBox(0, 44, hertz, 22); works on a screen range. Thank you for your great help

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


This site uses Akismet to reduce spam. Learn how your comment data is processed.