diff --git a/.travis.yml b/.travis.yml index 1eb9c4566d2d2fa62ef3ac330fb63425bed27849..88a1e72ba590475a21d8f6e194ad3696fb9dfcb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ cache: env: - PLATFORMIO_CI_SRC=examples/SSD1306UiDemo - PLATFORMIO_CI_SRC=examples/SSD1306SimpleDemo + - PLATFORMIO_CI_SRC=examples/SSD1306DrawingDemo + - PLATFORMIO_CI_SRC=examples/SSD1306OTADemo - PLATFORMIO_CI_SRC=examples/SSD1306ClockDemo diff --git a/OLEDDisplay.cpp b/OLEDDisplay.cpp index 75cb6ffdc60b9334db0402b1ae03440fc6c4b759..e55683f3b19345add7bb7f93822adc882bac4b62 100644 --- a/OLEDDisplay.cpp +++ b/OLEDDisplay.cpp @@ -125,13 +125,13 @@ void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) { drawHorizontalLine(x, y, width); drawVerticalLine(x, y, height); - drawVerticalLine(x + width, y, height); - drawHorizontalLine(x, y + height, width); + drawVerticalLine(x + width - 1, y, height); + drawHorizontalLine(x, y + height - 1, width); } void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) { - for (int16_t i = yMove; i < yMove + height; i++) { - drawHorizontalLine(xMove, i, width); + for (int16_t x = xMove; x < xMove + width; x++) { + drawVerticalLine(x, yMove, height); } } @@ -161,6 +161,46 @@ void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) { setPixel(x0, y0 - radius); } +void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + while (x < y) { + if (dp < 0) + dp = dp + 2 * (++x) + 3; + else + dp = dp + 2 * (++x) - 2 * (--y) + 5; + if (quads & 0x1) { + setPixel(x0 + x, y0 - y); + setPixel(x0 + y, y0 - x); + } + if (quads & 0x2) { + setPixel(x0 - y, y0 - x); + setPixel(x0 - x, y0 - y); + } + if (quads & 0x4) { + setPixel(x0 - y, y0 + x); + setPixel(x0 - x, y0 + y); + } + if (quads & 0x8) { + setPixel(x0 + x, y0 + y); + setPixel(x0 + y, y0 + x); + } + } + if (quads & 0x1 && quads & 0x8) { + setPixel(x0 + radius, y0); + } + if (quads & 0x4 && quads & 0x8) { + setPixel(x0, y0 + radius); + } + if (quads & 0x2 && quads & 0x4) { + setPixel(x0 - radius, y0); + } + if (quads & 0x1 && quads & 0x2) { + setPixel(x0, y0 - radius); + } +} + + void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) { int16_t x = 0, y = radius; int16_t dp = 1 - radius; @@ -215,7 +255,7 @@ void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { } void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { - if (x < 0 || x > DISPLAY_WIDTH) return; + if (x < 0 || x >= DISPLAY_WIDTH) return; if (y < 0) { length += y; @@ -245,9 +285,9 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { } switch (color) { - case WHITE: *bufferPtr |= drawBit; break; - case BLACK: *bufferPtr &= drawBit; break; - case INVERSE: *bufferPtr ^= drawBit; break; + case WHITE: *bufferPtr |= drawBit; break; + case BLACK: *bufferPtr &= ~drawBit; break; + case INVERSE: *bufferPtr ^= drawBit; break; } if (length < yOffset) return; @@ -280,28 +320,31 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { if (length > 0) { drawBit = (1 << (length & 7)) - 1; switch (color) { - case WHITE: *bufferPtr |= drawBit; break; - case BLACK: *bufferPtr &= drawBit; break; - case INVERSE: *bufferPtr ^= drawBit; break; + case WHITE: *bufferPtr |= drawBit; break; + case BLACK: *bufferPtr &= ~drawBit; break; + case INVERSE: *bufferPtr ^= drawBit; break; } } } void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) { uint16_t radius = height / 2; - uint16_t innerRadius = radius - 3; - setColor(WHITE); - drawCircle(x + radius, y + radius, radius); - drawRect(x+radius, y, width - 2*radius, height); - drawCircle(x + width - radius, y + radius, radius); - setColor(BLACK); - fillRect(x+radius, y+1, width - 2*radius + 1, height - 1); + uint16_t xRadius = x + radius; + uint16_t yRadius = y + radius; + uint16_t doubleRadius = 2 * radius; + uint16_t innerRadius = radius - 2; + setColor(WHITE); - uint16_t maxProgressWidth = (width - 2 * radius) * progress / 100; - for (uint16_t i = 0; i < maxProgressWidth; i++) { - fillCircle(x + radius + i, y + radius, innerRadius); - } + drawCircleQuads(xRadius, yRadius, radius, 0b00000110); + drawHorizontalLine(xRadius, y, width - doubleRadius + 1); + drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1); + drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001); + + uint16_t maxProgressWidth = (width - doubleRadius - 1) * progress / 100; + fillCircle(xRadius, yRadius, innerRadius); + fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3); + fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius); } void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *image) { @@ -384,24 +427,24 @@ void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) { // char* text must be freed! char* text = utf8ascii(strUser); - uint16_t xOffset = 0; + uint16_t yOffset = 0; // If the string should be centered vertically too // we need to now how heigh the string is. if (textAlignment == TEXT_ALIGN_CENTER_BOTH) { - uint16_t lb; + uint16_t lb = 0; // Find number of linebreaks in text - for (uint16_t i=0, lb=0; text[i]; i++) { - lb += (text[i] == '\n'); + for (uint16_t i=0;text[i] != 0; i++) { + lb += (text[i] == 10); } // Calculate center - xOffset = (lb * lineHeight) / 2; + yOffset = (lb * lineHeight) / 2; } uint16_t line = 0; char* textPart = strtok(text,"\n"); while (textPart != NULL) { uint16_t length = strlen(textPart); - drawStringInternal(xMove - xOffset, yMove + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length)); + drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length)); textPart = strtok(NULL, "\n"); } free(text); @@ -690,13 +733,13 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt if (yOffset >= 0) { switch (this->color) { case WHITE: buffer[dataPos] |= currentByte << yOffset; break; - case BLACK: buffer[dataPos] &= currentByte << yOffset; break; + case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break; case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break; } if (dataPos < (DISPLAY_BUFFER_SIZE - DISPLAY_WIDTH)) { switch (this->color) { case WHITE: buffer[dataPos + DISPLAY_WIDTH] |= currentByte >> (8 - yOffset); break; - case BLACK: buffer[dataPos + DISPLAY_WIDTH] &= currentByte >> (8 - yOffset); break; + case BLACK: buffer[dataPos + DISPLAY_WIDTH] &= ~(currentByte >> (8 - yOffset)); break; case INVERSE: buffer[dataPos + DISPLAY_WIDTH] ^= currentByte >> (8 - yOffset); break; } } @@ -706,7 +749,7 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt switch (this->color) { case WHITE: buffer[dataPos] |= currentByte >> yOffset; break; - case BLACK: buffer[dataPos] &= currentByte >> yOffset; break; + case BLACK: buffer[dataPos] &= ~(currentByte >> yOffset); break; case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break; } diff --git a/OLEDDisplay.h b/OLEDDisplay.h index f6a27d7d8d07a732931bd2cb489a1b7fc76fdfb3..74bdba1c2e786e0e886ab7c41c66ea3fc6ef5837 100644 --- a/OLEDDisplay.h +++ b/OLEDDisplay.h @@ -139,6 +139,9 @@ class OLEDDisplay : public Print { // Draw the border of a circle void drawCircle(int16_t x, int16_t y, int16_t radius); + // Draw all Quadrants specified in the quads bit mask + void drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads); + // Fill circle void fillCircle(int16_t x, int16_t y, int16_t radius); diff --git a/OLEDDisplayUi.cpp b/OLEDDisplayUi.cpp index 5acc6eedcca015922d1e490c33e2e0565937e0e9..e78744299f6dbd0f6ef7155d6cef43208a0aa886 100644 --- a/OLEDDisplayUi.cpp +++ b/OLEDDisplayUi.cpp @@ -76,6 +76,14 @@ void OLEDDisplayUi::disableIndicator(){ this->state.isIndicatorDrawen = false; } +void OLEDDisplayUi::enableAllIndicators(){ + this->shouldDrawIndicators = true; +} + +void OLEDDisplayUi::disableAllIndicators(){ + this->shouldDrawIndicators = false; +} + void OLEDDisplayUi::setIndicatorPosition(IndicatorPosition pos) { this->indicatorPosition = pos; } @@ -220,7 +228,9 @@ void OLEDDisplayUi::tick() { this->display->clear(); this->drawFrame(); - this->drawIndicator(); + if (shouldDrawIndicators) { + this->drawIndicator(); + } this->drawOverlays(); this->display->display(); } diff --git a/OLEDDisplayUi.h b/OLEDDisplayUi.h index 77c46c75985471c62dde0f798cfece07315c4ed3..617346a3a2ede21c9f09a19a279aa89d4cbe8387 100644 --- a/OLEDDisplayUi.h +++ b/OLEDDisplayUi.h @@ -81,7 +81,7 @@ struct OLEDDisplayUiState { bool isIndicatorDrawen = true; // Normal = 1, Inverse = -1; - int8_t frameTransitionDirection = 1; + int8_t frameTransitionDirection = 1; bool manuelControll = false; @@ -109,6 +109,8 @@ class OLEDDisplayUi { const char* activeSymbol = ANIMATION_activeSymbol; const char* inactiveSymbol = ANIMATION_inactiveSymbol; + bool shouldDrawIndicators = true; + // Values for the Frames AnimationDirection frameAnimationDirection = SLIDE_RIGHT; @@ -215,6 +217,16 @@ class OLEDDisplayUi { */ void disableIndicator(); + /** + * Enable drawing of indicators + */ + void enableAllIndicators(); + + /** + * Disable draw of indicators. + */ + void disableAllIndicators(); + /** * Set the position of the indicator bar. */ diff --git a/README.md b/README.md index 6e60fc63c31e71c3a3b4cee911bb0ee8f9354350..a63d4ba8927a44ce6c8cefc3c36da7584791e66b 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,16 @@ void enableIndicator(); */ void disableIndicator(); +/** + * Enable drawing of indicators + */ +void enableAllIndicator(); + +/** + * Disable drawing of indicators. + */ +void disableAllIndicator(); + /** * Set the position of the indicator bar. */ @@ -375,3 +385,9 @@ This shows how to use define a maximum width after which the driver automaticall  This shows the code working on the SPI version of the display. See demo code for ESP8266 pins used. + +## Project using this library + + * [QRCode ESP8266](https://github.com/anunpanya/ESP8266_QRcode) (by @anunpanya) + * [Scan I2C](https://github.com/hallard/Scan-I2C-WiFi) (by @hallard) + * [Weather Station](https://github.com/squix78/esp8266-weather-station) (by @squix) diff --git a/SH1106Brzo.h b/SH1106Brzo.h index c1a89c474273becc9243547dee542687d9373eaa..385630b3267a7191fe0c81a21fe34d4b5de0a2e4 100644 --- a/SH1106Brzo.h +++ b/SH1106Brzo.h @@ -60,6 +60,8 @@ class SH1106Brzo : public OLEDDisplay { uint8_t minBoundY = ~0; uint8_t maxBoundY = 0; + uint8_t minBoundX = ~0; + uint8_t maxBoundX = 0; uint8_t x, y; // Calculate the Y bounding box of changes @@ -70,6 +72,8 @@ class SH1106Brzo : public OLEDDisplay { if (buffer[pos] != buffer_back[pos]) { minBoundY = _min(minBoundY, y); maxBoundY = _max(maxBoundY, y); + minBoundX = _min(minBoundX, x); + maxBoundX = _max(maxBoundX, x); } buffer_back[pos] = buffer[pos]; } @@ -84,12 +88,18 @@ class SH1106Brzo : public OLEDDisplay { byte k = 0; uint8_t sendBuffer[17]; sendBuffer[0] = 0x40; + + // Calculate the colum offset + uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F; + uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 ); + brzo_i2c_start_transaction(this->_address, BRZO_I2C_SPEED); + for (y = minBoundY; y <= maxBoundY; y++) { sendCommand(0xB0 + y); - sendCommand(0x02); - sendCommand(0x10); - for (x = 0; x < DISPLAY_WIDTH; x++) { + sendCommand(minBoundXp2H); + sendCommand(minBoundXp2L); + for (x = minBoundX; x <= maxBoundX; x++) { k++; sendBuffer[k] = buffer[x + y * DISPLAY_WIDTH]; if (k == 16) { @@ -97,9 +107,15 @@ class SH1106Brzo : public OLEDDisplay { k = 0; } } + if (k != 0) { + brzo_i2c_write(sendBuffer, k + 1, true); + k = 0; + } yield(); } - brzo_i2c_write(sendBuffer, k + 1, true); + if (k != 0) { + brzo_i2c_write(sendBuffer, k + 1, true); + } brzo_i2c_end_transaction(); #else #endif diff --git a/SH1106Spi.h b/SH1106Spi.h new file mode 100644 index 0000000000000000000000000000000000000000..0a64e27568ff9fc1270e13ec0eec221ac9337a67 --- /dev/null +++ b/SH1106Spi.h @@ -0,0 +1,128 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 by Daniel Eichhorn + * Copyright (c) 2016 by Fabrice Weinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing! + */ + +#ifndef SH1106Spi_h +#define SH1106Spi_h + +#include "OLEDDisplay.h" +#include <SPI.h> + +class SH1106Spi : public OLEDDisplay { + private: + uint8_t _rst; + uint8_t _dc; + + public: + + SH1106Spi(uint8_t _rst, uint8_t _dc) { + this->_rst = _rst; + this->_dc = _dc; + } + + bool connect(){ + pinMode(_dc, OUTPUT); + pinMode(_rst, OUTPUT); + + SPI.begin (); + SPI.setClockDivider (SPI_CLOCK_DIV2); + + // Pulse Reset low for 10ms + digitalWrite(_rst, HIGH); + delay(1); + digitalWrite(_rst, LOW); + delay(10); + digitalWrite(_rst, HIGH); + return true; + } + + void display(void) { + #ifdef OLEDDISPLAY_DOUBLE_BUFFER + uint8_t minBoundY = ~0; + uint8_t maxBoundY = 0; + + uint8_t minBoundX = ~0; + uint8_t maxBoundX = 0; + + uint8_t x, y; + + // Calculate the Y bounding box of changes + // and copy buffer[pos] to buffer_back[pos]; + for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) { + for (x = 0; x < DISPLAY_WIDTH; x++) { + uint16_t pos = x + y * DISPLAY_WIDTH; + if (buffer[pos] != buffer_back[pos]) { + minBoundY = _min(minBoundY, y); + maxBoundY = _max(maxBoundY, y); + minBoundX = _min(minBoundX, x); + maxBoundX = _max(maxBoundX, x); + } + buffer_back[pos] = buffer[pos]; + } + yield(); + } + + // If the minBoundY wasn't updated + // we can savely assume that buffer_back[pos] == buffer[pos] + // holdes true for all values of pos + if (minBoundY == ~0) return; + + // Calculate the colum offset + uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F; + uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 ); + + for (y = minBoundY; y <= maxBoundY; y++) { + sendCommand(0xB0 + y); + sendCommand(minBoundXp2H); + sendCommand(minBoundXp2L); + digitalWrite(_dc, HIGH); // data mode + for (x = minBoundX; x <= maxBoundX; x++) { + SPI.transfer(buffer[x + y * DISPLAY_WIDTH]); + } + yield(); + } + #else + for (uint8_t y=0; y<DISPLAY_HEIGHT/8; y++) { + sendCommand(0xB0 + y); + sendCommand(0x02); + sendCommand(0x10); + digitalWrite(_dc, HIGH); // data mode + for( uint8_t x=0; x < DISPLAY_WIDTH; x++) { + SPI.transfer(buffer[x + y * DISPLAY_WIDTH]); + } + yield(); + } + #endif + } + + private: + inline void sendCommand(uint8_t com) __attribute__((always_inline)){ + digitalWrite(_dc, LOW); + SPI.transfer(com); + } +}; + +#endif diff --git a/SH1106Wire.h b/SH1106Wire.h index d885fab38e049b070d0f40e0292292d98c72d391..f0784b9423051a4e91bf2e237b38347a2f6b6ede 100644 --- a/SH1106Wire.h +++ b/SH1106Wire.h @@ -62,6 +62,10 @@ class SH1106Wire : public OLEDDisplay { #ifdef OLEDDISPLAY_DOUBLE_BUFFER uint8_t minBoundY = ~0; uint8_t maxBoundY = 0; + + uint8_t minBoundX = ~0; + uint8_t maxBoundX = 0; + uint8_t x, y; // Calculate the Y bounding box of changes @@ -72,6 +76,8 @@ class SH1106Wire : public OLEDDisplay { if (buffer[pos] != buffer_back[pos]) { minBoundY = _min(minBoundY, y); maxBoundY = _max(maxBoundY, y); + minBoundX = _min(minBoundX, x); + maxBoundX = _max(maxBoundX, x); } buffer_back[pos] = buffer[pos]; } @@ -83,12 +89,16 @@ class SH1106Wire : public OLEDDisplay { // holdes true for all values of pos if (minBoundY == ~0) return; + // Calculate the colum offset + uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F; + uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 ); + byte k = 0; for (y = minBoundY; y <= maxBoundY; y++) { sendCommand(0xB0 + y); - sendCommand(0x02); - sendCommand(0x10); - for (x = 0; x < DISPLAY_WIDTH; x++) { + sendCommand(minBoundXp2H); + sendCommand(minBoundXp2L); + for (x = minBoundX; x <= maxBoundX; x++) { if (k == 0) { Wire.beginTransmission(_address); Wire.write(0x40); @@ -100,6 +110,10 @@ class SH1106Wire : public OLEDDisplay { k = 0; } } + if (k != 0) { + Wire.endTransmission(); + k = 0; + } yield(); } diff --git a/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino b/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino index d9b5c1a4a2849d26c501cec9c306ea9ef41255db..e9db7d645a610f8c42d857ba20a774b2fe9cd89e 100644 --- a/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino +++ b/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino @@ -24,19 +24,21 @@ * */ -#include <Wire.h> #include <TimeLib.h> // Include the correct display library // For a connection via I2C using Wire include #include <Wire.h> // Only needed for Arduino 1.6.5 and earlier #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"` +// or #include "SH1106.h" alis for `#include "SH1106Wire.h"` // For a connection via I2C using brzo_i2c (must be installed) include // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier // #include "SSD1306Brzo.h" +// #include "SH1106Brzo.h" // For a connection via SPI include // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier // #include "SSD1306Spi.h" +// #include "SH1106SPi.h" // Include the UI lib #include "OLEDDisplayUi.h" @@ -53,14 +55,19 @@ // D2 -> DC // D8 -> CS // SSD1306Spi display(D0, D2, D8); +// or +// SH1106Spi display(D0, D2); // Initialize the OLED display using brzo_i2c // D3 -> SDA -// D4 -> SCL +// D5 -> SCL // SSD1306Brzo display(0x3c, D3, D5); +// or +// SH1106Brzo display(0x3c, D3, D5); // Initialize the OLED display using Wire library SSD1306 display(0x3c, D3, D5); +// SH1106 display(0x3c, D3, D5); OLEDDisplayUi ui ( &display ); diff --git a/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino b/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino new file mode 100644 index 0000000000000000000000000000000000000000..cf37fb0412002492388ed3d71fbb1ec58866c233 --- /dev/null +++ b/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino @@ -0,0 +1,229 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 by Daniel Eichhorn + * Copyright (c) 2016 by Fabrice Weinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + + // Include the correct display library + // For a connection via I2C using Wire include + #include <Wire.h> // Only needed for Arduino 1.6.5 and earlier + #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"` + // or #include "SH1106.h" alis for `#include "SH1106Wire.h"` + // For a connection via I2C using brzo_i2c (must be installed) include + // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier + // #include "SSD1306Brzo.h" + // #include "SH1106Brzo.h" + // For a connection via SPI include + // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier + // #include "SSD1306Spi.h" + // #include "SH1106SPi.h" + + // Use the corresponding display class: + + // Initialize the OLED display using SPI + // D5 -> CLK + // D7 -> MOSI (DOUT) + // D0 -> RES + // D2 -> DC + // D8 -> CS + // SSD1306Spi display(D0, D2, D8); + // or + // SH1106Spi display(D0, D2); + + // Initialize the OLED display using brzo_i2c + // D3 -> SDA + // D5 -> SCL + // SSD1306Brzo display(0x3c, D3, D5); + // or + // SH1106Brzo display(0x3c, D3, D5); + + // Initialize the OLED display using Wire library + SSD1306 display(0x3c, D3, D5); + // SH1106 display(0x3c, D3, D5); + +// Adapted from Adafruit_SSD1306 +void drawLines() { + for (int16_t i=0; i<DISPLAY_WIDTH; i+=4) { + display.drawLine(0, 0, i, DISPLAY_HEIGHT-1); + display.display(); + delay(10); + } + for (int16_t i=0; i<DISPLAY_HEIGHT; i+=4) { + display.drawLine(0, 0, DISPLAY_WIDTH-1, i); + display.display(); + delay(10); + } + delay(250); + + display.clear(); + for (int16_t i=0; i<DISPLAY_WIDTH; i+=4) { + display.drawLine(0, DISPLAY_HEIGHT-1, i, 0); + display.display(); + delay(10); + } + for (int16_t i=DISPLAY_HEIGHT-1; i>=0; i-=4) { + display.drawLine(0, DISPLAY_HEIGHT-1, DISPLAY_WIDTH-1, i); + display.display(); + delay(10); + } + delay(250); + + display.clear(); + for (int16_t i=DISPLAY_WIDTH-1; i>=0; i-=4) { + display.drawLine(DISPLAY_WIDTH-1, DISPLAY_HEIGHT-1, i, 0); + display.display(); + delay(10); + } + for (int16_t i=DISPLAY_HEIGHT-1; i>=0; i-=4) { + display.drawLine(DISPLAY_WIDTH-1, DISPLAY_HEIGHT-1, 0, i); + display.display(); + delay(10); + } + delay(250); + display.clear(); + for (int16_t i=0; i<DISPLAY_HEIGHT; i+=4) { + display.drawLine(DISPLAY_WIDTH-1, 0, 0, i); + display.display(); + delay(10); + } + for (int16_t i=0; i<DISPLAY_WIDTH; i+=4) { + display.drawLine(DISPLAY_WIDTH-1, 0, i, DISPLAY_HEIGHT-1); + display.display(); + delay(10); + } + delay(250); +} + +// Adapted from Adafruit_SSD1306 +void drawRect(void) { + for (int16_t i=0; i<DISPLAY_HEIGHT/2; i+=2) { + display.drawRect(i, i, DISPLAY_WIDTH-2*i, DISPLAY_HEIGHT-2*i); + display.display(); + delay(10); + } +} + +// Adapted from Adafruit_SSD1306 +void fillRect(void) { + uint8_t color = 1; + for (int16_t i=0; i<DISPLAY_HEIGHT/2; i+=3) { + display.setColor((color % 2 == 0) ? BLACK : WHITE); // alternate colors + display.fillRect(i, i, DISPLAY_WIDTH - i*2, DISPLAY_HEIGHT - i*2); + display.display(); + delay(10); + color++; + } + // Reset back to WHITE + display.setColor(WHITE); +} + +// Adapted from Adafruit_SSD1306 +void drawCircle(void) { + for (int16_t i=0; i<DISPLAY_HEIGHT; i+=2) { + display.drawCircle(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, i); + display.display(); + delay(10); + } + delay(1000); + display.clear(); + + // This will draw the part of the circel in quadrant 1 + // Quadrants are numberd like this: + // 0010 | 0001 + // ------|----- + // 0100 | 1000 + // + display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00000001); + display.display(); + delay(200); + display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00000011); + display.display(); + delay(200); + display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00000111); + display.display(); + delay(200); + display.drawCircleQuads(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, DISPLAY_HEIGHT/4, 0b00001111); + display.display(); +} + +void printBuffer(void) { + // Initialize the log buffer + // allocate memory to store 8 lines of text and 30 chars per line. + display.setLogBuffer(5, 30); + + // Some test data + const char* test[] = { + "Hello", + "World" , + "----", + "Show off", + "how", + "the log buffer", + "is", + "working.", + "Even", + "scrolling is", + "working" + }; + + for (uint8_t i = 0; i < 11; i++) { + display.clear(); + // Print to the screen + display.println(test[i]); + // Draw it to the internal screen buffer + display.drawLogBuffer(0, 0); + // Display it on the screen + display.display(); + delay(500); + } +} + +void setup() { + display.init(); + + // display.flipScreenVertically(); + + display.setContrast(255); + + drawLines(); + delay(1000); + display.clear(); + + drawRect(); + delay(1000); + display.clear(); + + fillRect(); + delay(1000); + display.clear(); + + drawCircle(); + delay(1000); + display.clear(); + + printBuffer(); + delay(1000); + display.clear(); +} + +void loop() { } diff --git a/examples/SSD1306OTADemo/SSD1306OTADemo.ino b/examples/SSD1306OTADemo/SSD1306OTADemo.ino new file mode 100644 index 0000000000000000000000000000000000000000..6460ff9e4a308dffa396d0db473c6708e0c14f34 --- /dev/null +++ b/examples/SSD1306OTADemo/SSD1306OTADemo.ino @@ -0,0 +1,119 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 by Daniel Eichhorn + * Copyright (c) 2016 by Fabrice Weinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +// WiFi includes + #include <ESP8266WiFi.h> + + // OTA Includes + #include <ESP8266mDNS.h> + #include <ArduinoOTA.h> + + const char *ssid = "[Your SSID]"; + const char *password = "[Your Password]"; + + +// Include the correct display library +// For a connection via I2C using Wire include +#include <Wire.h> // Only needed for Arduino 1.6.5 and earlier +#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"` +// or #include "SH1106.h" alis for `#include "SH1106Wire.h"` +// For a connection via I2C using brzo_i2c (must be installed) include +// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier +// #include "SSD1306Brzo.h" +// #include "SH1106Brzo.h" +// For a connection via SPI include +// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier +// #include "SSD1306Spi.h" +// #include "SH1106SPi.h" + +// Use the corresponding display class: + +// Initialize the OLED display using SPI +// D5 -> CLK +// D7 -> MOSI (DOUT) +// D0 -> RES +// D2 -> DC +// D8 -> CS +// SSD1306Spi display(D0, D2, D8); +// or +// SH1106Spi display(D0, D2); + +// Initialize the OLED display using brzo_i2c +// D3 -> SDA +// D5 -> SCL +// SSD1306Brzo display(0x3c, D3, D5); +// or +// SH1106Brzo display(0x3c, D3, D5); + +// Initialize the OLED display using Wire library +SSD1306 display(0x3c, D3, D5); +// SH1106 display(0x3c, D3, D5); + + +void setup() { + WiFi.begin ( ssid, password ); + + // Wait for connection + while ( WiFi.status() != WL_CONNECTED ) { + delay ( 10 ); + } + + display.init(); + display.flipScreenVertically(); + display.setContrast(255); + + ArduinoOTA.begin(); + ArduinoOTA.onStart([]() { + display.clear(); + display.setFont(ArialMT_Plain_10); + display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH); + display.drawString(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2 - 10, "OTA Update"); + display.display(); + }); + + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + display.drawProgressBar(4, 32, 120, 8, progress / (total / 100) ); + display.display(); + }); + + ArduinoOTA.onEnd([]() { + display.clear(); + display.setFont(ArialMT_Plain_10); + display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH); + display.drawString(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, "Restart"); + display.display(); + }); + + // Align text vertical/horizontal center + display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH); + display.setFont(ArialMT_Plain_10); + display.drawString(DISPLAY_WIDTH/2, DISPLAY_HEIGHT/2, "Ready for OTA:\n" + WiFi.localIP().toString()); + display.display(); +} + +void loop() { + ArduinoOTA.handle(); +} diff --git a/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino b/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino index 97594b95c3808ff30e459798a05e77f17fd557f5..ed7401915861f89d9a1f4dd6f697bc82b44f3069 100644 --- a/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino +++ b/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino @@ -23,24 +23,23 @@ * */ -#include <Wire.h> - // Include the correct display library // For a connection via I2C using Wire include #include <Wire.h> // Only needed for Arduino 1.6.5 and earlier #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"` +// or #include "SH1106.h" alis for `#include "SH1106Wire.h"` // For a connection via I2C using brzo_i2c (must be installed) include // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier // #include "SSD1306Brzo.h" +// #include "SH1106Brzo.h" // For a connection via SPI include // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier // #include "SSD1306Spi.h" +// #include "SH1106SPi.h" // Include custom images #include "images.h" -// Use the corresponding display class: - // Initialize the OLED display using SPI // D5 -> CLK // D7 -> MOSI (DOUT) @@ -48,14 +47,19 @@ // D2 -> DC // D8 -> CS // SSD1306Spi display(D0, D2, D8); +// or +// SH1106Spi display(D0, D2); // Initialize the OLED display using brzo_i2c // D3 -> SDA -// D4 -> SCL +// D5 -> SCL // SSD1306Brzo display(0x3c, D3, D5); +// or +// SH1106Brzo display(0x3c, D3, D5); // Initialize the OLED display using Wire library SSD1306 display(0x3c, D3, D5); +// SH1106 display(0x3c, D3, D5); #define DEMO_DURATION 3000 diff --git a/examples/SSD1306UiDemo/SSD1306UiDemo.ino b/examples/SSD1306UiDemo/SSD1306UiDemo.ino index a51c57c6380a05785badda4d4dfc39dd90570502..31357569ff3849b6c1098165aa96f9880129327f 100644 --- a/examples/SSD1306UiDemo/SSD1306UiDemo.ino +++ b/examples/SSD1306UiDemo/SSD1306UiDemo.ino @@ -24,18 +24,19 @@ * */ -#include <Wire.h> - -// Include the correct display library -// For a connection via I2C using Wire include -#include <Wire.h> // Only needed for Arduino 1.6.5 and earlier -#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"` -// For a connection via I2C using brzo_i2c (must be installed) include -// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier -// #include "SSD1306Brzo.h" -// For a connection via SPI include -// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier -// #include "SSD1306Spi.h" + // Include the correct display library + // For a connection via I2C using Wire include + #include <Wire.h> // Only needed for Arduino 1.6.5 and earlier + #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"` + // or #include "SH1106.h" alis for `#include "SH1106Wire.h"` + // For a connection via I2C using brzo_i2c (must be installed) include + // #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier + // #include "SSD1306Brzo.h" + // #include "SH1106Brzo.h" + // For a connection via SPI include + // #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier + // #include "SSD1306Spi.h" + // #include "SH1106SPi.h" // Include the UI lib #include "OLEDDisplayUi.h" @@ -52,14 +53,19 @@ // D2 -> DC // D8 -> CS // SSD1306Spi display(D0, D2, D8); +// or +// SH1106Spi display(D0, D2); // Initialize the OLED display using brzo_i2c // D3 -> SDA -// D4 -> SCL +// D5 -> SCL // SSD1306Brzo display(0x3c, D3, D5); +// or +// SH1106Brzo display(0x3c, D3, D5); // Initialize the OLED display using Wire library SSD1306 display(0x3c, D3, D5); +// SH1106 display(0x3c, D3, D5); OLEDDisplayUi ui ( &display );