diff --git a/SSD1306.cpp b/SSD1306.cpp index b103f7612e426b554a4e193faf25abc7b546e829..0b4189075a71843f09596f282c197456d83a45bd 100644 --- a/SSD1306.cpp +++ b/SSD1306.cpp @@ -109,6 +109,44 @@ void SSD1306::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t heig } } +void SSD1306::drawCircle(int16_t x0, int16_t y0, int16_t radius) { + int16_t x = 0, y = radius; + int16_t dp = 1 - radius; + do { + if (dp < 0) + dp = dp + 2 * (++x) + 3; + else + dp = dp + 2 * (++x) - 2 * (--y) + 5; + + setPixel(x0 + x, y0 + y); //For the 8 octants + setPixel(x0 - x, y0 + y); + setPixel(x0 + x, y0 - y); + setPixel(x0 - x, y0 - y); + setPixel(x0 + y, y0 + x); + setPixel(x0 - y, y0 + x); + setPixel(x0 + y, y0 - x); + setPixel(x0 - y, y0 - x); + + } while (x < y); + + setPixel(x0 + radius, y0); + setPixel(x0, y0 + radius); + setPixel(x0 - radius, y0); + setPixel(x0, y0 - radius); +} + +void SSD1306::fillCircle(int16_t x, int16_t y, int16_t radius) { + int sqrRadius = radius * radius; + for (int xv = -radius; xv < radius; xv++) { + for (int yv = -radius; yv < radius; yv++) { + int currentSqrRadius = xv * xv + yv * yv; + if (currentSqrRadius <= sqrRadius) { + setPixel(x + xv, y + yv); + } + } + } +} + void SSD1306::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { if (y < 0 || y >= DISPLAY_HEIGHT) { return; } @@ -211,6 +249,23 @@ void SSD1306::drawVerticalLine(int16_t x, int16_t y, int16_t length) { } } +void SSD1306::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); + 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); + } + +} + void SSD1306::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *image) { drawInternal(xMove, yMove, width, height, image, 0, 0); } diff --git a/SSD1306.h b/SSD1306.h index 76a5b31f0b748d30e4c239373b4684b7b545fdd6..84cb5a9918654fda16e88045b207a085235da734 100644 --- a/SSD1306.h +++ b/SSD1306.h @@ -166,12 +166,23 @@ class SSD1306 { // Fill the rectangle void fillRect(int16_t x, int16_t y, int16_t width, int16_t height); + // Draw the border of a circle + void drawCircle(int16_t x, int16_t y, int16_t radius); + + // Fill circle + void fillCircle(int16_t x, int16_t y, int16_t radius); + // Draw a line horizontally void drawHorizontalLine(int16_t x, int16_t y, int16_t length); // Draw a lin vertically void drawVerticalLine(int16_t x, int16_t y, int16_t length); + /** + * Draws a rounded progress bar with the outer dimensions given by width and height. + */ + void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress); + // Draw a bitmap in the internal image format void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const char *image); diff --git a/SSD1306Ui.cpp b/SSD1306Ui.cpp index 44cc87f8792f6bc9287ed3b552490bb7ec65d839..36b46aa129e836f96bedec98e2956bff829bcb5b 100644 --- a/SSD1306Ui.cpp +++ b/SSD1306Ui.cpp @@ -89,7 +89,6 @@ void SSD1306Ui::setInactiveSymbol(const char* symbol) { this->inactiveSymbol = symbol; } - // -/----- Frame settings -----\- void SSD1306Ui::setFrameAnimation(AnimationDirection dir) { this->frameAnimationDirection = dir; diff --git a/SSD1306Ui.h b/SSD1306Ui.h index bdf218fd4e9c2e79dfcc68b9431d85c03ec6547c..690e37e860e37e37dad644cb10d8e2db91ba9161 100644 --- a/SSD1306Ui.h +++ b/SSD1306Ui.h @@ -231,7 +231,6 @@ class SSD1306Ui { */ void setInactiveSymbol(const char* symbol); - // Frame settings /** diff --git a/examples/SSD1306Demo/SSD1306Demo.ino b/examples/SSD1306Demo/SSD1306Demo.ino index 68dcc667dcb4b1b5bf398a18f5527740ee34f046..604dab144699ffe921d0c8f3c55ad8c17a5fa299 100644 --- a/examples/SSD1306Demo/SSD1306Demo.ino +++ b/examples/SSD1306Demo/SSD1306Demo.ino @@ -33,12 +33,71 @@ SSD1306 display(0x3c, D3, D4); SSD1306Ui ui ( &display ); + +void msOverlay(SSD1306 *display, SSD1306UiState* state) { + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->setFont(ArialMT_Plain_10); + display->drawString(128, 0, String(millis())); +} + +void drawFrame1(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { + // draw an xbm image. + // Please note that everything that should be transitioned + // needs to be drawn relative to x and y + + display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits); +} + +void drawFrame2(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { + // Demonstrates the 3 included default sizes. The fonts come from SSD1306Fonts.h file + // Besides the default fonts there will be a program to convert TrueType fonts into this format + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_10); + display->drawString(0 + x, 10 + y, "Arial 10"); + + display->setFont(ArialMT_Plain_16); + display->drawString(0 + x, 20 + y, "Arial 16"); + + display->setFont(ArialMT_Plain_24); + display->drawString(0 + x, 34 + y, "Arial 24"); +} + +void drawFrame3(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { + // Text alignment demo + display->setFont(ArialMT_Plain_10); + + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(0 + x, 11 + y, "Left aligned (0,10)"); + + // The coordinates define the center of the text + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 22 + y, "Center aligned (64,22)"); + + // The coordinates define the right end of the text + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(128 + x, 33 + y, "Right aligned (128,33)"); +} + +void drawFrame4(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { + // Demo for drawStringMaxWidth: + // with the third parameter you can define the width after which words will be wrapped. + // Currently only spaces and "-" are allowed for wrapping + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_10); + display->drawStringMaxWidth(0 + x, 10 + y, 128, "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore."); +} + +void drawFrame5(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { + +} + // This array keeps function pointers to all frames // frames are the single views that slide in -FrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4 }; +FrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4, drawFrame5 }; // how many frames are there? -int frameCount = 4; +int frameCount = 5; // Overlays are statically drawn on top of a frame eg. a clock OverlayCallback overlays[] = { msOverlay }; @@ -80,8 +139,12 @@ void setup() { display.flipScreenVertically(); + + + } + void loop() { int remainingTimeBudget = ui.update(); @@ -90,59 +153,9 @@ void loop() { // Don't do stuff if you are below your // time budget. delay(remainingTimeBudget); - } -} - -void msOverlay(SSD1306 *display, SSD1306UiState* state) { - display->setTextAlignment(TEXT_ALIGN_RIGHT); - display->setFont(ArialMT_Plain_10); - display->drawString(128, 0, String(millis())); -} - -void drawFrame1(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { - // draw an xbm image. - // Please note that everything that should be transitioned - // needs to be drawn relative to x and y - - display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits); -} - -void drawFrame2(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { - // Demonstrates the 3 included default sizes. The fonts come from SSD1306Fonts.h file - // Besides the default fonts there will be a program to convert TrueType fonts into this format - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_10); - display->drawString(0 + x, 10 + y, "Arial 10"); - - display->setFont(ArialMT_Plain_16); - display->drawString(0 + x, 20 + y, "Arial 16"); - - display->setFont(ArialMT_Plain_24); - display->drawString(0 + x, 34 + y, "Arial 24"); -} - -void drawFrame3(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { - // Text alignment demo - display->setFont(ArialMT_Plain_10); - // The coordinates define the left starting point of the text - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->drawString(0 + x, 11 + y, "Left aligned (0,10)"); + } - // The coordinates define the center of the text - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->drawString(64 + x, 22 + y, "Center aligned (64,22)"); - // The coordinates define the right end of the text - display->setTextAlignment(TEXT_ALIGN_RIGHT); - display->drawString(128 + x, 33 + y, "Right aligned (128,33)"); } -void drawFrame4(SSD1306 *display, SSD1306UiState* state, int16_t x, int16_t y) { - // Demo for drawStringMaxWidth: - // with the third parameter you can define the width after which words will be wrapped. - // Currently only spaces and "-" are allowed for wrapping - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_10); - display->drawStringMaxWidth(0 + x, 10 + y, 128, "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore."); -} diff --git a/examples/SimpleSSD1306Demo/SimpleSSD1306Demo.ino b/examples/SimpleSSD1306Demo/SimpleSSD1306Demo.ino new file mode 100644 index 0000000000000000000000000000000000000000..6549183844badef7c386678bf6eabf7c4f0e212b --- /dev/null +++ b/examples/SimpleSSD1306Demo/SimpleSSD1306Demo.ino @@ -0,0 +1,146 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 by Daniel Eichhorn + * + * 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 <Wire.h> +#include "SSD1306.h" +#include "images.h" + +#define DEMO_SPEED 500 +#define NUMBER_OF_DEMOS 5 +typedef void (*Demo)(void); + +// Initialize the OLED display on address 0x3c +// D3 and D4 are the pin names on the NodeMCU. Change to int values +// if get compilation errors +SSD1306 display(0x3c, D3, D4); + + +int demoMode = 0; +int counter = 1; + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.println(); + + + // Initialising the UI will init the display too. + display.init(); + + display.flipScreenVertically(); + display.setFont(ArialMT_Plain_10); + +} + +void fontFaceDemo() { + // Font Demo1 + // create more fonts at http://oleddisplay.squix.ch/ + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setFont(ArialMT_Plain_10); + display.drawString(0, 0, "Hello world"); + display.setFont(ArialMT_Plain_16); + display.drawString(0, 10, "Hello world"); + display.setFont(ArialMT_Plain_24); + display.drawString(0, 26, "Hello world"); +} + +void textFlowDemo() { + display.setFont(ArialMT_Plain_10); + display.drawStringMaxWidth(0, 0, 128, + "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore." ); +} + +void textAlignmentDemo() { + // Text alignment demo + display.setFont(ArialMT_Plain_10); + + // The coordinates define the left starting point of the text + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawString(0, 10, "Left aligned (0,10)"); + + // The coordinates define the center of the text + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.drawString(64, 22, "Center aligned (64,22)"); + + // The coordinates define the right end of the text + display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.drawString(128, 33, "Right aligned (128,33)"); +} + +void drawRectDemo() { + // Draw a pixel at given position + for (int i = 0; i < 10; i++) { + display.setPixel(i, i); + display.setPixel(10 - i, i); + } + display.drawRect(12, 12, 20, 20); + + // Fill the rectangle + display.fillRect(14, 14, 17, 17); + + // Draw a line horizontally + display.drawHorizontalLine(0, 40, 20); + + // Draw a line horizontally + display.drawVerticalLine(40, 0, 20); + + // this demo is too fast otherwise + delay(10); +} + +void circleDemo() { + for (int i=1; i < 8; i++) { + display.setColor(WHITE); + display.drawCircle(32, 32, i*3); + if (i % 2 == 0) { + display.setColor(BLACK); + } + display.fillCircle(96, 32, 32 - i* 3); + } + delay(25); +} + +void progressBarDemo() { + display.drawProgressBar(0, 32, 120, 16, (counter / 5) % 100); +} + +Demo demos[] = {progressBarDemo, /*fontFaceDemo, textFlowDemo, textAlignmentDemo, drawRectDemo, circleDemo*/}; +int demoLength = (sizeof(demos) / sizeof(Demo)); + +void loop() { + // clear the display + display.clear(); + // draw the current demo method + demos[demoMode](); + // write the buffer to the display + display.display(); + + if (counter % DEMO_SPEED == 0) { + demoMode = (demoMode + 1) % demoLength; + Serial.println(String(counter) + ": " + String(demoMode)); + } + counter++; +} + diff --git a/examples/SimpleSSD1306Demo/images.h b/examples/SimpleSSD1306Demo/images.h new file mode 100644 index 0000000000000000000000000000000000000000..8b876a369e6f2609700798da9da47431e5e0db21 --- /dev/null +++ b/examples/SimpleSSD1306Demo/images.h @@ -0,0 +1,50 @@ +#define WiFi_Logo_width 60 +#define WiFi_Logo_height 36 +const char WiFi_Logo_bits[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF, + 0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00, + 0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C, + 0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00, + 0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C, + 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00, + 0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, + 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, + 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C, + 0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00, + 0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F, + 0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00, + 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF, + 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + +const char activeSymbol[] PROGMEM = { + B00000000, + B00000000, + B00011000, + B00100100, + B01000010, + B01000010, + B00100100, + B00011000 +}; + +const char inactiveSymbol[] PROGMEM = { + B00000000, + B00000000, + B00000000, + B00000000, + B00011000, + B00011000, + B00000000, + B00000000 +};