Skip to content
Snippets Groups Projects
Commit cd87e284 authored by Fabrice Weinberg's avatar Fabrice Weinberg
Browse files

Merge remote-tracking branch 'squix78/master'

* squix78/master:
  Merge with update stream
  Update sample to use extended UI
  Refactor Ui into separate class
  Remove Ui related function from core
parents 49dcafda ef64c27b
No related branches found
No related tags found
No related merge requests found
#include "SSD1306Ui.h"
SSD1306Ui::SSD1306Ui(SSD1306 *display) {
this->display = display;
}
void SSD1306Ui::init() {
this->display->init();
}
void SSD1306Ui::setTargetFPS(byte fps){
this->updateInterval = ((float) 1.0 / (float) fps) * 1000;
Serial.println(this->updateInterval);
}
// -/------ Automatic controll ------\-
void SSD1306Ui::enableAutoTransition(){
autoTransition = true;
}
void SSD1306Ui::disableAutoTransition(){
autoTransition = false;
}
void SSD1306Ui::setAutoTransitionForwards(){
this->frameTransitionDirection = 1;
}
void SSD1306Ui::setAutoTransitionBackwards(){
this->frameTransitionDirection = 1;
}
void SSD1306Ui::setTimePerFrame(int time){
this->ticksPerFrame = (int) ( (float) time / (float) updateInterval);
}
void SSD1306Ui::setTimePerTransition(int time){
this->ticksPerTransition = (int) ( (float) time / (float) updateInterval);
}
// -/------ Customize indicator position and style -------\-
void SSD1306Ui::setIndicatorPosition(IndicatorPosition pos) {
this->indicatorPosition = pos;
this->dirty = true;
}
void SSD1306Ui::setIndicatorDirection(IndicatorDirection dir) {
this->indicatorDirection = dir;
}
void SSD1306Ui::setActiveSymbole(const char* symbole) {
this->activeSymbole = symbole;
this->dirty = true;
}
void SSD1306Ui::setInactiveSymbole(const char* symbole) {
this->inactiveSymbole = symbole;
this->dirty = true;
}
// -/----- Frame settings -----\-
void SSD1306Ui::setFrameAnimation(AnimationDirection dir) {
this->frameAnimationDirection = dir;
}
void SSD1306Ui::setFrames(bool (*frameFunctions[])(SSD1306 *display, int x, int y), int frameCount) {
this->frameCount = frameCount;
this->frameFunctions = frameFunctions;
}
// -/----- Overlays ------\-
void SSD1306Ui::setOverlays(bool (*overlayFunctions[])(SSD1306 *display), int overlayCount){
this->overlayCount = overlayCount;
this->overlayFunctions = overlayFunctions;
}
// -/----- Manuel control -----\-
void SSD1306Ui::nextFrame() {
this->frameState = IN_TRANSITION;
this->ticksSinceLastStateSwitch = 0;
this->frameTransitionDirection = 1;
}
void SSD1306Ui::previousFrame() {
this->frameState = IN_TRANSITION;
this->ticksSinceLastStateSwitch = 0;
this->frameTransitionDirection = -1;
}
// -/----- State information -----\-
FrameState SSD1306Ui::getFrameState(){
return this->frameState;
}
int SSD1306Ui::getCurrentFrame(){
return this->currentFrame;
}
int SSD1306Ui::update(){
int timeBudget = this->updateInterval - (millis() - this->lastUpdate);
if ( timeBudget <= 0) {
// Implement frame skipping to ensure time budget is keept
if (this->autoTransition && this->lastUpdate != 0) this->ticksSinceLastStateSwitch += abs(timeBudget) / this->updateInterval;
this->lastUpdate = millis();
this->tick();
}
return timeBudget;
}
void SSD1306Ui::tick() {
this->ticksSinceLastStateSwitch++;
switch (this->frameState) {
case IN_TRANSITION:
this->dirty = true;
if (this->ticksSinceLastStateSwitch >= this->ticksPerTransition){
this->frameState = FIXED;
this->currentFrame = getNextFrameNumber();
this->ticksSinceLastStateSwitch = 0;
}
break;
case FIXED:
if (this->ticksSinceLastStateSwitch >= this->ticksPerFrame){
if (this->autoTransition){
this->frameState = IN_TRANSITION;
this->dirty = true;
}
this->ticksSinceLastStateSwitch = 0;
}
break;
}
if (this->dirty) {
this->dirty = false;
this->display->clear();
this->drawIndicator();
this->drawFrame();
this->drawOverlays();
this->display->display();
}
}
void SSD1306Ui::drawFrame(){
switch (this->frameState){
case IN_TRANSITION: {
float progress = (float) this->ticksSinceLastStateSwitch / (float) this->ticksPerTransition;
int x, y, x1, y1;
switch(this->frameAnimationDirection){
case SLIDE_LEFT:
x = -128 * progress;
y = 0;
x1 = x + 128;
y1 = 0;
break;
case SLIDE_RIGHT:
x = 128 * progress;
y = 0;
x1 = x - 128;
y1 = 0;
break;
case SLIDE_UP:
x = 0;
y = -64 * progress;
x1 = 0;
y1 = y + 64;
break;
case SLIDE_DOWN:
x = 0;
y = 64 * progress;
x1 = 0;
y1 = y - 64;
break;
}
// Invert animation if direction is reversed.
int dir = frameTransitionDirection >= 0 ? 1 : -1;
x *= dir; y *= dir; x1 *= dir; y1 *= dir;
this->dirty |= (*this->frameFunctions[this->currentFrame])(this->display, x, y);
this->dirty |= (*this->frameFunctions[this->getNextFrameNumber()])(this->display, x1, y1);
break;
}
case FIXED:
this->dirty |= (*this->frameFunctions[this->currentFrame])(this->display, 0, 0);
break;
}
}
void SSD1306Ui::drawIndicator() {
byte posOfCurrentFrame;
switch (this->indicatorDirection){
case LEFT_RIGHT:
posOfCurrentFrame = this->currentFrame;
break;
case RIGHT_LEFT:
posOfCurrentFrame = (this->frameCount - 1) - this->currentFrame;
break;
}
for (byte i = 0; i < this->frameCount; i++) {
const char *xbm;
if (posOfCurrentFrame == i) {
xbm = this->activeSymbole;
} else {
xbm = this->inactiveSymbole;
}
int x,y;
switch (this->indicatorPosition){
case TOP:
y = 0;
x = 64 - (12 * frameCount / 2) + 12 * i;
break;
case BOTTOM:
y = 56;
x = 64 - (12 * frameCount / 2) + 12 * i;
break;
case RIGHT:
x = 120;
y = 32 - (12 * frameCount / 2) + 12 * i;
break;
case LEFT:
x = 0;
y = 32 - (12 * frameCount / 2) + 12 * i;
break;
}
this->display->drawXbm(x, y, 8, 8, xbm);
}
}
void SSD1306Ui::drawOverlays() {
for (int i=0;i<this->overlayCount;i++){
this->dirty |= (*this->overlayFunctions[i])(this->display);
}
}
int SSD1306Ui::getNextFrameNumber(){
int nextFrame = (this->currentFrame + this->frameTransitionDirection) % this->frameCount;
if (nextFrame < 0){
nextFrame = this->frameCount + nextFrame;
}
return nextFrame;
}
/**The MIT License (MIT)
Copyright (c) 2015 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 Daniel Eichhorn
*/
#pragma once
#include <Arduino.h>
#include "ssd1306_i2c.h"
enum AnimationDirection {
SLIDE_UP,
SLIDE_DOWN,
SLIDE_LEFT,
SLIDE_RIGHT
};
enum IndicatorPosition {
TOP,
RIGHT,
BOTTOM,
LEFT
};
enum IndicatorDirection {
LEFT_RIGHT,
RIGHT_LEFT
};
enum FrameState {
IN_TRANSITION,
FIXED
};
const char ANIMATION_activeSymbole[] PROGMEM = {
0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00
};
const char ANIMATION_inactiveSymbole[] PROGMEM = {
0x00, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x00
};
class SSD1306Ui {
private:
SSD1306 *display;
// Global dirty flag to indicate that the display needs to be redraw.
bool dirty = true;
// Symboles for the Indicator
IndicatorPosition indicatorPosition = BOTTOM;
IndicatorDirection indicatorDirection = LEFT_RIGHT;
const char* activeSymbole = ANIMATION_activeSymbole;
const char* inactiveSymbole = ANIMATION_inactiveSymbole;
// Values for the Frames
AnimationDirection frameAnimationDirection = SLIDE_RIGHT;
FrameState frameState = FIXED;
int frameTransitionDirection = 1;
int ticksPerFrame = 313; // ~ 5000ms at 60 FPS
int ticksPerTransition = 32; // ~ 500ms at 60 FPS
int ticksSinceLastStateSwitch = 0;
int currentFrame = 0;
bool autoTransition = true;
bool (**frameFunctions)(SSD1306 *display, int x, int y);
int frameCount = 0;
// Values for Overlays
bool (**overlayFunctions)(SSD1306 *display);
int overlayCount = 0;
// Bookeeping for update
int updateInterval = 16;
unsigned long lastUpdate = 0;
int getNextFrameNumber();
void drawIndicator();
void drawFrame();
void drawOverlays();
void tick();
public:
SSD1306Ui(SSD1306 *display);
/**
* Initialise the display
*/
void init();
/**
* Configure the internal used target FPS
*/
void setTargetFPS(byte fps);
// Automatic Controll
/**
* Enable automatic transition to next frame after the some time can be configured with `setTimePerFrame` and `setTimePerTransition`.
*/
void enableAutoTransition();
/**
* Disable automatic transition to next frame.
*/
void disableAutoTransition();
/**
* Set the direction if the automatic transitioning
*/
void setAutoTransitionForwards();
void setAutoTransitionBackwards();
/**
* Set the approx. time a frame is displayed
*/
void setTimePerFrame(int time);
/**
* Set the approx. time a transition will take
*/
void setTimePerTransition(int time);
// Customize Indicator Position and style
/**
* Set the position of the indicator bar.
*/
void setIndicatorPosition(IndicatorPosition pos);
/**
* Set the direction of the indicator bar. Defining the order of frames ASCENDING / DESCENDING
*/
void setIndicatorDirection(IndicatorDirection dir);
/**
* Set the symbole to indicate an active frame in the indicator bar.
*/
void setActiveSymbole(const char* symbole);
/**
* Set the symbole to indicate an inactive frame in the indicator bar.
*/
void setInactiveSymbole(const char* symbole);
// Frame settings
/**
* Configure what animation is used to transition from one frame to another
*/
void setFrameAnimation(AnimationDirection dir);
/**
* Add frame drawing functions
*/
void setFrames(bool (*frameFunctions[])(SSD1306 *display, int x, int y), int frameCount);
// Overlay
/**
* Add overlays drawing functions that are draw independent of the Frames
*/
void setOverlays(bool (*overlayFunctions[])(SSD1306 *display), int overlayCount);
// Manuell Controll
void nextFrame();
void previousFrame();
// State Info
FrameState getFrameState();
int getCurrentFrame();
int update();
};
#include <ArduinoJson.h>
/**The MIT License (MIT)
Copyright (c) 2015 by Daniel Eichhorn
......@@ -26,6 +24,7 @@ See more at http://blog.squix.ch
*/
#include <Wire.h>
#include "ssd1306_i2c.h"
#include "SSD1306Ui.h"
#include "images.h"
// if you are using a ESP8266 module with NodeMCU
......@@ -48,105 +47,125 @@ See more at http://blog.squix.ch
// Initialize the oled display for address 0x3c
// sda-pin=14 and sdc-pin=12
SSD1306 display(0x3c, NODEMCU_D6, NODEMCU_D5);
SSD1306 display(0x3c, NODEMCU_D6, NODEMCU_D5);
SSD1306Ui ui ( &display );
// this array keeps function pointers to all frames
// frames are the single views that slide from right to left
void (*frameCallbacks[])(int x, int y) = {drawFrame1, drawFrame2, drawFrame3, drawFrame4};
bool (*frames[])(SSD1306 *display, int x, int y) = { drawFrame1, drawFrame2, drawFrame3, drawFrame4 };
// how many frames are there?
int frameCount = 4;
bool (*overlays[])(SSD1306 *display) = { msOverlay };
int overlaysCount = 1;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
// initialize dispaly
display.init();
ui.setTargetFPS(30);
ui.setActiveSymbole(activeSymbole);
ui.setInactiveSymbole(inactiveSymbole);
// You can change this to
// TOP, LEFT, BOTTOM, RIGHT
ui.setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar.
ui.setIndicatorDirection(LEFT_RIGHT);
// You can change the transition that is used
// SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
ui.setFrameAnimation(SLIDE_LEFT);
// Add frames
ui.setFrames(frames, frameCount);
// Add overlays
ui.setOverlays(overlays, overlaysCount);
// Inital UI takes care of initalising the display too.
ui.init();
display.flipScreenVertically();
// set the drawing functions
display.setFrameCallbacks(frameCount, frameCallbacks);
// how many ticks does a slide of a frame take?
display.setFrameTransitionTicks(10);
// defines how many ticks the driver waits between frame transitions
display.setFrameWaitTicks(150);
display.clear();
display.display();
}
void loop() {
if (display.getFrameState() == display.FRAME_STATE_FIX) {
// do something which consumes a lot of time in a moment
// when there is no transition between frames going on.
// This will keep transitions smooth;
}
// clear the frame
display.clear();
// Tell the driver to render the next frame.
// This enables the frame mode including the transition
// and the drawing of the frame indicators
display.nextFrameTick();
int remainingTimeBudget = ui.update();
// Even in frame mode you can draw static elements.
// But they won't be transitioned
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0, 54, "20:54");
if (remainingTimeBudget > 0) {
// You can do some work here
// Don't do stuff if you are below your
// time budget.
delay(remainingTimeBudget);
}
}
// copy the buffer to the display
display.display();
bool msOverlay(SSD1306 *display) {
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->setFont(ArialMT_Plain_10);
display->drawString(128, 0, String(millis()));
return true;
}
void drawFrame1(int x, int y) {
bool drawFrame1(SSD1306 *display, int x, int 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(int x, int y) {
// if this frame need to be refreshed at the targetFPS you need to
// return true
display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
return false;
}
bool drawFrame2(SSD1306 *display, int x, int 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, 0 + y, "Arial 10");
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_16);
display.drawString(0 + x, 10 + y, "Arial 16");
display->setFont(ArialMT_Plain_24);
display->drawString(0 + x, 34 + y, "Arial 24");
display.setFont(ArialMT_Plain_24);
display.drawString(0 + x, 24 + y, "Arial 24");
return false;
}
void drawFrame3(int x, int y) {
bool drawFrame3(SSD1306 *display, int x, int y) {
// Text alignment demo
display.setFont(ArialMT_Plain_10);
display->setFont(ArialMT_Plain_10);
// The coordinates define the left starting point of the text
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0 + x, 0 + y, "Left aligned (0,0)");
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, 20, "Center aligned (64,20)");
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, 22, "Center aligned (64,22)");
// The coordinates define the right end of the text
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.drawString(128 + x, 40, "Right aligned (128,40)");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(128 + x, 33, "Right aligned (128,33)");
return false;
}
void drawFrame4(int x, int y) {
// Demo for drawStringMaxWidth:
bool drawFrame4(SSD1306 *display, int x, int 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, 0 + y, 128, "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore.");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
display->drawStringMaxWidth(0 + x, 10 + y, 128, "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore.");
return false;
}
......
#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,
};
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 activeSymbole[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const char inactiveSymbole[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
\ No newline at end of file
......@@ -29,23 +29,20 @@ Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
#include <Wire.h>
SSD1306::SSD1306(int i2cAddress, int sda, int sdc)
{
SSD1306::SSD1306(int i2cAddress, int sda, int sdc) {
myI2cAddress = i2cAddress;
mySda = sda;
mySdc = sdc;
}
void SSD1306::init() {
Wire.begin(mySda, mySdc);
Wire.setClock(400000);
Wire.setClock(400000);
sendInitCommands();
resetDisplay();
}
void SSD1306::resetDisplay(void)
{
void SSD1306::resetDisplay(void) {
displayOff();
clear();
display();
......@@ -53,30 +50,29 @@ void SSD1306::resetDisplay(void)
}
void SSD1306::reconnect() {
Wire.begin(mySda, mySdc);
Wire.begin(mySda, mySdc);
}
void SSD1306::displayOn(void)
{
void SSD1306::displayOn(void) {
sendCommand(0xaf); //display on
}
void SSD1306::displayOff(void)
{
sendCommand(0xae); //display off
void SSD1306::displayOff(void) {
sendCommand(0xae); //display off
}
void SSD1306::setContrast(char contrast) {
sendCommand(0x81);
sendCommand(contrast);
sendCommand(contrast);
}
void SSD1306::flipScreenVertically() {
sendCommand(0xA0 | 0x1); //SEGREMAP //Rotate screen 180 deg
sendCommand(0xC8); //COMSCANDEC Rotate screen 180 Deg
}
void SSD1306::clear(void) {
memset(buffer, 0, (128*64 / 8));
memset(buffer, 0, (128 * 64 / 8));
}
void SSD1306::display(void) {
......@@ -88,10 +84,8 @@ void SSD1306::display(void) {
sendCommand(0x0);
sendCommand(0x7);
for (uint16_t i=0; i<(128*64/8); i++) {
// send a bunch of data in one xmission
//Wire.begin(mySda, mySdc);
Wire.beginTransmission(myI2cAddress);
Wire.write(0x40);
for (uint8_t x=0; x<16; x++) {
......@@ -102,18 +96,17 @@ void SSD1306::display(void) {
yield();
Wire.endTransmission();
}
}
void SSD1306::setPixel(int x, int y) {
if (x >= 0 && x < 128 && y >= 0 && y < 64) {
switch (myColor) {
case WHITE: buffer[x+ (y/8)*128] |= (1 << (y&7)); break;
case BLACK: buffer[x+ (y/8)*128] &= ~(1 << (y&7)); break;
case INVERSE: buffer[x+ (y/8)*128] ^= (1 << (y&7)); break;
case WHITE: buffer[x + (y/8)*128] |= (1 << (y&7)); break;
case BLACK: buffer[x + (y/8)*128] &= ~(1 << (y&7)); break;
case INVERSE: buffer[x + (y/8)*128] ^= (1 << (y&7)); break;
}
}
}
......@@ -122,15 +115,15 @@ void SSD1306::setChar(int x, int y, unsigned char data) {
for (int i = 0; i < 8; i++) {
if (bitRead(data, i)) {
setPixel(x,y + i);
}
}
}
}
}
// Code form http://playground.arduino.cc/Main/Utf8ascii
byte SSD1306::utf8ascii(byte ascii) {
if ( ascii<128 ) // Standard ASCII-set 0..0x7F handling
{ lastChar=0;
return( ascii );
if ( ascii<128 ) { // Standard ASCII-set 0..0x7F handling
lastChar=0;
return( ascii );
}
// get previous input
......@@ -147,7 +140,7 @@ byte SSD1306::utf8ascii(byte ascii) {
}
// Code form http://playground.arduino.cc/Main/Utf8ascii
String SSD1306::utf8ascii(String s) {
String SSD1306::utf8ascii(String s) {
String r= "";
char c;
for (int i=0; i<s.length(); i++)
......@@ -192,7 +185,7 @@ void SSD1306::drawString(int x, int y, String text) {
currentCharWidth = pgm_read_byte(myFontData + CHAR_WIDTH_START_POS + charCode);
// Jump to font data beginning
currentCharStartPos = CHAR_WIDTH_START_POS + numberOfChars;
for (int m = 0; m < charCode; m++) {
currentCharStartPos += pgm_read_byte(myFontData + CHAR_WIDTH_START_POS + m) * charHeight / 8 + 1;
......@@ -201,26 +194,24 @@ void SSD1306::drawString(int x, int y, String text) {
currentCharByteNum = ((charHeight * currentCharWidth) / 8) + 1;
// iterate over all bytes of character
for (int i = 0; i < currentCharByteNum; i++) {
currentByte = pgm_read_byte(myFontData + currentCharStartPos + i);
//Serial.println(String(charCode) + ", " + String(currentCharWidth) + ", " + String(currentByte));
// iterate over all bytes of character
for(int bit = 0; bit < 8; bit++) {
//int currentBit = bitRead(currentByte, bit);
currentBitCount = i * 8 + bit;
charX = currentBitCount % currentCharWidth;
charY = currentBitCount / currentCharWidth;
if (bitRead(currentByte, bit)) {
//Serial.println(String(charX) + ", " + String(charY));
setPixel(startX + cursorX + charX, startY + charY);
//setPixel(charX, charY);
setPixel(startX + cursorX + charX, startY + charY);
}
}
yield();
}
yield();
}
cursorX += currentCharWidth;
......@@ -248,7 +239,7 @@ void SSD1306::drawStringMaxWidth(int x, int y, int maxLineWidth, String text) {
startsAt = endsAt + 1;
}
}
}
drawString(x, y + lineNumber * lineHeight, text.substring(startsAt));
}
......@@ -275,28 +266,28 @@ void SSD1306::setFont(const char *fontData) {
void SSD1306::drawBitmap(int x, int y, int width, int height, const char *bitmap) {
for (int i = 0; i < width * height / 8; i++ ){
unsigned char charColumn = 255 - pgm_read_byte(bitmap + i);
for (int j = 0; j < 8; j++) {
for (int j = 0; j < 8; j++) {
int targetX = i % width + x;
int targetY = (i / (width)) * 8 + j + y;
if (bitRead(charColumn, j)) {
setPixel(targetX, targetY);
setPixel(targetX, targetY);
}
}
}
}
}
void SSD1306::setColor(int color) {
myColor = color;
myColor = color;
}
void SSD1306::drawRect(int x, int y, int width, int height) {
for (int i = x; i < x + width; i++) {
setPixel(i, y);
setPixel(i, y + height);
setPixel(i, y + height);
}
for (int i = y; i < y + height; i++) {
setPixel(x, i);
setPixel(x + width, i);
setPixel(x + width, i);
}
}
......@@ -314,28 +305,24 @@ void SSD1306::drawXbm(int x, int y, int width, int height, const char *xbm) {
}
for (int i = 0; i < width * height / 8; i++ ){
unsigned char charColumn = pgm_read_byte(xbm + i);
for (int j = 0; j < 8; j++) {
for (int j = 0; j < 8; j++) {
int targetX = (i * 8 + j) % width + x;
int targetY = (8 * i / (width)) + y;
if (bitRead(charColumn, j)) {
setPixel(targetX, targetY);
setPixel(targetX, targetY);
}
}
}
}
}
void SSD1306::sendCommand(unsigned char com)
{
//Wire.begin(mySda, mySdc);
void SSD1306::sendCommand(unsigned char com) {
Wire.beginTransmission(myI2cAddress); //begin transmitting
Wire.write(0x80); //command mode
Wire.write(com);
Wire.endTransmission(); // stop transmitting
}
void SSD1306::sendInitCommands(void)
{
void SSD1306::sendInitCommands(void) {
sendCommand(DISPLAYOFF);
sendCommand(NORMALDISPLAY);
sendCommand(SETDISPLAYCLOCKDIV);
......@@ -363,53 +350,4 @@ void SSD1306::sendInitCommands(void)
sendCommand(NORMALDISPLAY);
sendCommand(0x2e); // stop scroll
sendCommand(DISPLAYON);
}
void SSD1306::nextFrameTick() {
myFrameTick++;
if (myFrameTick==myFrameWaitTicks && myFrameState == 0 || myFrameTick==myFrameTransitionTicks && myFrameState == 1) {
myFrameState = (myFrameState + 1) % 2;
if (myFrameState==FRAME_STATE_FIX) {
myCurrentFrame = (myCurrentFrame + 1) % myFrameCount;
}
myFrameTick = 0;
}
drawIndicators(myFrameCount, myCurrentFrame);
switch(myFrameState) {
case 0:
(*myFrameCallbacks[myCurrentFrame])(0, 0);
break;
case 1:
(*myFrameCallbacks[myCurrentFrame])(-128 * myFrameTick / myFrameTransitionTicks, 0);
(*myFrameCallbacks[(myCurrentFrame + 1) % myFrameCount])(-128 * myFrameTick / myFrameTransitionTicks + 128, 0);
break;
}
}
void SSD1306::drawIndicators(int frameCount, int activeFrame) {
for (int i = 0; i < frameCount; i++) {
const char *xbm;
if (activeFrame == i) {
xbm = active_bits;
} else {
xbm = inactive_bits;
}
drawXbm(64 - (12 * frameCount / 2) + 12 * i,56, 8, 8, xbm);
}
}
void SSD1306::setFrameCallbacks(int frameCount, void (*frameCallbacks[])(int x, int y)) {
myFrameCount = frameCount;
myFrameCallbacks = frameCallbacks;
}
void SSD1306::setFrameWaitTicks(int frameWaitTicks) {
myFrameWaitTicks = frameWaitTicks;
}
void SSD1306::setFrameTransitionTicks(int frameTransitionTicks) {
myFrameTransitionTicks = frameTransitionTicks;
}
int SSD1306::getFrameState() {
return myFrameState;
}
}
\ No newline at end of file
......@@ -29,21 +29,10 @@ Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
#include <Arduino.h>
#include "SSD1306Fonts.h"
#define active_width 8
#define active_height 8
const char active_bits[] PROGMEM = {
0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00 };
#define inactive_width 8
#define inactive_height 8
const char inactive_bits[] PROGMEM = {
0x00, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x00 };
#define BLACK 0
#define WHITE 1
#define INVERSE 2
#define WIDTH_POS 0
#define HEIGHT_POS 1
#define FIRST_CHAR_POS 2
......@@ -88,19 +77,10 @@ private:
int mySda;
int mySdc;
uint8_t buffer[128 * 64 / 8];
int myFrameState = 0;
int myFrameTick = 0;
int myCurrentFrame = 0;
int myFrameCount = 0;
int myFrameWaitTicks = 100;
int myFrameTransitionTicks = 25;
int myTextAlignment = TEXT_ALIGN_LEFT;
int myColor = WHITE;
byte lastChar;
const char *myFontData = ArialMT_Plain_10;
void (**myFrameCallbacks)(int x, int y);
public:
// Create the display object connected to pin sda and sdc
......@@ -190,32 +170,4 @@ public:
// ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24
void setFont(const char *fontData);
// Sets the callback methods of the format void method(x,y)
void setFrameCallbacks(int frameCount, void (*frameCallbacks[])(int x, int y));
// Tells the framework to move to the next tick. The
// current visible frame callback will be called once
// per tick
void nextFrameTick(void);
// Draws the frame indicators. In a normal setup
// the framework does this for you
void drawIndicators(int frameCount, int activeFrame);
// defines how many ticks a frame should remain visible
// This does not include the transition
void setFrameWaitTicks(int frameWaitTicks);
// Defines how many ticks should be used for a transition
void setFrameTransitionTicks(int frameTransitionTicks);
// Returns the current state of the internal state machine
// Possible values: FRAME_STATE_FIX, FRAME_STATE_TRANSITION
// You can use this to detect when there is no transition
// on the way to execute operations that would
int getFrameState();
const int FRAME_STATE_FIX = 0;
const int FRAME_STATE_TRANSITION = 1;
};
};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment