I recently came across a tiny OLED display which I also used for another project. This time I thought a tiny display can be driven by an [AT]Tiny processor :).

The vision is - "create a tiny gaming machine"

Well the first step is taken. At least something is happening on the display. Feel free to suggest a game idea.

Parts we need

  • ATTiny85 break out board - CoPiino Connectable BrainZ from ebay ($6)
  • OLED Display with SSD1306 driver from ebay ($5)
  • AVR Programmer USBasp from ebay ($4)
  • 5V/3.3V regulated voltage source
  • some jumper wires
  • Arduino IDE

Attention: The display module I used had an operation range from +3.3V to +5V. So I could easily connect +5V. You need to carefully check if your display also supports +5V otherwise use a regulated +3.3V power source !!


  • uploaded additional target project => demo for font and icons
  • uploaded some pictures for font and icons

Step 1: Soldering the Board

The CoPiino Connectable BrainZ comes as soldering kit. So it needs some soldering. All parts are through-hole and can be soldered old fashioned with soldering iron.

Scope of supply:

  • PCB 21x28mm with M3 fixing hole
  • 1x ATTiny85-20PU
  • 1x LED 3mm yellow
  • 1x Resistor 1k
  • 3x Resistors 4.7k
  • 2x Capacitors 100nF
  • 1x pin header angled 1x4
  • 1x pin header angled 1x5
  • 1x Straight header
  • 2x3 (AVR ISP)
  • 1x Receptacle angled 1x4

It took me 20mins to solder all parts.

Step 2: Programming the CoPiino Connectable BrainZ

This step is pretty forward. The required source code is attached to this step. All files need be extracted.

Included files are

  • ATTiny_OLED_Bouncing_Ball.ino
  • SSD1306_minimal.cpp
  • SSD1306_minimal.h
  • TinyWireM.cpp
  • TinyWireM.h
  • USI_TWI_Master.cpp
  • USI_TWI_Master.h

1. With the Arduino IDE we open the ATTiny_OLED_Bouncing_Ball.ino

2. We need to use the menu "Sketch" - "Add File ... " and add all other files one by one

3. Connect the CoPiino Connectable BrainZ to the USBasp (see notes below)

4. Connect USBasp preferably to a USB hub

5. Arduino IDE: Compile and Upload

6. Check for completed Upload

7. Disconnect USB

8. done


For connecting the USBasp to the CoPiino Connectable BrainZ we apply these pin connections


Pin 9 to 1 [MISO]

Pin 2 to 2 [VCC]

Pin 7 to 3 [SCK]

Pin 1 to 4 [MOSI]

Pin 5 to 5 [RST]

Pin 2 to 6 [GND]

Step 3: Connect and Run

The display will be connected through I2C / TWI which are the signales SDA/SCL. Additionally we draw VCC and GND from the CoPiino Connectable BrainZ to the display. So all toghether we have 4 single cables between display and BrainZ.

Attention: The display module I used had an operation range from +3.3V to +5V. So I could easily connect +5V. You need to carefully check if your display also supports +5V otherwise use a regulated +3.3V power source !!

We then use our 5V/3.3V regulated power source and inject GND and VCC into the appropriate pins at the BrainZ module.

You will be enlightened by the nice moving ball in a grid on the display.


Now its time to make the next step. Any gaming idea that can be implemented?

<p>Update: I discover there is a memory leak (or something else) in the library or code that freeze the attiny85 after approx one hour of running the code. Anyone else experienced this?</p>
This can also be some electrics communication issue and lockup :)<br>
<p>Thank you for the nice and easy to understand code. I ordered some <br>displays (white and blue) to use on a DigiSpark and a DigiSpark clone. <br>It seems to be a little different and you need to add some pull up <br>resistors (the 4.7K ones) to get it to work. I solder these two <br>resistors onto the display board (to the data header pins, between +5V <br>and the data header pins) directly. On the DigiSpark you must use P0 and<br> P2 as I2C data lines, P0=SDA and P2=SLC/SLK. </p><p>To speed up screen updates (processor speed), to get the full speed potentional out of it, I use this code:</p><p>void setMaxClockSpeed()<br>{<br> // Examine Page 33<br> CLKPR = 0x80; // Setup CLKPCE to be receptive<br> CLKPR = 0x00; // No scalar<br><br> // Maximum clock speeds!<br> PLLCSR = _BV(PLLE) | _BV( PCKE );<br> OSCCAL = 0xff;<br>} </p><p>You can call this at the setup routine and the animation is twice the speed! Pretty amazing stuff.</p>
<p>Hi. Thanks for excellent tutorial. I'd already got a simple 'blink' sketch running on my ATtiny85. When I connected the OLED and tried your code it all worked perfectly first try. Saved me hours struggling how to configure the TinyWireM library to run at 16MHz and then figuring out how to use it with the SSD1306. :)</p>
Thank that's nice to hear!<br><br>Let me know what cool things you are doing with it.<br><br>
<p>Hi - great tutorial. I got it working.</p><p>Now I'm struggling to get images to display correctly. Can you describe your workflow for making the byte arrays? Whenever I use http://manytools.org/hacker-tools/image-to-byte-array/ to make my own I always get a random assortment of pixels in the correct size. I have figured out that the width is the width in pixels and the height is the height in pixels/8.</p>
Hi Alex,<br>Yeah that's right. It can be tricky to display images. It usually something with byte order and endianess.<br><br>The ssd1306 is configured that way<br>(1) As far as I remember the first byte starts top left corner. <br>(2) the display reads bytes from left to right<br>(3) the display reads lines from top to bottom <br><br>So basically we need a byte stream in that order - that's it<br><br>(4) I am unsure about byte endianess - I think it was byte0 - bit7 that sits on pixel (0,0) - so this should be LSB first.<br><br>Hope that helps at least a little :)<br><br>Let me know how things are and if a deeper look from my side can be of some help here.<br>
<p>I've tried tons of different image to hex array converters, but none of them seem to function. All of them display a seemingly random assortment of pixels, except for solid white or solid black images, which makes sense. I've tried both the methods listed here: https://learn.adafruit.com/mini-thermal-receipt-printer/bitmap-printing , as well as a few online converters. All display the pixels in an incorrect order, which leads me to believe that the order they're encoded is not as you listed. Can you please share what tool you used to convert the images to hex arrays?</p>
<p>Aha! I've finally gotten it! Every single tutorial and page I've ever seen says the image orientation needs to be horizontal for the OLED to display it correctly. Out of desperation I tried vertical orientation ONCE and it appears to be working.</p>
<p>that's great that you got it working. I did use some Linux tool, but remember to have changed the bit order from MSB to LSB.</p><p>If you can,... send some pictures - would be great!!</p>
I'did it! xD AtTiny Micro Wheather Station! Take a look:
<p>Can u send me the code you used? with librabry?</p><p>the code below gives me the error.</p>
This works for me :D<br><br>#include // I2C Master lib for ATTinys which use USI - comment this out to use with standard arduinos<br>#include // needed to up clock to 16 MHz on 5v Trinket<br>#include <br>dht DHT;<br>const byte DHT22_Pin = 1;<br>const int analogInPin = 3;<br>#include &quot;SSD1306_minimal.h&quot;<br>#include <br>#define DEG &quot;\xa7&quot; &quot;C&quot;<br><br>SSD1306_Mini oled;<br><br><br>char strHum[5];<br>char strTemp[5];<br>char strSensorValue[5];<br><br>// Struct for sending measured data<br>/*<br>struct Data {<br> uint16_t temp; // Temperature value<br> uint16_t hum; // Humidity value<br> int status; // DHT22 module status<br>} data;<br><br>*/<br>void setup(){<br> if (F_CPU == 16000000) clock_prescale_set(clock_div_1); // 5V Trinket: run at 16 MHz<br> TinyWireM.begin(); // initialize I2C lib - comment this out to use with standard arduinos<br> oled.init(0x3c);<br> oled.clear();<br>}<br><br><br>void loop(){<br> /*<br> sensorValue = analogRead(analogInPin);<br> data.status = DHT.read22(DHT22_Pin);<br> data.hum = (int)DHT.temperature;<br> data.temp = (int)DHT.humidity;<br> */<br><br>int chk = DHT.read22(DHT22_Pin);<br>int h=DHT.humidity;<br>int t=DHT.temperature;<br>int sensorValue = analogRead(analogInPin);<br><br><br> oled.startScreen();<br> oled.cursorTo(0,0);<br> oled.printString( &quot;Luftfeuchte: &quot;); <br><br> oled.startScreen();<br> oled.cursorTo(86,0);<br> oled.printString( itoa(h, strHum, 10)); <br><br> oled.startScreen();<br> oled.cursorTo(0,18);<br> oled.printString(&quot;Temperatur: &quot;); <br> <br><br> oled.startScreen();<br> oled.cursorTo(100,18);<br> oled.printString( itoa(t, strTemp, 10));<br><br> oled.startScreen();<br> oled.cursorTo(0,36);<br> oled.printString(&quot;Licht: &quot;); <br><br> oled.startScreen();<br> oled.cursorTo(51,36);<br> oled.printString( itoa(sensorValue, strSensorValue, 10));<br><br> delay(500);<br>}<br>
Cool thanks!
<p>you are welcome.</p>
<p>Great! Congratulations!</p>
<p>@ChristianK35 that's great you got it running. Perhaps you want to add picture of your solution? - that would be awesome!</p>
<p>that is nice! Can you add your code?</p>
<p>Off course!</p><blockquote>#include &quot;font6x8.h&quot;<br>#include &quot;font8x16.h&quot;<br>#include &quot;ssd1306xled.h&quot;<br>#include &quot;ssd1306xled8x16.h&quot;<br>#include &lt;stdlib.h&gt;<br>#include &lt;dht.h&gt;<br>#define DHT11_PIN 4<br>dht DHT;<br>// ============================================================================<br>float h=0;<br>float t=0;<br>char buffH[6];<br>char buffT[6];<br><br>void setup()<br>{<br> _delay_ms(40);<br> SSD1306.ssd1306_init();<br>}<br>//////////////////////////FUN&Ccedil;&Otilde;ES DO OLED 0,96&quot;//////////////////////<br>void texto(char* s) {SSD1306.ssd1306_string_font6x8(s);}<br>void textoG(int pos_x, int pos_y, char* sG) {SSD1306.ssd1306_char_f8x16(pos_x, pos_y, sG);}<br>void pos(uint8_t x, uint8_t y){SSD1306.ssd1306_setpos(x, y);}<br>void limpaTela(){uint8_t p = 0xff; for (uint8_t i = 0; i &lt; 4; i++){p = (p &gt;&gt; i); SSD1306.ssd1306_fillscreen(~p); _delay_ms(100);}SSD1306.ssd1306_fillscreen(0x00);}<br>/////////////////////////////////////////////////////////////////////<br><br>void loop() {<br>///////////////FUN&Ccedil;&Otilde;ES DHT-11///////////////<br> int chk = DHT.read11(DHT11_PIN);<br> h=DHT.humidity;<br> t=DHT.temperature;<br> dtostrf(h, 4, 2, buffH);<br> dtostrf(t, 4, 2, buffT);<br>////////////////////////////////////////////<br> limpaTela();<br> pos(0, 3);<br> texto(&quot;Humidade(%)&quot;);<br> pos(0, 5);<br> texto(&quot;Temperatura(C)&quot;);<br> pos(0, 7);<br> texto(&quot; Jesus is good!&quot;);<br> textoG(0,0,&quot;Raphaelangelo S2&quot;);<br> textoG(87,2,buffH);<br> textoG(87,4,buffT);<br> _delay_ms(3000);<br>}</blockquote><p>Feel free to make an Instructable out of it, if you like.. =)</p><p>Let me know if you lack any library, but I think you can have it all here: </p><p>http://tinusaur.org/projects/ssd1306xled/</p>
<p>I have opened your code and have the tinusaur library but when I compile it gives me &quot;error: 'SSD1306' was not declared in this scope&quot; Anyone have any idea why?</p><p>In case it makes any difference, I'm using an adafruit trinket 3V and arduino ide 1.6.6</p>
<p>When I use import library, it brings in the<br> things after include enclosed in brackets instead of quotes. Still <br>same error. I have deleted any reference to the temp sensor, as I only <br>need to display text. I am sorry, not very good at programming, I rely <br>on finding code I can use and then modifying it to work for me. My code<br> looks like this:</p><p>#include &lt;font6x8.h&gt;<br>#include &lt;font8x16.h&gt;<br>#include &lt;ssd1306xled.h&gt;<br>#include &lt;ssd1306xled8x16.h&gt;<br>#include &lt;stdlib.h&gt;<br><br>// ============================================================================<br>float h=0;<br>float t=0;<br>char buffH[6];<br>char buffT[6];<br><br>void setup()<br>{<br>_delay_ms(40);<br>SSD1306.ssd1306_init();<br>}</p><p>//////////////////////////FUN&Ccedil;&Otilde;ES DO OLED 0,96&quot;//////////////////////</p><p>void texto(char* s) {SSD1306.ssd1306_string_font6x8(s);}<br>void textoG(int pos_x, int pos_y, char* sG) {SSD1306.ssd1306_char_f8x16(pos_x, pos_y, sG);}<br>void pos(uint8_t x, uint8_t y){SSD1306.ssd1306_setpos(x, y);}<br>void<br> limpaTela(){uint8_t p = 0xff; for (uint8_t i = 0; i &lt; 4; i++){p = (p<br> &gt;&gt; i); SSD1306.ssd1306_fillscreen(~p); <br>_delay_ms(100);}SSD1306.ssd1306_fillscreen(0x00);}<br>/////////////////////////////////////////////////////////////////////<br><br>void loop() {<br>///////////////FUN&Ccedil;&Otilde;ES DHT-11///////////////<br>h=23;<br>t=23;<br>dtostrf(h, 4, 2, buffH);<br>dtostrf(t, 4, 2, buffT);<br>////////////////////////////////////////////<br>limpaTela();<br>pos(0, 3);<br>texto(&quot;Humidade(%)&quot;);<br>pos(0, 5);<br>texto(&quot;Temperatura(C)&quot;);<br>pos(0, 7);<br>texto(&quot; Jesus is good!&quot;);<br>textoG(0,0,&quot;Raphaelangelo S2&quot;);<br>textoG(87,2,buffH);<br>textoG(87,4,buffT);<br>_delay_ms(3000);<br>}</p><p>Compiling that, i get many of these errors:</p><p>ATTiny85_OLED_weather_demo:17: error: 'SSD1306' was not declared in this scope<br><br> SSD1306.ssd1306_init();</p>
<p>It's actually hard if not all parts of your code can be seen. Could you zip the whole project and send a download link. Then I will have a look your code. Hopefully we will beat the bugs ;)</p>
<p>Thank you for your help. Here is what I have done in my troubleshooting: I was originally using Arduino IDE 1.6.6 on Windows 10. I went and tried this on an old computer (Ive run into problems with new ide versions before) with Windows 7 and Arduino IDE 1.6.5 and then got different errors! </p><p>The errors were:</p><p>&quot;</p><p>num2str.c: In function 'usint2decascii':<br>num2str.c:32: error: 'for' loop initial declarations are only allowed in C99 mode<br> for (uint8_t pos = 0; pos &lt; 5; pos++) // &quot;pos&quot; is index in array, so should be of type int.<br> ^<br>num2str.c:32:2: note: use option -std=c99 or -std=gnu99 to compile your code<br>'for' loop initial declarations are only allowed in C99 mode</p><p>&quot;</p><p>When I researched those errors, I found someone had said the fix was to rename the .c files to .cpp. After doing that, I am back to the &quot;Error: 'SSD1306' was not declared in this scope&quot;</p><p>Here is a link to a .rar of my files.</p><p><a href="https://www.dropbox.com/s/jaxj04g5sy6i5js/ATTiny85_OLED_weather_demo.rar?dl=0" rel="nofollow">https://www.dropbox.com/s/jaxj04g5sy6i5js/ATTiny85...</a></p>
<p>1) You did use &quot;_delay_ms(3000);&quot; also you should use &quot;delay(3000)&quot;</p><p>2) You have to decide if you want to use &quot;SSD1306_minimal&quot; or &quot;SSD1306xlded.h&quot; - you mixed the code.</p><p>There is a fixed version in </p><p><a href="https://www.dropbox.com/s/j6at2evgjqglsnz/ATTiny85_OLED_weather_demo%20v1.0.zip?dl=0">https://www.dropbox.com/s/j6at2evgjqglsnz/ATTiny85...</a></p>
<p>There's a little difference when using libraries:</p><p>1) If the lib is on the same folder of the sketch, then you should use 'quotes';</p><p>2) If the lib is already imported to Arduino IDE, the you should use &lt;&gt;.</p><p>Maybe your arduino is not recognizing the libs because of these slight differences...</p>
<p>Is the trinket equipped with same processor atmega85?</p>
<p>Yes, it uses an attiny85 and has usb on it. Pretty awesome little device. I'm trying to make a wearable with one.</p><p>https://www.adafruit.com/products/1500</p>
<p>Did you remember to import all the libraries mentioned in the &quot;#include&quot; procedures? </p><p>&quot;error: 'SSD1306' was not declared in this scope&quot; Possibly means that you have not done so..</p><p>Hope it helps... =)</p>
<p>Thats great, thank you -- You are the man!</p>
<p>Made it Thank you!<br><br></p>
Thats great - congratulations. <br>Thanks for sharing.<br>
<p>Hi!! i am trying to get the wheaterstation working.</p><p>This is my code i adapt it to my needs..</p><p><a href="http://cloudkemi.at/owncloud/index.php/s/GO6BwICL6NXuQh6" rel="nofollow">http://cloudkemi.at/owncloud/index.php/s/GO6BwICL6...</a></p><p><br>FINAL_OLED.ino: In function 'void loop()':<br>FINAL_OLED.ino:58:23: error: no matching function for call to 'SSD1306_Mini::printString(float&amp;)'<br>FINAL_OLED.ino:58:23: note: candidate is:<br>In file included from FINAL_OLED.ino:7:0:<br>C:\Users\kemi\Documents\Arduino\libraries\ATTiny85_OLED_weather_demo/SSD1306_minimal.h:130:10: note: void SSD1306_Mini::printString(char*)<br> void printString( char * pText );<br> ^<br>C:\Users\kemi\Documents\Arduino\libraries\ATTiny85_OLED_weather_demo/SSD1306_minimal.h:130:10: note: no known conversion for argument 1 from 'float' to 'char*'<br>no matching function for call to 'SSD1306_Mini::printString(float&amp;)'</p>
<p>Hi!</p><p>This is great project!</p><p>I'm just starting on Arduino and I wanted to do what Raphango did but just simple one.</p><p>My goal is AtTiny85, some display, temp sensor and 3.7 battery.</p><p>I don't know how if the battery can take all those parts on.</p><p>I also thought about adding a solar panel so I don't need to charge it.</p><p>Can you help me with it?</p><p>Thanks!</p>
<p>Great idea. Lets split your project into parts</p><p>1. select parts</p><p>2. connect the wires</p><p>3. program your device</p><p>now how about (1) the parts?</p><p>Parts we need<br></p><ul><li>ATTiny85 break out board - CoPiino Connectable BrainZ from <a href="http://search.ebay.com/copiino-brainz">ebay</a> ($6) <li>OLED Display with SSD1306 driver from <a href="http://search.ebay.com/ssd1306-oled-128-64-IIC">ebay</a> ($5) <li>AVR Programmer USBasp from <a href="http://search.ebay.com/usbasp-avr-programmer">ebay</a> ($4) <li>5V/3.3V regulated voltage source <li>Temperature Sensor DHT11<li>some jumper wires <li>Arduino IDE</ul><p>do you have all parts at hand?</p>
<p>Thank you for your answer!</p><p>1. I've ordered ATTiny85 from ebay and a few breadboards.<br>2. I still don't have the display, I wanted to know if it's possible first, before I order the display.<br>3. I'll use Arduino Uno as ISP for programming the ATTiny85 (is that good?)<br>4. Should not have problem with 5V but don't know where to get 3.3v regulated (I thought about the tiny LiPo 3.7v, don't know if it's good for this project)<br>5. I think I'll use the LM35 temperature sensor, no need for other measurements right now.<br>6. Jumper wires are on the way from ebay along with the ATTiny85<br>7. Already installed.</p>
<p>Nice, it works using the very basics (5volt, ATtiny85 and the screen)! However I did have to burn using ATtiny85 (internal 1 MHz clock) as it didn't work using 8 Mhz.</p>
<p>Hi bASEL, Thank you for following the instructions. Hope that this was fun? :)<br>The ATTiny85 without oscillator comes with 1MHz. We can increase performance with setting the fuse bits and let it run on 8MHz. <br></p>
<p>Great! It worked just perfect for me, out of the box, like you said.</p><p>Congrats!</p><p>Now that I've managed to make it work, i was wondering if I could use it to display text messages. Actually, I'd like to use it as a Micro Weather Station, getting data from the DHT-11 and displaying it on the OLED. I've managed to do it with my Arduino UNO, using U8GLib, but not with the Attiny85..... (next pics)</p>
<p>@raphango : good job!</p><p>I also see a good option to display the sensor data. This should be fun. The tricky part here is that &quot;my&quot; library does not use any frambuffer, because the ATiny has not sufficient RAM for that. It is still possible to run the display -- you see. We need to include the fonts in my tiny lib then it will be able to display the sensor data easily.</p>
<p>Thanks! I found this lib here that can display text: </p><p><a href="http://tinusaur.org/projects/ssd1306xled/" rel="nofollow">http://tinusaur.org/projects/ssd1306xled/</a></p><p>regards!</p>
<p>I just uploaded a modified version of my SSD1306_minimal lib together with a small weather demo.</p>
<p>So the ATTiny85 is also able to display text :)</p>
<p>also thank you for the pics :)</p>
<p>1) You can make a small basic computer !</p><p>2) pins SDA SCL on the board is pins 5 , 7 on the attiny85 ?</p>
<p>Thanks.</p><p>1) I think there might be smaller boards on market. However this one is designed to be able to solder very easily. </p><p>2) The ATTiny85 has some hardware pins for I2C, so I used them of course :).</p><p>It is also possible to run these boards in master or slave mode. So one master can address multiple of these slaves. That makes them a nice sensing network. </p>
<p>btw. These boards come with soldering instructions and schematic.</p>
<p>Are there any good online source for learning OLED programming?</p>
<p>OLED displays usually behave like other graphic displays. So looking for standard displays and how to program them might be a great starter. Although I can not recommend a specific one. I usually use the display drivers data sheet. In this case the driver chip is SSD1306. </p>
<p>in case you need additional help - contact me - any time.</p>
<p>Ok, I made it work on a DigiSpark ATTiny85 module. Only issue was part of screen refresh would move screen a bit off center. But was one of my wires. Here's a video of it working attached to Anker Phone charger for power.. Sorry not a very good webcam. So also did one with phone.</p>

About This Instructable




Bio: Electronics is great! http://CoPiino.cc
More by tswaehn:101hero $99 3D Printer - an Upgrade Story 
Add instructable to: