Thursday 22 January 2015

Arduino - OLED Module with 3D demo sketch


Arduino Uno compatible OLED 128x64

Recently I bought a small OLED 128x64 screen module for use with my Arduino Uno. The module I chose was based upon a few key requirements. The module had to be cheap, under (£5 GPB), 128x64 screen resolution, work within 3-5volts , I2C compatible, minimum 4 wire setup and not require additional electrical components to get up and running. The module I eventually bought was a Chinese import from Amazon UK.

The module is manufactured by Heltec (Heltec.cn)
0.96 Inch I2C IIC SPI Serial 128 x 64 OLED LCD LED
http://www.amazon.co.uk/dp/B00NHP6HVQ/ref=pe_385721_37038051_TE_3p_dp_1

Wiring the OLED module


The Arduino has two sets of pins allocated to I2C communication.Arduino boards with the R3 layout (1.0 pinout), the SDA (data line) and SCL (clock line) are on the pin headers close to the AREF pin. I used the alternative pins A4 (SDA), A5 (SCL) only to keep the wiring together.

OLED - Arduino Uno
VCC ---> 5V
GND ---> GND
SCL ---> Pin A5
SDA ---> Pin A4

U8G library for graphics

I chose to use the U8GLib library for all necessary graphics functions. The U8GLib examples have lists of Constructors (device drivers) embedded into the code, so matching the module to an appropriate driver was easy. (I initially tried using the Adafruit libraries but had problems getting images to show on the screen).

The library can be downloaded here:
https://code.google.com/p/u8glib/

Installation 

1.  Copy the U8G files to an appropriate Arduino Library folder e.g. 
C:\Program Files\Arduino\libraries\U8glib\
2.  Launch the Arduino application
3.  Copy the 3d wireframe code below into a new sketch.
4.  Upload the sketch to the Arduino and enjoy the spinning 3D cube!

Compilation using the U8G library usually takes a while, so be patient!

Arduino sketch

//3D_Cube for Arduino OLED module by Colin Ord, 9/1/2015
//A port of my original JustBasic Cube_3D demo to the Arduino Uno using U8G library.

#include "U8glib.h"

//The following line will need changing depending on your board type!
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI

float tx, nx, p;
float ty, ny, py;
float rot, rotx, roty, rotz, rotxx, rotyy, rotzz, rotxxx, rotyyy, rotzzz;
int i; //0 to 360
int fl, scale; //focal length
int wireframe[12][2];

int originx = 64;
int originy = 32; //32

int front_depth = 20;
int back_depth = -20;

//Store cube vertices
int cube_vertex[8][3] = {
{ -20, -20, front_depth},
{20, -20, front_depth},
{20, 20, front_depth},
{ -20, 20, front_depth},
{ -20, -20, back_depth},
{20, -20, back_depth},
{20, 20, back_depth},
{ -20, 20, back_depth}
};

int fd = 0; //0=orthographic

void setup(void)
{
u8g.begin();

//Clear Screen
u8g.firstPage();
do {
// empty screen
} while ( u8g.nextPage() );
}

void draw_vertices(void)
{
u8g.drawPixel (rotxxx, rotyyy);
}

void draw_wireframe(void)
{
u8g.drawLine(wireframe[0][0], wireframe[0][1], wireframe[1][0], wireframe[1][1]);
u8g.drawLine(wireframe[1][0], wireframe[1][1], wireframe[2][0], wireframe[2][1]);
u8g.drawLine(wireframe[2][0], wireframe[2][1], wireframe[3][0], wireframe[3][1]);
u8g.drawLine(wireframe[3][0], wireframe[3][1], wireframe[0][0], wireframe[0][1]);

//cross face above
u8g.drawLine(wireframe[1][0], wireframe[1][1], wireframe[3][0], wireframe[3][1]);
u8g.drawLine(wireframe[0][0], wireframe[0][1], wireframe[2][0], wireframe[2][1]);

u8g.drawLine(wireframe[4][0], wireframe[4][1], wireframe[5][0], wireframe[5][1]);
u8g.drawLine(wireframe[5][0], wireframe[5][1], wireframe[6][0], wireframe[6][1]);
u8g.drawLine(wireframe[6][0], wireframe[6][1], wireframe[7][0], wireframe[7][1]);
u8g.drawLine(wireframe[7][0], wireframe[7][1], wireframe[4][0], wireframe[4][1]);

u8g.drawLine(wireframe[0][0], wireframe[0][1], wireframe[4][0], wireframe[4][1]);
u8g.drawLine(wireframe[1][0], wireframe[1][1], wireframe[5][0], wireframe[5][1]);
u8g.drawLine(wireframe[2][0], wireframe[2][1], wireframe[6][0], wireframe[6][1]);
u8g.drawLine(wireframe[3][0], wireframe[3][1], wireframe[7][0], wireframe[7][1]);
}

void loop(void)
{
//picture loop
for (int angle = 0; angle <= 360; angle = angle + 3) {
u8g.firstPage();
do {
for (int i = 0; i < 8; i++) {

rot = angle * 0.0174532; //0.0174532 = one degree
//rotateY
rotz = cube_vertex[i][2] * cos(rot) - cube_vertex[i][0] * sin(rot);
rotx = cube_vertex[i][2] * sin(rot) + cube_vertex[i][0] * cos(rot);
roty = cube_vertex[i][1];
//rotateX
rotyy = roty * cos(rot) - rotz * sin(rot);
rotzz = roty * sin(rot) + rotz * cos(rot);
rotxx = rotx;
//rotateZ
rotxxx = rotxx * cos(rot) - rotyy * sin(rot);
rotyyy = rotxx * sin(rot) + rotyy * cos(rot);
rotzzz = rotzz;

//orthographic projection
rotxxx = rotxxx + originx;
rotyyy = rotyyy + originy;

//store new vertices values for wireframe drawing
wireframe[i][0] = rotxxx;
wireframe[i][1] = rotyyy;
wireframe[i][2] = rotzzz;

draw_vertices();
}

draw_wireframe();

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

4 comments:

  1. Cool i managed to port over the code to work with the adafruit graphics lib. thanks for sharing the code :)
    https://www.youtube.com/watch?v=An-vnfhKDhk

    ReplyDelete
    Replies
    1. Not a problem. I hope you find it useful for future projects.

      Delete
  2. Is there a way to check the design for using this code on the module?

    Shalin @ Creately

    ReplyDelete
    Replies
    1. Sorry, but I don't understand your question. Can you please elaborate?

      Delete