├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── Adafruit_SSD1306.cpp ├── Adafruit_SSD1306.h ├── README.md ├── README.txt ├── examples ├── ssd1306_128x32_i2c │ └── ssd1306_128x32_i2c.ino ├── ssd1306_128x32_spi │ └── ssd1306_128x32_spi.ino ├── ssd1306_128x64_i2c │ └── ssd1306_128x64_i2c.ino └── ssd1306_128x64_spi │ └── ssd1306_128x64_spi.ino ├── library.properties └── license.txt /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /Adafruit_SSD1306.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | These displays use SPI to communicate, 4 or 5 pins are required to 8 | interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen below must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #ifdef __AVR__ 20 | #include 21 | #elif defined(ESP8266) 22 | #include 23 | #else 24 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 25 | #endif 26 | 27 | #if !defined(__ARM_ARCH) && !defined(ENERGIA) && !defined(ESP8266) 28 | #include 29 | #endif 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include "Adafruit_GFX.h" 36 | #include "Adafruit_SSD1306.h" 37 | 38 | // the memory buffer for the LCD 39 | 40 | static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 45 | 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 52 | 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 53 | #if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 96*16) 54 | 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 55 | 0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8, 57 | 0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | #if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 64*32) // added for 64x32 display option 59 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 60 | 0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01, 62 | 0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF, 63 | 0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00, 64 | 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF, 65 | 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 66 | 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F, 68 | 0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 69 | 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03, 70 | 0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 71 | 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00, 72 | 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 73 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, 74 | 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | #if (SSD1306_LCDHEIGHT == 64) 76 | 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, 77 | 0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF, 78 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F, 85 | 0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 86 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 87 | 0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E, 88 | 0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC, 89 | 0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06, 90 | 0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8, 91 | 0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80, 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03, 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 95 | 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C, 96 | 0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 97 | 0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 98 | 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07, 99 | 0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 108 | #endif 109 | #endif 110 | #endif 111 | }; 112 | 113 | #define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; } 114 | 115 | // the most basic function, set a single pixel 116 | void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { 117 | if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) 118 | return; 119 | 120 | // check rotation, move pixel around if necessary 121 | switch (getRotation()) { 122 | case 1: 123 | ssd1306_swap(x, y); 124 | x = WIDTH - x - 1; 125 | break; 126 | case 2: 127 | x = WIDTH - x - 1; 128 | y = HEIGHT - y - 1; 129 | break; 130 | case 3: 131 | ssd1306_swap(x, y); 132 | y = HEIGHT - y - 1; 133 | break; 134 | } 135 | 136 | // x is which column 137 | switch (color) 138 | { 139 | case WHITE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break; 140 | case BLACK: buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break; 141 | case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break; 142 | } 143 | 144 | } 145 | 146 | Adafruit_SSD1306::Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { 147 | cs = CS; 148 | rst = RST; 149 | dc = DC; 150 | sclk = SCLK; 151 | sid = SID; 152 | hwSPI = false; 153 | } 154 | 155 | // constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset 156 | Adafruit_SSD1306::Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { 157 | dc = DC; 158 | rst = RST; 159 | cs = CS; 160 | hwSPI = true; 161 | } 162 | 163 | // initializer for I2C - we only indicate the reset pin! 164 | Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) : 165 | Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { 166 | sclk = dc = cs = sid = -1; 167 | rst = reset; 168 | } 169 | 170 | 171 | void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { 172 | _vccstate = vccstate; 173 | _i2caddr = i2caddr; 174 | 175 | // set pin directions 176 | if (sid != -1){ 177 | pinMode(dc, OUTPUT); 178 | pinMode(cs, OUTPUT); 179 | #ifdef HAVE_PORTREG 180 | csport = portOutputRegister(digitalPinToPort(cs)); 181 | cspinmask = digitalPinToBitMask(cs); 182 | dcport = portOutputRegister(digitalPinToPort(dc)); 183 | dcpinmask = digitalPinToBitMask(dc); 184 | #endif 185 | if (!hwSPI){ 186 | // set pins for software-SPI 187 | pinMode(sid, OUTPUT); 188 | pinMode(sclk, OUTPUT); 189 | #ifdef HAVE_PORTREG 190 | clkport = portOutputRegister(digitalPinToPort(sclk)); 191 | clkpinmask = digitalPinToBitMask(sclk); 192 | mosiport = portOutputRegister(digitalPinToPort(sid)); 193 | mosipinmask = digitalPinToBitMask(sid); 194 | #endif 195 | } 196 | if (hwSPI){ 197 | SPI.begin(); 198 | #ifdef SPI_HAS_TRANSACTION 199 | SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); 200 | #else 201 | SPI.setClockDivider (4); 202 | #endif 203 | } 204 | } 205 | else 206 | { 207 | // I2C Init 208 | Wire.begin(); 209 | #ifdef __SAM3X8E__ 210 | // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL) 211 | TWI1->TWI_CWGR = 0; 212 | TWI1->TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101; 213 | #elif ARDUINO >= 157 // Send data MUCH faster to display 214 | Wire.setClock(400000UL); // Set I2C frequency to 400kHz 215 | #endif 216 | } 217 | if ((reset) && (rst >= 0)) { 218 | // Setup reset pin direction (used by both SPI and I2C) 219 | pinMode(rst, OUTPUT); 220 | digitalWrite(rst, HIGH); 221 | // VDD (3.3V) goes high at start, lets just chill for a ms 222 | delay(1); 223 | // bring reset low 224 | digitalWrite(rst, LOW); 225 | // wait 10ms 226 | delay(10); 227 | // bring out of reset 228 | digitalWrite(rst, HIGH); 229 | // turn on VCC (9V?) 230 | } 231 | 232 | // Init sequence 233 | ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE 234 | ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 235 | ssd1306_command(0x80); // the suggested ratio 0x80 236 | 237 | ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 238 | ssd1306_command(SSD1306_LCDHEIGHT - 1); 239 | 240 | ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 241 | ssd1306_command(0x0); // no offset 242 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 243 | ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D 244 | if (vccstate == SSD1306_EXTERNALVCC) 245 | { ssd1306_command(0x10); } 246 | else 247 | { ssd1306_command(0x14); } 248 | ssd1306_command(SSD1306_MEMORYMODE); // 0x20 249 | ssd1306_command(0x00); // 0x0 act like ks0108 250 | ssd1306_command(SSD1306_SEGREMAP | 0x1); 251 | ssd1306_command(SSD1306_COMSCANDEC); 252 | 253 | #if defined SSD1306_128_32 254 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 255 | ssd1306_command(0x02); 256 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 257 | ssd1306_command(0x8F); 258 | 259 | #elif defined SSD1306_128_64 260 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 261 | ssd1306_command(0x12); 262 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 263 | if (vccstate == SSD1306_EXTERNALVCC) 264 | { ssd1306_command(0x9F); } 265 | else 266 | { ssd1306_command(0xCF); } 267 | 268 | #elif defined SSD1306_96_16 269 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 270 | ssd1306_command(0x2); //ada x12 271 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 272 | if (vccstate == SSD1306_EXTERNALVCC) 273 | { ssd1306_command(0x10); } 274 | else 275 | { ssd1306_command(0xAF); } 276 | #elif defined SSD1306_64_32 277 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 278 | ssd1306_command(0x12); 279 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 280 | ssd1306_command(0xcf); 281 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 282 | if (vccstate == SSD1306_EXTERNALVCC) 283 | { ssd1306_command(0x22); } 284 | else 285 | { ssd1306_command(0xF1); } 286 | #endif 287 | 288 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 289 | if (vccstate == SSD1306_EXTERNALVCC) 290 | { ssd1306_command(0x22); } 291 | else 292 | { ssd1306_command(0xF1); } 293 | ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB 294 | ssd1306_command(0x40); 295 | ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 296 | ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 297 | 298 | ssd1306_command(SSD1306_DEACTIVATE_SCROLL); 299 | 300 | ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel 301 | } 302 | 303 | 304 | void Adafruit_SSD1306::invertDisplay(uint8_t i) { 305 | if (i) { 306 | ssd1306_command(SSD1306_INVERTDISPLAY); 307 | } else { 308 | ssd1306_command(SSD1306_NORMALDISPLAY); 309 | } 310 | } 311 | 312 | void Adafruit_SSD1306::ssd1306_command(uint8_t c) { 313 | if (sid != -1) 314 | { 315 | // SPI 316 | #ifdef HAVE_PORTREG 317 | *csport |= cspinmask; 318 | *dcport &= ~dcpinmask; 319 | *csport &= ~cspinmask; 320 | #else 321 | digitalWrite(cs, HIGH); 322 | digitalWrite(dc, LOW); 323 | digitalWrite(cs, LOW); 324 | #endif 325 | fastSPIwrite(c); 326 | #ifdef HAVE_PORTREG 327 | *csport |= cspinmask; 328 | #else 329 | digitalWrite(cs, HIGH); 330 | #endif 331 | } 332 | else 333 | { 334 | // I2C 335 | uint8_t control = 0x00; // Co = 0, D/C = 0 336 | Wire.beginTransmission(_i2caddr); 337 | Wire.write(control); 338 | Wire.write(c); 339 | Wire.endTransmission(); 340 | } 341 | } 342 | 343 | // startscrollright 344 | // Activate a right handed scroll for rows start through stop 345 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 346 | // display.scrollright(0x00, 0x0F) 347 | void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop){ 348 | ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL); 349 | ssd1306_command(0X00); 350 | ssd1306_command(start); 351 | ssd1306_command(0X00); 352 | ssd1306_command(stop); 353 | ssd1306_command(0X00); 354 | ssd1306_command(0XFF); 355 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 356 | } 357 | 358 | // startscrollleft 359 | // Activate a right handed scroll for rows start through stop 360 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 361 | // display.scrollright(0x00, 0x0F) 362 | void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop){ 363 | ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL); 364 | ssd1306_command(0X00); 365 | ssd1306_command(start); 366 | ssd1306_command(0X00); 367 | ssd1306_command(stop); 368 | ssd1306_command(0X00); 369 | ssd1306_command(0XFF); 370 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 371 | } 372 | 373 | // startscrolldiagright 374 | // Activate a diagonal scroll for rows start through stop 375 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 376 | // display.scrollright(0x00, 0x0F) 377 | void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ 378 | ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); 379 | ssd1306_command(0X00); 380 | ssd1306_command(SSD1306_LCDHEIGHT); 381 | ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); 382 | ssd1306_command(0X00); 383 | ssd1306_command(start); 384 | ssd1306_command(0X00); 385 | ssd1306_command(stop); 386 | ssd1306_command(0X01); 387 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 388 | } 389 | 390 | // startscrolldiagleft 391 | // Activate a diagonal scroll for rows start through stop 392 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 393 | // display.scrollright(0x00, 0x0F) 394 | void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ 395 | ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); 396 | ssd1306_command(0X00); 397 | ssd1306_command(SSD1306_LCDHEIGHT); 398 | ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); 399 | ssd1306_command(0X00); 400 | ssd1306_command(start); 401 | ssd1306_command(0X00); 402 | ssd1306_command(stop); 403 | ssd1306_command(0X01); 404 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 405 | } 406 | 407 | void Adafruit_SSD1306::stopscroll(void){ 408 | ssd1306_command(SSD1306_DEACTIVATE_SCROLL); 409 | } 410 | 411 | // Dim the display 412 | // dim = true: display is dimmed 413 | // dim = false: display is normal 414 | void Adafruit_SSD1306::dim(boolean dim) { 415 | uint8_t contrast; 416 | 417 | if (dim) { 418 | contrast = 0; // Dimmed display 419 | } else { 420 | if (_vccstate == SSD1306_EXTERNALVCC) { 421 | contrast = 0x9F; 422 | } else { 423 | contrast = 0xCF; 424 | } 425 | } 426 | // the range of contrast to too small to be really useful 427 | // it is useful to dim the display 428 | ssd1306_command(SSD1306_SETCONTRAST); 429 | ssd1306_command(contrast); 430 | } 431 | 432 | void Adafruit_SSD1306::display(void) { 433 | ssd1306_command(SSD1306_COLUMNADDR); 434 | #if defined SSD1306_64_32 // Added by CL 2016-9-10 435 | ssd1306_command(0x20); // Column start address (0x20 = reset) - 64 pixel wide displays have starting values offset 436 | ssd1306_command(0x20 + (SSD1306_LCDWIDTH-1)); // Column end address (127 = reset) - 64 pixel wide displays have starting values offset - could use static 0x5F here 437 | #else 438 | ssd1306_command(0); // Column start address (0 = reset) 439 | ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) 440 | #endif 441 | 442 | ssd1306_command(SSD1306_PAGEADDR); 443 | ssd1306_command(0); // Page start address (0 = reset) 444 | #if SSD1306_LCDHEIGHT == 64 445 | ssd1306_command(7); // Page end address 446 | #endif 447 | #if SSD1306_LCDHEIGHT == 32 448 | ssd1306_command(3); // Page end address 449 | #endif 450 | #if SSD1306_LCDHEIGHT == 16 451 | ssd1306_command(1); // Page end address 452 | #endif 453 | 454 | if (sid != -1) 455 | { 456 | // SPI 457 | #ifdef HAVE_PORTREG 458 | *csport |= cspinmask; 459 | *dcport |= dcpinmask; 460 | *csport &= ~cspinmask; 461 | #else 462 | digitalWrite(cs, HIGH); 463 | digitalWrite(dc, HIGH); 464 | digitalWrite(cs, LOW); 465 | #endif 466 | 467 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 468 | fastSPIwrite(buffer[i]); 469 | } 470 | #ifdef HAVE_PORTREG 471 | *csport |= cspinmask; 472 | #else 473 | digitalWrite(cs, HIGH); 474 | #endif 475 | } 476 | else 477 | { 478 | // save I2C bitrate 479 | #ifdef TWBR 480 | uint8_t twbrbackup = TWBR; 481 | TWBR = 12; // upgrade to 400KHz! 482 | #endif 483 | 484 | //Serial.println(TWBR, DEC); 485 | //Serial.println(TWSR & 0x3, DEC); 486 | 487 | // I2C 488 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 489 | // send a bunch of data in one xmission 490 | Wire.beginTransmission(_i2caddr); 491 | WIRE_WRITE(0x40); 492 | for (uint8_t x=0; x<16; x++) { 493 | WIRE_WRITE(buffer[i]); 494 | i++; 495 | } 496 | i--; 497 | Wire.endTransmission(); 498 | } 499 | #ifdef TWBR 500 | TWBR = twbrbackup; 501 | #endif 502 | } 503 | } 504 | 505 | // clear everything 506 | void Adafruit_SSD1306::clearDisplay(void) { 507 | memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8)); 508 | } 509 | 510 | 511 | inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) { 512 | 513 | if(hwSPI) { 514 | (void)SPI.transfer(d); 515 | } else { 516 | for(uint8_t bit = 0x80; bit; bit >>= 1) { 517 | #ifdef HAVE_PORTREG 518 | *clkport &= ~clkpinmask; 519 | if(d & bit) *mosiport |= mosipinmask; 520 | else *mosiport &= ~mosipinmask; 521 | *clkport |= clkpinmask; 522 | #else 523 | digitalWrite(sclk, LOW); 524 | if(d & bit) digitalWrite(sid, HIGH); 525 | else digitalWrite(sid, LOW); 526 | digitalWrite(sclk, HIGH); 527 | #endif 528 | } 529 | } 530 | } 531 | 532 | void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { 533 | boolean bSwap = false; 534 | switch(rotation) { 535 | case 0: 536 | // 0 degree rotation, do nothing 537 | break; 538 | case 1: 539 | // 90 degree rotation, swap x & y for rotation, then invert x 540 | bSwap = true; 541 | ssd1306_swap(x, y); 542 | x = WIDTH - x - 1; 543 | break; 544 | case 2: 545 | // 180 degree rotation, invert x and y - then shift y around for height. 546 | x = WIDTH - x - 1; 547 | y = HEIGHT - y - 1; 548 | x -= (w-1); 549 | break; 550 | case 3: 551 | // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h) 552 | bSwap = true; 553 | ssd1306_swap(x, y); 554 | y = HEIGHT - y - 1; 555 | y -= (w-1); 556 | break; 557 | } 558 | 559 | if(bSwap) { 560 | drawFastVLineInternal(x, y, w, color); 561 | } else { 562 | drawFastHLineInternal(x, y, w, color); 563 | } 564 | } 565 | 566 | void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) { 567 | // Do bounds/limit checks 568 | if(y < 0 || y >= HEIGHT) { return; } 569 | 570 | // make sure we don't try to draw below 0 571 | if(x < 0) { 572 | w += x; 573 | x = 0; 574 | } 575 | 576 | // make sure we don't go off the edge of the display 577 | if( (x + w) > WIDTH) { 578 | w = (WIDTH - x); 579 | } 580 | 581 | // if our width is now negative, punt 582 | if(w <= 0) { return; } 583 | 584 | // set up the pointer for movement through the buffer 585 | register uint8_t *pBuf = buffer; 586 | // adjust the buffer pointer for the current row 587 | pBuf += ((y/8) * SSD1306_LCDWIDTH); 588 | // and offset x columns in 589 | pBuf += x; 590 | 591 | register uint8_t mask = 1 << (y&7); 592 | 593 | switch (color) 594 | { 595 | case WHITE: while(w--) { *pBuf++ |= mask; }; break; 596 | case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break; 597 | case INVERSE: while(w--) { *pBuf++ ^= mask; }; break; 598 | } 599 | } 600 | 601 | void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { 602 | bool bSwap = false; 603 | switch(rotation) { 604 | case 0: 605 | break; 606 | case 1: 607 | // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w) 608 | bSwap = true; 609 | ssd1306_swap(x, y); 610 | x = WIDTH - x - 1; 611 | x -= (h-1); 612 | break; 613 | case 2: 614 | // 180 degree rotation, invert x and y - then shift y around for height. 615 | x = WIDTH - x - 1; 616 | y = HEIGHT - y - 1; 617 | y -= (h-1); 618 | break; 619 | case 3: 620 | // 270 degree rotation, swap x & y for rotation, then invert y 621 | bSwap = true; 622 | ssd1306_swap(x, y); 623 | y = HEIGHT - y - 1; 624 | break; 625 | } 626 | 627 | if(bSwap) { 628 | drawFastHLineInternal(x, y, h, color); 629 | } else { 630 | drawFastVLineInternal(x, y, h, color); 631 | } 632 | } 633 | 634 | 635 | void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) { 636 | 637 | // do nothing if we're off the left or right side of the screen 638 | if(x < 0 || x >= WIDTH) { return; } 639 | 640 | // make sure we don't try to draw below 0 641 | if(__y < 0) { 642 | // __y is negative, this will subtract enough from __h to account for __y being 0 643 | __h += __y; 644 | __y = 0; 645 | 646 | } 647 | 648 | // make sure we don't go past the height of the display 649 | if( (__y + __h) > HEIGHT) { 650 | __h = (HEIGHT - __y); 651 | } 652 | 653 | // if our height is now negative, punt 654 | if(__h <= 0) { 655 | return; 656 | } 657 | 658 | // this display doesn't need ints for coordinates, use local byte registers for faster juggling 659 | register uint8_t y = __y; 660 | register uint8_t h = __h; 661 | 662 | 663 | // set up the pointer for fast movement through the buffer 664 | register uint8_t *pBuf = buffer; 665 | // adjust the buffer pointer for the current row 666 | pBuf += ((y/8) * SSD1306_LCDWIDTH); 667 | // and offset x columns in 668 | pBuf += x; 669 | 670 | // do the first partial byte, if necessary - this requires some masking 671 | register uint8_t mod = (y&7); 672 | if(mod) { 673 | // mask off the high n bits we want to set 674 | mod = 8-mod; 675 | 676 | // note - lookup table results in a nearly 10% performance improvement in fill* functions 677 | // register uint8_t mask = ~(0xFF >> (mod)); 678 | static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; 679 | register uint8_t mask = premask[mod]; 680 | 681 | // adjust the mask if we're not going to reach the end of this byte 682 | if( h < mod) { 683 | mask &= (0XFF >> (mod-h)); 684 | } 685 | 686 | switch (color) 687 | { 688 | case WHITE: *pBuf |= mask; break; 689 | case BLACK: *pBuf &= ~mask; break; 690 | case INVERSE: *pBuf ^= mask; break; 691 | } 692 | 693 | // fast exit if we're done here! 694 | if(h= 8) { 704 | if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop 705 | do { 706 | *pBuf=~(*pBuf); 707 | 708 | // adjust the buffer forward 8 rows worth of data 709 | pBuf += SSD1306_LCDWIDTH; 710 | 711 | // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now) 712 | h -= 8; 713 | } while(h >= 8); 714 | } 715 | else { 716 | // store a local value to work with 717 | register uint8_t val = (color == WHITE) ? 255 : 0; 718 | 719 | do { 720 | // write our value in 721 | *pBuf = val; 722 | 723 | // adjust the buffer forward 8 rows worth of data 724 | pBuf += SSD1306_LCDWIDTH; 725 | 726 | // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now) 727 | h -= 8; 728 | } while(h >= 8); 729 | } 730 | } 731 | 732 | // now do the final partial byte, if necessary 733 | if(h) { 734 | mod = h & 7; 735 | // this time we want to mask the low bits of the byte, vs the high bits we did above 736 | // register uint8_t mask = (1 << mod) - 1; 737 | // note - lookup table results in a nearly 10% performance improvement in fill* functions 738 | static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; 739 | register uint8_t mask = postmask[mod]; 740 | switch (color) 741 | { 742 | case WHITE: *pBuf |= mask; break; 743 | case BLACK: *pBuf &= ~mask; break; 744 | case INVERSE: *pBuf ^= mask; break; 745 | } 746 | } 747 | } 748 | -------------------------------------------------------------------------------- /Adafruit_SSD1306.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | These displays use SPI to communicate, 4 or 5 pins are required to 8 | interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | #ifndef _Adafruit_SSD1306_H_ 19 | #define _Adafruit_SSD1306_H_ 20 | 21 | #if ARDUINO >= 100 22 | #include "Arduino.h" 23 | #define WIRE_WRITE Wire.write 24 | #else 25 | #include "WProgram.h" 26 | #define WIRE_WRITE Wire.send 27 | #endif 28 | 29 | #if defined(__SAM3X8E__) 30 | typedef volatile RwReg PortReg; 31 | typedef uint32_t PortMask; 32 | #define HAVE_PORTREG 33 | #elif defined(ARDUINO_ARCH_SAMD) 34 | // not supported 35 | #elif defined(ESP8266) || defined(ARDUINO_STM32_FEATHER) 36 | typedef volatile uint32_t PortReg; 37 | typedef uint32_t PortMask; 38 | #else 39 | typedef volatile uint8_t PortReg; 40 | typedef uint8_t PortMask; 41 | #define HAVE_PORTREG 42 | #endif 43 | 44 | #include 45 | #include 46 | 47 | #define BLACK 0 48 | #define WHITE 1 49 | #define INVERSE 2 50 | 51 | #define SSD1306_I2C_ADDRESS 0x3C // 011110+SA0+RW - 0x3C or 0x3D 52 | // Address for 128x32 is 0x3C 53 | // Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded) 54 | 55 | /*========================================================================= 56 | SSD1306 Displays 57 | ----------------------------------------------------------------------- 58 | The driver is used in multiple displays (128x64, 128x32, etc.). 59 | Select the appropriate display below to create an appropriately 60 | sized framebuffer, etc. 61 | 62 | SSD1306_128_64 128x64 pixel display 63 | 64 | SSD1306_128_32 128x32 pixel display 65 | 66 | SSD1306_96_16 67 | 68 | -----------------------------------------------------------------------*/ 69 | // #define SSD1306_128_64 70 | // #define SSD1306_128_32 71 | // #define SSD1306_96_16 72 | #define SSD1306_64_32 73 | /*=========================================================================*/ 74 | 75 | #if defined SSD1306_128_64 && defined SSD1306_128_32 76 | #error "Only one SSD1306 display can be specified at once in SSD1306.h" 77 | #endif 78 | #if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 && !defined SSD1306_64_32 79 | #error "At least one SSD1306 display must be specified in SSD1306.h" 80 | #endif 81 | 82 | #if defined SSD1306_128_64 83 | #define SSD1306_LCDWIDTH 128 84 | #define SSD1306_LCDHEIGHT 64 85 | #endif 86 | #if defined SSD1306_128_32 87 | #define SSD1306_LCDWIDTH 128 88 | #define SSD1306_LCDHEIGHT 32 89 | #endif 90 | #if defined SSD1306_96_16 91 | #define SSD1306_LCDWIDTH 96 92 | #define SSD1306_LCDHEIGHT 16 93 | #endif 94 | #if defined SSD1306_64_32 95 | #define SSD1306_LCDWIDTH 64 96 | #define SSD1306_LCDHEIGHT 32 97 | #endif 98 | 99 | #define SSD1306_SETCONTRAST 0x81 100 | #define SSD1306_DISPLAYALLON_RESUME 0xA4 101 | #define SSD1306_DISPLAYALLON 0xA5 102 | #define SSD1306_NORMALDISPLAY 0xA6 103 | #define SSD1306_INVERTDISPLAY 0xA7 104 | #define SSD1306_DISPLAYOFF 0xAE 105 | #define SSD1306_DISPLAYON 0xAF 106 | 107 | #define SSD1306_SETDISPLAYOFFSET 0xD3 108 | #define SSD1306_SETCOMPINS 0xDA 109 | 110 | #define SSD1306_SETVCOMDETECT 0xDB 111 | 112 | #define SSD1306_SETDISPLAYCLOCKDIV 0xD5 113 | #define SSD1306_SETPRECHARGE 0xD9 114 | 115 | #define SSD1306_SETMULTIPLEX 0xA8 116 | 117 | #define SSD1306_SETLOWCOLUMN 0x00 118 | #define SSD1306_SETHIGHCOLUMN 0x10 119 | 120 | #define SSD1306_SETSTARTLINE 0x40 121 | 122 | #define SSD1306_MEMORYMODE 0x20 123 | #define SSD1306_COLUMNADDR 0x21 124 | #define SSD1306_PAGEADDR 0x22 125 | 126 | #define SSD1306_COMSCANINC 0xC0 127 | #define SSD1306_COMSCANDEC 0xC8 128 | 129 | #define SSD1306_SEGREMAP 0xA0 130 | 131 | #define SSD1306_CHARGEPUMP 0x8D 132 | 133 | #define SSD1306_EXTERNALVCC 0x1 134 | #define SSD1306_SWITCHCAPVCC 0x2 135 | 136 | // Scrolling #defines 137 | #define SSD1306_ACTIVATE_SCROLL 0x2F 138 | #define SSD1306_DEACTIVATE_SCROLL 0x2E 139 | #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 140 | #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 141 | #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 142 | #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 143 | #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A 144 | 145 | class Adafruit_SSD1306 : public Adafruit_GFX { 146 | public: 147 | Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS); 148 | Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS); 149 | Adafruit_SSD1306(int8_t RST = -1); 150 | 151 | void begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS, bool reset=true); 152 | void ssd1306_command(uint8_t c); 153 | 154 | void clearDisplay(void); 155 | void invertDisplay(uint8_t i); 156 | void display(); 157 | 158 | void startscrollright(uint8_t start, uint8_t stop); 159 | void startscrollleft(uint8_t start, uint8_t stop); 160 | 161 | void startscrolldiagright(uint8_t start, uint8_t stop); 162 | void startscrolldiagleft(uint8_t start, uint8_t stop); 163 | void stopscroll(void); 164 | 165 | void dim(boolean dim); 166 | 167 | void drawPixel(int16_t x, int16_t y, uint16_t color); 168 | 169 | virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); 170 | virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); 171 | 172 | private: 173 | int8_t _i2caddr, _vccstate, sid, sclk, dc, rst, cs; 174 | void fastSPIwrite(uint8_t c); 175 | 176 | boolean hwSPI; 177 | #ifdef HAVE_PORTREG 178 | PortReg *mosiport, *clkport, *csport, *dcport; 179 | PortMask mosipinmask, clkpinmask, cspinmask, dcpinmask; 180 | #endif 181 | 182 | inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)); 183 | inline void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline)); 184 | 185 | }; 186 | 187 | #endif /* _Adafruit_SSD1306_H_ */ 188 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adafruit_SSD1306 2 | 3 | 4 | ## Compatibility 5 | 6 | MCU | Tested Works | Doesn't Work | Not Tested | Notes 7 | ------------------ | :----------: | :----------: | :---------: | ----- 8 | Atmega328 @ 16MHz | X | | | 9 | Atmega328 @ 12MHz | X | | | 10 | Atmega32u4 @ 16MHz | X | | | 11 | Atmega32u4 @ 8MHz | X | | | 12 | ESP8266 | X | | | change OLED_RESET to different pin if using default I2C pins D4/D5. 13 | Atmega2560 @ 16MHz | X | | | 14 | ATSAM3X8E | X | | | 15 | ATSAM21D | X | | | 16 | ATtiny85 @ 16MHz | | X | | 17 | ATtiny85 @ 8MHz | | X | | 18 | Intel Curie @ 32MHz | | | X | 19 | STM32F2 | | | X | 20 | 21 | * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini 22 | * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V 23 | * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 24 | * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro 25 | * ESP8266 : Adafruit Huzzah 26 | * ATmega2560 @ 16MHz : Arduino Mega 27 | * ATSAM3X8E : Arduino Due 28 | * ATSAM21D : Arduino Zero, M0 Pro 29 | * ATtiny85 @ 16MHz : Adafruit Trinket 5V 30 | * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 2 | 3 | Pick one up today in the adafruit shop! 4 | ------> http://www.adafruit.com/category/63_98 5 | 6 | These displays use SPI to communicate, 4 or 5 pins are required to 7 | interface 8 | 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | Scrolling code contributed by Michael Gregg 15 | BSD license, check license.txt for more information 16 | All text above must be included in any redistribution 17 | 18 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h 19 | 20 | Place the Adafruit_SSD1306 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. 21 | 22 | You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from 23 | https://github.com/adafruit/Adafruit-GFX-Library 24 | and download/install that library as well -------------------------------------------------------------------------------- /examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is an example for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x32 size display using I2C to communicate 8 | 3 pins are required to interface (2 I2C and one reset) 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define OLED_RESET 4 25 | Adafruit_SSD1306 display(OLED_RESET); 26 | 27 | #define NUMFLAKES 10 28 | #define XPOS 0 29 | #define YPOS 1 30 | #define DELTAY 2 31 | 32 | 33 | #define LOGO16_GLCD_HEIGHT 16 34 | #define LOGO16_GLCD_WIDTH 16 35 | static const unsigned char PROGMEM logo16_glcd_bmp[] = 36 | { B00000000, B11000000, 37 | B00000001, B11000000, 38 | B00000001, B11000000, 39 | B00000011, B11100000, 40 | B11110011, B11100000, 41 | B11111110, B11111000, 42 | B01111110, B11111111, 43 | B00110011, B10011111, 44 | B00011111, B11111100, 45 | B00001101, B01110000, 46 | B00011011, B10100000, 47 | B00111111, B11100000, 48 | B00111111, B11110000, 49 | B01111100, B11110000, 50 | B01110000, B01110000, 51 | B00000000, B00110000 }; 52 | 53 | #if (SSD1306_LCDHEIGHT != 32) 54 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 55 | #endif 56 | 57 | void setup() { 58 | Serial.begin(9600); 59 | 60 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 61 | display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) 62 | // init done 63 | 64 | // Show image buffer on the display hardware. 65 | // Since the buffer is intialized with an Adafruit splashscreen 66 | // internally, this will display the splashscreen. 67 | display.display(); 68 | delay(2000); 69 | 70 | // Clear the buffer. 71 | display.clearDisplay(); 72 | 73 | // draw a single pixel 74 | display.drawPixel(10, 10, WHITE); 75 | // Show the display buffer on the hardware. 76 | // NOTE: You _must_ call display after making any drawing commands 77 | // to make them visible on the display hardware! 78 | display.display(); 79 | delay(2000); 80 | display.clearDisplay(); 81 | 82 | // draw many lines 83 | testdrawline(); 84 | display.display(); 85 | delay(2000); 86 | display.clearDisplay(); 87 | 88 | // draw rectangles 89 | testdrawrect(); 90 | display.display(); 91 | delay(2000); 92 | display.clearDisplay(); 93 | 94 | // draw multiple rectangles 95 | testfillrect(); 96 | display.display(); 97 | delay(2000); 98 | display.clearDisplay(); 99 | 100 | // draw mulitple circles 101 | testdrawcircle(); 102 | display.display(); 103 | delay(2000); 104 | display.clearDisplay(); 105 | 106 | // draw a white circle, 10 pixel radius 107 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 108 | display.display(); 109 | delay(2000); 110 | display.clearDisplay(); 111 | 112 | testdrawroundrect(); 113 | delay(2000); 114 | display.clearDisplay(); 115 | 116 | testfillroundrect(); 117 | delay(2000); 118 | display.clearDisplay(); 119 | 120 | testdrawtriangle(); 121 | delay(2000); 122 | display.clearDisplay(); 123 | 124 | testfilltriangle(); 125 | delay(2000); 126 | display.clearDisplay(); 127 | 128 | // draw the first ~12 characters in the font 129 | testdrawchar(); 130 | display.display(); 131 | delay(2000); 132 | display.clearDisplay(); 133 | 134 | // draw scrolling text 135 | testscrolltext(); 136 | delay(2000); 137 | display.clearDisplay(); 138 | 139 | // text display tests 140 | display.setTextSize(1); 141 | display.setTextColor(WHITE); 142 | display.setCursor(0,0); 143 | display.println("Hello, world!"); 144 | display.setTextColor(BLACK, WHITE); // 'inverted' text 145 | display.println(3.141592); 146 | display.setTextSize(2); 147 | display.setTextColor(WHITE); 148 | display.print("0x"); display.println(0xDEADBEEF, HEX); 149 | display.display(); 150 | delay(2000); 151 | display.clearDisplay(); 152 | 153 | // miniature bitmap display 154 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 155 | display.display(); 156 | delay(1); 157 | 158 | // invert the display 159 | display.invertDisplay(true); 160 | delay(1000); 161 | display.invertDisplay(false); 162 | delay(1000); 163 | display.clearDisplay(); 164 | 165 | // draw a bitmap icon and 'animate' movement 166 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 167 | } 168 | 169 | 170 | void loop() { 171 | 172 | } 173 | 174 | 175 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 176 | uint8_t icons[NUMFLAKES][3]; 177 | 178 | // initialize 179 | for (uint8_t f=0; f< NUMFLAKES; f++) { 180 | icons[f][XPOS] = random(display.width()); 181 | icons[f][YPOS] = 0; 182 | icons[f][DELTAY] = random(5) + 1; 183 | 184 | Serial.print("x: "); 185 | Serial.print(icons[f][XPOS], DEC); 186 | Serial.print(" y: "); 187 | Serial.print(icons[f][YPOS], DEC); 188 | Serial.print(" dy: "); 189 | Serial.println(icons[f][DELTAY], DEC); 190 | } 191 | 192 | while (1) { 193 | // draw each icon 194 | for (uint8_t f=0; f< NUMFLAKES; f++) { 195 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); 196 | } 197 | display.display(); 198 | delay(200); 199 | 200 | // then erase it + move it 201 | for (uint8_t f=0; f< NUMFLAKES; f++) { 202 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, BLACK); 203 | // move it 204 | icons[f][YPOS] += icons[f][DELTAY]; 205 | // if its gone, reinit 206 | if (icons[f][YPOS] > display.height()) { 207 | icons[f][XPOS] = random(display.width()); 208 | icons[f][YPOS] = 0; 209 | icons[f][DELTAY] = random(5) + 1; 210 | } 211 | } 212 | } 213 | } 214 | 215 | 216 | void testdrawchar(void) { 217 | display.setTextSize(1); 218 | display.setTextColor(WHITE); 219 | display.setCursor(0,0); 220 | 221 | for (uint8_t i=0; i < 168; i++) { 222 | if (i == '\n') continue; 223 | display.write(i); 224 | if ((i > 0) && (i % 21 == 0)) 225 | display.println(); 226 | } 227 | display.display(); 228 | delay(1); 229 | } 230 | 231 | void testdrawcircle(void) { 232 | for (int16_t i=0; i0; i-=5) { 263 | display.fillTriangle(display.width()/2, display.height()/2-i, 264 | display.width()/2-i, display.height()/2+i, 265 | display.width()/2+i, display.height()/2+i, WHITE); 266 | if (color == WHITE) color = BLACK; 267 | else color = WHITE; 268 | display.display(); 269 | delay(1); 270 | } 271 | } 272 | 273 | void testdrawroundrect(void) { 274 | for (int16_t i=0; i=0; i-=4) { 320 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 321 | display.display(); 322 | delay(1); 323 | } 324 | delay(250); 325 | 326 | display.clearDisplay(); 327 | for (int16_t i=display.width()-1; i>=0; i-=4) { 328 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 329 | display.display(); 330 | delay(1); 331 | } 332 | for (int16_t i=display.height()-1; i>=0; i-=4) { 333 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 334 | display.display(); 335 | delay(1); 336 | } 337 | delay(250); 338 | 339 | display.clearDisplay(); 340 | for (int16_t i=0; i http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x32 size display using SPI to communicate 8 | 4 or 5 pins are required to interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | // If using software SPI (the default case): 25 | #define OLED_MOSI 9 26 | #define OLED_CLK 10 27 | #define OLED_DC 11 28 | #define OLED_CS 12 29 | #define OLED_RESET 13 30 | Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); 31 | 32 | /* Uncomment this block to use hardware SPI 33 | #define OLED_DC 6 34 | #define OLED_CS 7 35 | #define OLED_RESET 8 36 | Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS); 37 | */ 38 | 39 | #define NUMFLAKES 10 40 | #define XPOS 0 41 | #define YPOS 1 42 | #define DELTAY 2 43 | 44 | #define LOGO16_GLCD_HEIGHT 16 45 | #define LOGO16_GLCD_WIDTH 16 46 | static const unsigned char PROGMEM logo16_glcd_bmp[] = 47 | { B00000000, B11000000, 48 | B00000001, B11000000, 49 | B00000001, B11000000, 50 | B00000011, B11100000, 51 | B11110011, B11100000, 52 | B11111110, B11111000, 53 | B01111110, B11111111, 54 | B00110011, B10011111, 55 | B00011111, B11111100, 56 | B00001101, B01110000, 57 | B00011011, B10100000, 58 | B00111111, B11100000, 59 | B00111111, B11110000, 60 | B01111100, B11110000, 61 | B01110000, B01110000, 62 | B00000000, B00110000 }; 63 | 64 | #if (SSD1306_LCDHEIGHT != 32) 65 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 66 | #endif 67 | 68 | void setup() { 69 | Serial.begin(9600); 70 | 71 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 72 | display.begin(SSD1306_SWITCHCAPVCC); 73 | // init done 74 | 75 | // Show image buffer on the display hardware. 76 | // Since the buffer is intialized with an Adafruit splashscreen 77 | // internally, this will display the splashscreen. 78 | display.display(); 79 | delay(2000); 80 | 81 | // Clear the buffer. 82 | display.clearDisplay(); 83 | 84 | // draw a single pixel 85 | display.drawPixel(10, 10, WHITE); 86 | // Show the display buffer on the hardware. 87 | // NOTE: You _must_ call display after making any drawing commands 88 | // to make them visible on the display hardware! 89 | display.display(); 90 | delay(2000); 91 | display.clearDisplay(); 92 | 93 | // draw many lines 94 | testdrawline(); 95 | display.display(); 96 | delay(2000); 97 | display.clearDisplay(); 98 | 99 | // draw rectangles 100 | testdrawrect(); 101 | display.display(); 102 | delay(2000); 103 | display.clearDisplay(); 104 | 105 | // draw multiple rectangles 106 | testfillrect(); 107 | display.display(); 108 | delay(2000); 109 | display.clearDisplay(); 110 | 111 | // draw mulitple circles 112 | testdrawcircle(); 113 | display.display(); 114 | delay(2000); 115 | display.clearDisplay(); 116 | 117 | // draw a white circle, 10 pixel radius 118 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 119 | display.display(); 120 | delay(2000); 121 | display.clearDisplay(); 122 | 123 | testdrawroundrect(); 124 | delay(2000); 125 | display.clearDisplay(); 126 | 127 | testfillroundrect(); 128 | delay(2000); 129 | display.clearDisplay(); 130 | 131 | testdrawtriangle(); 132 | delay(2000); 133 | display.clearDisplay(); 134 | 135 | testfilltriangle(); 136 | delay(2000); 137 | display.clearDisplay(); 138 | 139 | // draw the first ~12 characters in the font 140 | testdrawchar(); 141 | display.display(); 142 | delay(2000); 143 | display.clearDisplay(); 144 | 145 | // draw scrolling text 146 | testscrolltext(); 147 | delay(2000); 148 | display.clearDisplay(); 149 | 150 | // text display tests 151 | display.setTextSize(1); 152 | display.setTextColor(WHITE); 153 | display.setCursor(0,0); 154 | display.println("Hello, world!"); 155 | display.setTextColor(BLACK, WHITE); // 'inverted' text 156 | display.println(3.141592); 157 | display.setTextSize(2); 158 | display.setTextColor(WHITE); 159 | display.print("0x"); display.println(0xDEADBEEF, HEX); 160 | display.display(); 161 | delay(2000); 162 | display.clearDisplay(); 163 | 164 | // miniature bitmap display 165 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 166 | display.display(); 167 | 168 | // invert the display 169 | display.invertDisplay(true); 170 | delay(1000); 171 | display.invertDisplay(false); 172 | delay(1000); 173 | display.clearDisplay(); 174 | 175 | // draw a bitmap icon and 'animate' movement 176 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 177 | } 178 | 179 | 180 | void loop() { 181 | 182 | } 183 | 184 | 185 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 186 | uint8_t icons[NUMFLAKES][3]; 187 | 188 | // initialize 189 | for (uint8_t f=0; f< NUMFLAKES; f++) { 190 | icons[f][XPOS] = random(display.width()); 191 | icons[f][YPOS] = 0; 192 | icons[f][DELTAY] = random(5) + 1; 193 | 194 | Serial.print("x: "); 195 | Serial.print(icons[f][XPOS], DEC); 196 | Serial.print(" y: "); 197 | Serial.print(icons[f][YPOS], DEC); 198 | Serial.print(" dy: "); 199 | Serial.println(icons[f][DELTAY], DEC); 200 | } 201 | 202 | while (1) { 203 | // draw each icon 204 | for (uint8_t f=0; f< NUMFLAKES; f++) { 205 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); 206 | } 207 | display.display(); 208 | delay(200); 209 | 210 | // then erase it + move it 211 | for (uint8_t f=0; f< NUMFLAKES; f++) { 212 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, BLACK); 213 | // move it 214 | icons[f][YPOS] += icons[f][DELTAY]; 215 | // if its gone, reinit 216 | if (icons[f][YPOS] > display.height()) { 217 | icons[f][XPOS] = random(display.width()); 218 | icons[f][YPOS] = 0; 219 | icons[f][DELTAY] = random(5) + 1; 220 | } 221 | } 222 | } 223 | } 224 | 225 | 226 | void testdrawchar(void) { 227 | display.setTextSize(1); 228 | display.setTextColor(WHITE); 229 | display.setCursor(0,0); 230 | 231 | for (uint8_t i=0; i < 168; i++) { 232 | if (i == '\n') continue; 233 | display.write(i); 234 | if ((i > 0) && (i % 21 == 0)) 235 | display.println(); 236 | } 237 | display.display(); 238 | } 239 | 240 | void testdrawcircle(void) { 241 | for (int16_t i=0; i0; i-=5) { 269 | display.fillTriangle(display.width()/2, display.height()/2-i, 270 | display.width()/2-i, display.height()/2+i, 271 | display.width()/2+i, display.height()/2+i, WHITE); 272 | if (color == WHITE) color = BLACK; 273 | else color = WHITE; 274 | display.display(); 275 | } 276 | } 277 | 278 | void testdrawroundrect(void) { 279 | for (int16_t i=0; i=0; i-=4) { 319 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 320 | display.display(); 321 | } 322 | delay(250); 323 | 324 | display.clearDisplay(); 325 | for (int16_t i=display.width()-1; i>=0; i-=4) { 326 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 327 | display.display(); 328 | } 329 | for (int16_t i=display.height()-1; i>=0; i-=4) { 330 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 331 | display.display(); 332 | } 333 | delay(250); 334 | 335 | display.clearDisplay(); 336 | for (int16_t i=0; i http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x64 size display using I2C to communicate 8 | 3 pins are required to interface (2 I2C and one reset) 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define OLED_RESET 4 25 | Adafruit_SSD1306 display(OLED_RESET); 26 | 27 | #define NUMFLAKES 10 28 | #define XPOS 0 29 | #define YPOS 1 30 | #define DELTAY 2 31 | 32 | 33 | #define LOGO16_GLCD_HEIGHT 16 34 | #define LOGO16_GLCD_WIDTH 16 35 | static const unsigned char PROGMEM logo16_glcd_bmp[] = 36 | { B00000000, B11000000, 37 | B00000001, B11000000, 38 | B00000001, B11000000, 39 | B00000011, B11100000, 40 | B11110011, B11100000, 41 | B11111110, B11111000, 42 | B01111110, B11111111, 43 | B00110011, B10011111, 44 | B00011111, B11111100, 45 | B00001101, B01110000, 46 | B00011011, B10100000, 47 | B00111111, B11100000, 48 | B00111111, B11110000, 49 | B01111100, B11110000, 50 | B01110000, B01110000, 51 | B00000000, B00110000 }; 52 | 53 | #if (SSD1306_LCDHEIGHT != 64) 54 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 55 | #endif 56 | 57 | void setup() { 58 | Serial.begin(9600); 59 | 60 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 61 | display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64) 62 | // init done 63 | 64 | // Show image buffer on the display hardware. 65 | // Since the buffer is intialized with an Adafruit splashscreen 66 | // internally, this will display the splashscreen. 67 | display.display(); 68 | delay(2000); 69 | 70 | // Clear the buffer. 71 | display.clearDisplay(); 72 | 73 | // draw a single pixel 74 | display.drawPixel(10, 10, WHITE); 75 | // Show the display buffer on the hardware. 76 | // NOTE: You _must_ call display after making any drawing commands 77 | // to make them visible on the display hardware! 78 | display.display(); 79 | delay(2000); 80 | display.clearDisplay(); 81 | 82 | // draw many lines 83 | testdrawline(); 84 | display.display(); 85 | delay(2000); 86 | display.clearDisplay(); 87 | 88 | // draw rectangles 89 | testdrawrect(); 90 | display.display(); 91 | delay(2000); 92 | display.clearDisplay(); 93 | 94 | // draw multiple rectangles 95 | testfillrect(); 96 | display.display(); 97 | delay(2000); 98 | display.clearDisplay(); 99 | 100 | // draw mulitple circles 101 | testdrawcircle(); 102 | display.display(); 103 | delay(2000); 104 | display.clearDisplay(); 105 | 106 | // draw a white circle, 10 pixel radius 107 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 108 | display.display(); 109 | delay(2000); 110 | display.clearDisplay(); 111 | 112 | testdrawroundrect(); 113 | delay(2000); 114 | display.clearDisplay(); 115 | 116 | testfillroundrect(); 117 | delay(2000); 118 | display.clearDisplay(); 119 | 120 | testdrawtriangle(); 121 | delay(2000); 122 | display.clearDisplay(); 123 | 124 | testfilltriangle(); 125 | delay(2000); 126 | display.clearDisplay(); 127 | 128 | // draw the first ~12 characters in the font 129 | testdrawchar(); 130 | display.display(); 131 | delay(2000); 132 | display.clearDisplay(); 133 | 134 | // draw scrolling text 135 | testscrolltext(); 136 | delay(2000); 137 | display.clearDisplay(); 138 | 139 | // text display tests 140 | display.setTextSize(1); 141 | display.setTextColor(WHITE); 142 | display.setCursor(0,0); 143 | display.println("Hello, world!"); 144 | display.setTextColor(BLACK, WHITE); // 'inverted' text 145 | display.println(3.141592); 146 | display.setTextSize(2); 147 | display.setTextColor(WHITE); 148 | display.print("0x"); display.println(0xDEADBEEF, HEX); 149 | display.display(); 150 | delay(2000); 151 | display.clearDisplay(); 152 | 153 | // miniature bitmap display 154 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 155 | display.display(); 156 | delay(1); 157 | 158 | // invert the display 159 | display.invertDisplay(true); 160 | delay(1000); 161 | display.invertDisplay(false); 162 | delay(1000); 163 | display.clearDisplay(); 164 | 165 | // draw a bitmap icon and 'animate' movement 166 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 167 | } 168 | 169 | 170 | void loop() { 171 | 172 | } 173 | 174 | 175 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 176 | uint8_t icons[NUMFLAKES][3]; 177 | 178 | // initialize 179 | for (uint8_t f=0; f< NUMFLAKES; f++) { 180 | icons[f][XPOS] = random(display.width()); 181 | icons[f][YPOS] = 0; 182 | icons[f][DELTAY] = random(5) + 1; 183 | 184 | Serial.print("x: "); 185 | Serial.print(icons[f][XPOS], DEC); 186 | Serial.print(" y: "); 187 | Serial.print(icons[f][YPOS], DEC); 188 | Serial.print(" dy: "); 189 | Serial.println(icons[f][DELTAY], DEC); 190 | } 191 | 192 | while (1) { 193 | // draw each icon 194 | for (uint8_t f=0; f< NUMFLAKES; f++) { 195 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); 196 | } 197 | display.display(); 198 | delay(200); 199 | 200 | // then erase it + move it 201 | for (uint8_t f=0; f< NUMFLAKES; f++) { 202 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, BLACK); 203 | // move it 204 | icons[f][YPOS] += icons[f][DELTAY]; 205 | // if its gone, reinit 206 | if (icons[f][YPOS] > display.height()) { 207 | icons[f][XPOS] = random(display.width()); 208 | icons[f][YPOS] = 0; 209 | icons[f][DELTAY] = random(5) + 1; 210 | } 211 | } 212 | } 213 | } 214 | 215 | 216 | void testdrawchar(void) { 217 | display.setTextSize(1); 218 | display.setTextColor(WHITE); 219 | display.setCursor(0,0); 220 | 221 | for (uint8_t i=0; i < 168; i++) { 222 | if (i == '\n') continue; 223 | display.write(i); 224 | if ((i > 0) && (i % 21 == 0)) 225 | display.println(); 226 | } 227 | display.display(); 228 | delay(1); 229 | } 230 | 231 | void testdrawcircle(void) { 232 | for (int16_t i=0; i0; i-=5) { 263 | display.fillTriangle(display.width()/2, display.height()/2-i, 264 | display.width()/2-i, display.height()/2+i, 265 | display.width()/2+i, display.height()/2+i, WHITE); 266 | if (color == WHITE) color = BLACK; 267 | else color = WHITE; 268 | display.display(); 269 | delay(1); 270 | } 271 | } 272 | 273 | void testdrawroundrect(void) { 274 | for (int16_t i=0; i=0; i-=4) { 320 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 321 | display.display(); 322 | delay(1); 323 | } 324 | delay(250); 325 | 326 | display.clearDisplay(); 327 | for (int16_t i=display.width()-1; i>=0; i-=4) { 328 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 329 | display.display(); 330 | delay(1); 331 | } 332 | for (int16_t i=display.height()-1; i>=0; i-=4) { 333 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 334 | display.display(); 335 | delay(1); 336 | } 337 | delay(250); 338 | 339 | display.clearDisplay(); 340 | for (int16_t i=0; i http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x64 size display using SPI to communicate 8 | 4 or 5 pins are required to interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | // If using software SPI (the default case): 25 | #define OLED_MOSI 9 26 | #define OLED_CLK 10 27 | #define OLED_DC 11 28 | #define OLED_CS 12 29 | #define OLED_RESET 13 30 | Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); 31 | 32 | /* Uncomment this block to use hardware SPI 33 | #define OLED_DC 6 34 | #define OLED_CS 7 35 | #define OLED_RESET 8 36 | Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS); 37 | */ 38 | 39 | #define NUMFLAKES 10 40 | #define XPOS 0 41 | #define YPOS 1 42 | #define DELTAY 2 43 | 44 | #define LOGO16_GLCD_HEIGHT 16 45 | #define LOGO16_GLCD_WIDTH 16 46 | static const unsigned char PROGMEM logo16_glcd_bmp[] = 47 | { B00000000, B11000000, 48 | B00000001, B11000000, 49 | B00000001, B11000000, 50 | B00000011, B11100000, 51 | B11110011, B11100000, 52 | B11111110, B11111000, 53 | B01111110, B11111111, 54 | B00110011, B10011111, 55 | B00011111, B11111100, 56 | B00001101, B01110000, 57 | B00011011, B10100000, 58 | B00111111, B11100000, 59 | B00111111, B11110000, 60 | B01111100, B11110000, 61 | B01110000, B01110000, 62 | B00000000, B00110000 }; 63 | 64 | #if (SSD1306_LCDHEIGHT != 64) 65 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 66 | #endif 67 | 68 | void setup() { 69 | Serial.begin(9600); 70 | 71 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 72 | display.begin(SSD1306_SWITCHCAPVCC); 73 | // init done 74 | 75 | // Show image buffer on the display hardware. 76 | // Since the buffer is intialized with an Adafruit splashscreen 77 | // internally, this will display the splashscreen. 78 | display.display(); 79 | delay(2000); 80 | 81 | // Clear the buffer. 82 | display.clearDisplay(); 83 | 84 | // draw a single pixel 85 | display.drawPixel(10, 10, WHITE); 86 | // Show the display buffer on the hardware. 87 | // NOTE: You _must_ call display after making any drawing commands 88 | // to make them visible on the display hardware! 89 | display.display(); 90 | delay(2000); 91 | display.clearDisplay(); 92 | 93 | // draw many lines 94 | testdrawline(); 95 | display.display(); 96 | delay(2000); 97 | display.clearDisplay(); 98 | 99 | // draw rectangles 100 | testdrawrect(); 101 | display.display(); 102 | delay(2000); 103 | display.clearDisplay(); 104 | 105 | // draw multiple rectangles 106 | testfillrect(); 107 | display.display(); 108 | delay(2000); 109 | display.clearDisplay(); 110 | 111 | // draw mulitple circles 112 | testdrawcircle(); 113 | display.display(); 114 | delay(2000); 115 | display.clearDisplay(); 116 | 117 | // draw a white circle, 10 pixel radius 118 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 119 | display.display(); 120 | delay(2000); 121 | display.clearDisplay(); 122 | 123 | testdrawroundrect(); 124 | delay(2000); 125 | display.clearDisplay(); 126 | 127 | testfillroundrect(); 128 | delay(2000); 129 | display.clearDisplay(); 130 | 131 | testdrawtriangle(); 132 | delay(2000); 133 | display.clearDisplay(); 134 | 135 | testfilltriangle(); 136 | delay(2000); 137 | display.clearDisplay(); 138 | 139 | // draw the first ~12 characters in the font 140 | testdrawchar(); 141 | display.display(); 142 | delay(2000); 143 | display.clearDisplay(); 144 | 145 | // draw scrolling text 146 | testscrolltext(); 147 | delay(2000); 148 | display.clearDisplay(); 149 | 150 | // text display tests 151 | display.setTextSize(1); 152 | display.setTextColor(WHITE); 153 | display.setCursor(0,0); 154 | display.println("Hello, world!"); 155 | display.setTextColor(BLACK, WHITE); // 'inverted' text 156 | display.println(3.141592); 157 | display.setTextSize(2); 158 | display.setTextColor(WHITE); 159 | display.print("0x"); display.println(0xDEADBEEF, HEX); 160 | display.display(); 161 | delay(2000); 162 | display.clearDisplay(); 163 | 164 | // miniature bitmap display 165 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 166 | display.display(); 167 | 168 | // invert the display 169 | display.invertDisplay(true); 170 | delay(1000); 171 | display.invertDisplay(false); 172 | delay(1000); 173 | display.clearDisplay(); 174 | 175 | // draw a bitmap icon and 'animate' movement 176 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 177 | } 178 | 179 | 180 | void loop() { 181 | 182 | } 183 | 184 | 185 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 186 | uint8_t icons[NUMFLAKES][3]; 187 | 188 | // initialize 189 | for (uint8_t f=0; f< NUMFLAKES; f++) { 190 | icons[f][XPOS] = random(display.width()); 191 | icons[f][YPOS] = 0; 192 | icons[f][DELTAY] = random(5) + 1; 193 | 194 | Serial.print("x: "); 195 | Serial.print(icons[f][XPOS], DEC); 196 | Serial.print(" y: "); 197 | Serial.print(icons[f][YPOS], DEC); 198 | Serial.print(" dy: "); 199 | Serial.println(icons[f][DELTAY], DEC); 200 | } 201 | 202 | while (1) { 203 | // draw each icon 204 | for (uint8_t f=0; f< NUMFLAKES; f++) { 205 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE); 206 | } 207 | display.display(); 208 | delay(200); 209 | 210 | // then erase it + move it 211 | for (uint8_t f=0; f< NUMFLAKES; f++) { 212 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, BLACK); 213 | // move it 214 | icons[f][YPOS] += icons[f][DELTAY]; 215 | // if its gone, reinit 216 | if (icons[f][YPOS] > display.height()) { 217 | icons[f][XPOS] = random(display.width()); 218 | icons[f][YPOS] = 0; 219 | icons[f][DELTAY] = random(5) + 1; 220 | } 221 | } 222 | } 223 | } 224 | 225 | 226 | void testdrawchar(void) { 227 | display.setTextSize(1); 228 | display.setTextColor(WHITE); 229 | display.setCursor(0,0); 230 | 231 | for (uint8_t i=0; i < 168; i++) { 232 | if (i == '\n') continue; 233 | display.write(i); 234 | if ((i > 0) && (i % 21 == 0)) 235 | display.println(); 236 | } 237 | display.display(); 238 | } 239 | 240 | void testdrawcircle(void) { 241 | for (int16_t i=0; i0; i-=5) { 269 | display.fillTriangle(display.width()/2, display.height()/2-i, 270 | display.width()/2-i, display.height()/2+i, 271 | display.width()/2+i, display.height()/2+i, WHITE); 272 | if (color == WHITE) color = BLACK; 273 | else color = WHITE; 274 | display.display(); 275 | } 276 | } 277 | 278 | void testdrawroundrect(void) { 279 | for (int16_t i=0; i=0; i-=4) { 319 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 320 | display.display(); 321 | } 322 | delay(250); 323 | 324 | display.clearDisplay(); 325 | for (int16_t i=display.width()-1; i>=0; i-=4) { 326 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 327 | display.display(); 328 | } 329 | for (int16_t i=display.height()-1; i>=0; i-=4) { 330 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 331 | display.display(); 332 | } 333 | delay(250); 334 | 335 | display.clearDisplay(); 336 | for (int16_t i=0; i 5 | sentence=SSD1306 oled driver library for 'monochrome' 128x64 and 128x32 OLEDs! 6 | paragraph=SSD1306 oled driver library for 'monochrome' 128x64 and 128x32 OLEDs! 7 | category=Display 8 | url=https://github.com/adafruit/Adafruit_SSD1306 9 | architectures=* 10 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2012, Adafruit Industries 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holders nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | --------------------------------------------------------------------------------