Wednesday, 6 November 2013

Another update to the OLED 1602 Library

I've made a change to the 1602 OLED library and also added a new function.

I've modified the sendString() function to now include the cursor position data and added a new function called sendFloat(), this allows you to send float data values, such as temperature, to the LCD ant it gets converted to a string before being sent to the display.

The sendFloat function takes the following parameters: float value, minimum length inc. decimal point, number of positions after the decimal point, the start column position, the start row position.

I've updated the library in my GitHub repository here

Please note that older sketches using the sendString() function will not work with the new library and will need to be altered.

Demo sketch to display Strings and float values on the OLED
1602 display  from Wide.HK. This uses a Lbrary that I've
put together containing some basic functions.
 The I2C Address is set to 0x3C in OLedI2C.cpp
 Phil Grant 2013

#include "Wire.h"
#include "OLedI2C.h"
float digit;

void setup()
  digit = 21.6;//This would normally be the float value returned from a temp sensor or other sensor
void loop()
  LCD.sendString("Temp",0,0);// now includes the cursor position data (col, row)
  LCD.sendFloat(digit,5,2,7,0);//Send the string to the display


Mortimer Neuss said...

Great Great Great!
This ight here is an excelent example of why I love the Arduino-Scene so much. I received my OLED-Display today and tried the Code WIDE-HK delivered on the auction site, but it was full of problems ( sendCommand(0xC0) -> So such command and eine } was even missing... ugh)

Have many thanks that you took the time and made a amazing lib for this Display. I'm fairly new to this field of technology and can only thank you so much. Thank you!

Gadjet said...

Thanks for the kind feedback, I'm glad someone is finding my efforts useful.

I had much the same experience with the display when I first bought it, I am used to always finding an existing library to use, but not this time so I thought I would try writing my own.

dnbblah said...

Hey there, thanks for the Library, works great for me, i even used a multiplexer to chain 4 dispays on one single I2C port and everything runs smoothly.

Well despite one tiny thing..:

I tried to get the display to actually using ROM A.

It looks like the command given seems not to change to ROM A.
I looked into the command table of the spec of the SSD131x_1.0 IC Spec.pdf and the command seems to be O.K. but my LEDs are actually running on ROM C.

To verify this i used the binary B10111110 which should be a sharp S - umlaut but instead its a Chinese character representing ROM C in the spec.

Any clues?


Gadjet said...

Sorry but I've not looked into using special characters at all so I'm not able to give you any answers I'm afraid.

dnbblah said...

thanks for your help and your response.
I guess i have to contact the seller and ask.
It definitely looks like that the ROM isn't been changed.



peterpeter said...

Great work! I just bought this display and I am very happy to see useable library. The one provided by manufacturer is really just to write hello world :) Thank you!

Q said...

Your library works great.

Is there a way to hook up 2 of these displays to 1 Arduino without adding more hardware.

Gadjet said...

On the face of it it looks like there are no jumpers to set the address, I don't know if it can be programaticaly changed.

I would use the Jeenode ports library ( to create a soft I2C port(s) and then you should be send data to more than one LCD even with the same address.

Carneiro said...


I received a OLED 2002 from but it doesn't show any characters and it gets crazy hot... Maybe this unit is broken?



Gadjet said...

I have to ask, have you got the supply connections the right way around?
What is the voltage your using?

Carneiro said...

No problem, logical question :-). I got it right, and I'm using 5V. The VCC pin is the most right, like the pictures from them.

If it were just not working I would imagime some software issue, but it gets crazy hot... I wrote them today.



Gadjet said...

Yes it does sound like it's faulty.

Hope you get a replacement OK

Carneiro said...

Thanks for the help. I've tried to power the Arduino with a wall supply, 9V, and Arduino goes off and even the power supply goes OFF! Very weird.

Does their shipping get quickly to US? Here it takes sooo long, but more then half to blame is our customs... :-(

Gadjet said...

What is the current rating of your wall adapter, it may be shutting down because there is too much current being drawn by the circuit or it is a faulty supply.

I don't know about the US I'm in the UK.

Carneiro said...

The supply is 1000 mA.

Gadjet said...

Should be fine, have you measured the supply voltage with a multimeter, sometimes the voltage from a wall wart can be a bit higher than stated when supplying low currents.

Carneiro said...

9.3V :-)

Gadjet said...

OK, last try, I assume it's an UNO, does it work when supplied from the PC USB port?

Carneiro said...

Yes, it works, but the OLED gets hot (and the Arduino LED is a little bit dimmed down). It really seems something is off with this OLED display.

Gadjet said...

Yes I would guess that the display is drawing too much current.

Get a replacement :-)

Mortimer Neuss said...

Hi again :D

Today I received the 20x04 Module:

Your current library only supports 16x02 as far as I see. Do you know what I need to change to make it useable for the 20x04 as well?

I tried poking around inside the class. I cloned it with a new name, rename all classes and found for example this line:

sendCommand(0x09); // **** Set 5-dot, 3 or 4 line(0x09), 1 or 2 line(0x08)

AS you can see, I already changed the value to 0x09 as I have 4 lines instead of 2. Was this correct?

Somehoew, it still does not work. I wrote:

LCD.sendString("Line 0",0,0);
LCD.sendString("Line 1",0,1);
LCD.sendString("Line 2",0,2);
LCD.sendString("Line 3",0,3);

and the Displays shows:

Any idea?


Gadjet said...

I didn't even know they did a 4 line....I'll have to get one.
I don't know how to modify the library to cope with 4 lines but I will look into it when I get a chance.


Gadjet said...

Just had a quick look in the cpp file, maybe there needs to be 2 more offsets in this code, maybe

void OLedI2C::cursPos(uint8_t col, uint8_t row)
int row_offsets[] = { 0x00, 0x40 };
sendCommand(0x80 | (col + row_offsets[row]));

Also the offsets may be different because it 20 characters wide ??

Mortimer Neuss said...

What are you doing here?
int row_offsets[] = { 0x00, 0x40 };

0x40 is 64 DEC, so I assume that every Char on the Display has 4 bits and the display has 16 chars, that why 16x4=64?

But even without the following fix, the module already gave me the full 20 char size:

I tried this:
int row_offsets[] = { 0x00, 0x40, 0x80, 0xC0 };

But still, line 3+4 are not accessed, online 1+2 are overwritten.
You said that the offset must also be changed cause now that the display has 20 chars. So I changed the offset from 0,64,128,192 (0x00, 0x40, 0x80, 0xC0) to a 0,80,160,240 (0x00, 0x50, 0xA0, 0xF0)

The result was this:

So I guess that is not the part I want to change. Somehow, even with only the two values for the offset, the full 20 chars on line 1+2 can be displayed. But I have no success to access line 3+4.

Do you remember the commented line i mentioned in the last post?
// **** Set 5-dot, 3 or 4 line(0x09), 1 or 2 line(0x08)

Why were you aware of 4 lines? Strange. I will keep my eye onte the comments for the next weeks/month. I like this library very much! :D


Mortimer Neuss said...

How did you figured out the commands by the way? I have a hard time finding a Datasheet or soemthing were its written down what command is needed where.

Nick said...

Hello, where can I download the library please?

Thank you

Gadjet said...

yes, use the link in the post to github. ;-)

Chakko said...

Hi Phil,
Thank you so much for sharing your library. I purchased a couple of 2002 character OLED displays (ER-OLEDM2002-1_Series) from East Rising Technology, and these displays use the US2066 controller, which appears to be similar to the SSD1311. Anyway, I modified your library code appropriately and was able to bring both to life, and was even able to run them in parallel on my Arduino Mega by using two running instances of your library.
Although I have been able to achieve all that I need to achieve by way of my autopilot displays for simulated aircraft in MS FSX, I do look forward to your adding more functions to the library.
I do have a question about the sendString function. It appears to me to work only with literal strings (i.e. actual strings enclosed in " " quotes.) I find that if I declare a String variable, sendString refuses to deal with it. Is my understanding correct?
Thanks and Regards,

Gadjet said...

Glad people are getting some use out of the library and modifying it to suit their needs.

To be honest I've not really done anything with it for ages, the sendstring function is defined to use a string and therefore expects a string. Have you tried using the variable without the quotes?


Chakko said...

Hi Phil,
Yes, I did try that, and it either threw up an error or resulted in incorrectly displayed digits. I needed to do this in order to control the display and location of leading zeroes, decimal points (and such), which is possible if you declare the numerical sequences as strings, but not as floats.
Anyway, as it stands, it's a small price to pay for the ability to get these displays working, because they are beautiful....the contrast is stunning! And your library is the only one I am aware of which will allow interfacing with Arduino without much modification. So thank you once again for your wonderful work, and for sharing it, and of course I have signed up at github to be notified of any revisions you make to the code.
Warm regards,

Chakko said...

Hello again Phil,

I decided I really needed to work with string variables as well, so I added the following function to my version of your library:

void OLedI2Cx3c::sendStringvar(String Var, uint8_t col, uint8_t row)
setCursor(col, row);
unsigned char i=0;
sendData(Var[i]); // *** Show Var to OLED

So far this has worked well, and the added functionality has given me fuller control over the display of leading zeroes, etc.


Chakko said...

Hello Phil,

Some of this discussion is in the context of my flight simulator displays, so do bear with me, but the issues are generally relevant.

The sendStringvar() function gives me the ability to display string variables such as Heading_set which contain numerical strings like 054 or 296. So I can now issue display commands such as: sendStringvar(Heading_set,6,1) which I could not do with sendString(). I could do this with sendFloat(), of course, but then I would lose the leading zeroes, which I would have to pad in with sendString("0",6,1), but then there was a problem of 'flickering zeroes'.

Another string variable I deal with, IASMach_set, might contain strings such as 345.00 (knots) or 000.78 (Mach) which need to be displayed as 345 and .78 respectively. This is beyond the capacity of sendFloat() to handle completely, and I also found that sendStringvar(), as defined, is incapable of displaying particular elements of a string variable. For instance, it will not accept IASMach_set[3] as an argument, so I could not write: sendStringvar(IASMach_set[3],10,1). (I could do this, however, with the LiquidCrystal libraries I use with my 4002 LCD's.)

So I have written one more function sendChar(), to deal with this:

void OLedI2Cx3c::sendChar(char Var, uint8_t col, uint8_t row)
setCursor(col, row);
sendData(Var); // *** Show Var to OLED

Now I can issue display commands such as: sendChar(IASMach_set[3],10,1). This gives me complete control over leading and trailing zeroes, decimal points, and so on.

With this I can say that I have all the functionality I need for my autopilot displays, and I hope this information is of use to someone else who is starting off with these OLED's.



Gadjet said...

that's brilliant, I had started to have a look into the code but I'm far from a code expert and I've been busy with other stuff I didn't get around to it.

Do you want me to add the function intomthe library? (Credited to you of course)

Chakko said...

Hi Phil,

I would be honoured if you added these functions to your library! (My full name is Chakko Kovoor)

In my own version I re-named your parent function sendString() to: sendStringlit() to reference its use with string literals only, and to differentiate it from the new function.

I thank you again for the marvellous contribution you have made in writing this library....I'd still be scratching my head and gazing at blank OLED's without it!



nucloid99 said...

There are 2 bugs in the init portion - after sendCommand(0x71.) you need to SENDATA(0x08) data, not command, and ditto for the 0x72 command. For the 4 line displays, the offsets are 0x00, 0x20, 0x40, 0x60 (in the set cursor function) -- this is good for either of the 3 char roms selected (in the init command example: sendCommand(0x72);
sendData(0x08); // set rom

nucloid99 said...

and to answer another question, to chose one of the 3 ROMS, the first init command (0x72) puts it into select rom, and your choices are 00 rom A, 04 rom B, and 08 for ROM C.


Chakko said...

Hi nucloid99,
This has already been discussed by Rafael Camacho at:
I believe you are correct, though I have:
sendData(0x01); // Set ROM A and 8 CGRAM
but I think Phil is yet to update the code in this respect.

nucloid99 said...

ok, since you say that, we should be more accurate. command 72 is followed by DATA byte which selects the character ROM and the CGROM and CGRAM. the data format is ro1 ro2 op1 op2 (as data bits 8,4,2,1). bits ro1 and ro2 select the ROM, bits op1 and op2, select the CGrom/ram. So if you keep it at CGROM 240 and CGRAM 08 (the lower 2 bits 0) , selecting ROMs A,B, or C.
it is sending byte 00 for A, 40 for B, and 80 for C. - FOR CGROM 240 and CGRAM 8.
sending data 01 - gives you ROM A , CGROM 248 and CGRAM 8, 02 is ROM A , CGROM 250 , CGRAM 6 and 03 is ROM A and CGROM 256 and CGRAM 0 -- just trying to keep it simple -- 00, 40, 80 select the char ROM, add 01, 02 or 03 to the value to select a CGROM and CGRAM at the same time (leaving it 0 works ) adding 01 you get CGROM , CGRAM 248, 8, -- 02: 250,6, and 03 - 256,0 . so whatever floats your boat.
The reason I posted was that there were a several comments about not being able to switch ROMS - that is done by sending DATA 00, 04, or 08 for ROM A, B and C -- if you add the lower 2 bits of 00,01,02, or 03 you also select the corresponding CGROM and CGRAM as well. i just left the bits as 00.. but whatever you like -- it is on page 40 of the spec.

Gadjet said...

Thanks for your input, it seems that you have a much better understanding of this display than me, I basically copied the init code from the HK example and made a library.
I have to admit that I struggle to fully understand the LCD spec, maybe I'm just getting old!
Would it be possible for you to contribute to the github code by branching etc. some corrected code so others may benefit.
My OLED display is "in-situ" and very difficult for me to start trying code.
I'm sure people reading the blog would be grateful for any help, I know I would.

Anonymous said...


to select the ROMS I figured out the following:

sending data 0x00 = 0b0000 for A, 0x04 = 0b0100 for B, and 0x08 = 0b1000 for C.
ROM C ist default

Check your bytes...:)
Greetings DrBockel

Anonymous said...

@nucloid99, @Gadjet,

Went through the SSD1311 datasheet and stripped the initialisation to the bare minimum. A lot of registers are already set correctly by power-on default, so you don't need to do that again.
Here is the init sequence:

void SSD1311_init()
delay(100); // let SSD1311 finish internal POR
sendCommand(0x2A); // Function Set, set RE=1
sendCommand(0x08); // Extended Function Set, 5-dot, disable cursor-invert, 2-line mode
sendCommand(0x72); // Function Selection B
sendData(0x03); // Set ROM A [0x03, ROM B 0x07, ROM C 0x0B]
// if you want to set the brightness to max, uncomment the following 4 lines
// sendCommand(0x79); // set SD=1, enable OLED Command Set
// sendCommand(0x81); // Set Contrast Control
// sendCommand(0xFF); // default is 0x7F
// sendCommand(0x78); // set SD=0, disable OLED Command Set
sendCommand(0x28); // Function Set, set RE=0
sendCommand(0x01); // Clear Display and set DDRAM location 00h
sendCommand(0x0C); // turn display ON, cursor OFF, blink OFF


Gadjet said...

Thanks for that Paul.