Skip to content

Instantly share code, notes, and snippets.

@tobozo
Created November 2, 2017 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tobozo/dcbc8ca498a59e0ace3a752aa5bc7614 to your computer and use it in GitHub Desktop.
Save tobozo/dcbc8ca498a59e0ace3a752aa5bc7614 to your computer and use it in GitHub Desktop.
/*
* SSD1306 Multiple monitor Demo
* Copyleft (c+) toboz Nov 2017
*
*/
#include <SPI.h>
#include <Wire.h>
#include <U8g2lib.h>
#define NUMSPRITES 16
#define NUMSCREENS 8
#define XPOS 0
#define YPOS 1
#define DELTAY 2
#define DIR 3
#define SPRITE 4
#define TCAADDR 0x70 // I2C Multiplexer ADDR
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH 16
int16_t icons[NUMSPRITES][5];
uint16_t hspritepos = 0;
uint16_t maxhpos = 0;
uint16_t maxvpos = 0;
/* adafruit logo */
const uint8_t logo16_glcd_bmp[] = {
B11000000, B00000000,
B11000000, B00000001,
B11000000, B00000001,
B11100000, B00000011,
B11100000, B11110011,
B11111000, B11111110,
B11111111, B01111110,
B10011111, B00110011,
B11111100, B00011111,
B01110000, B00001101,
B10100000, B00011011,
B11100000, B00111111,
B11110000, B00111111,
B11110000, B01111100,
B01110000, B01110000,
B00110000, B00000000,
};
/* smiley */
const uint8_t logo16_glcd2_bmp[] = {
B11100000, B00000111,
B00011000, B00011000,
B00000100, B00100000,
B00000010, B01000000,
B01100010, B01000110,
B01100001, B10000110,
B00000001, B10000000,
B00000001, B10000000,
B00000001, B10000000,
B00001001, B10010000,
B00010001, B10001000,
B11100010, B01000111,
B00000010, B01000000,
B00000100, B00100000,
B00011000, B00011000,
B11100000, B00000111,
};
/* smiley bored */
const uint8_t logo_smiley_bored[] = {
B11100000, B00000111,
B00011000, B00011000,
B00000100, B00100000,
B00000010, B01000000,
B00000010, B01000000,
B01111001, B10011110,
B00000001, B10000000,
B00000001, B10000000,
B00000001, B10000000,
B00000001, B10000000,
B00000001, B10000000,
B11100010, B01000111,
B00000010, B01000000,
B00000100, B00100000,
B00011000, B00011000,
B11100000, B00000111,
};
/* -pumpkin */
const uint8_t hzv_logo[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x03, 0x40, 0x00, 0x00, 0x02,
0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x78, 0x00, 0x00, 0x1e,
0x08, 0x00, 0xfc, 0x11, 0x08, 0x00, 0xfc, 0x11, 0x08, 0x00, 0xfc, 0x11,
0x88, 0x3f, 0xfc, 0x11, 0x88, 0x3f, 0xfc, 0x11, 0x88, 0x3f, 0xfc, 0x11,
0x88, 0x3f, 0xfc, 0x11, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10,
0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x78, 0x00, 0x00, 0x1e,
0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x3c, 0x3c, 0x02,
0x40, 0x24, 0x24, 0x02, 0x40, 0x24, 0x24, 0x02, 0x40, 0x24, 0x24, 0x02,
0xc0, 0xe7, 0xe7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t halloween_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xff, 0xff, 0x01,
0xc0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x1f,
0xf8, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xcf, 0x3f,
0xfc, 0xff, 0xc7, 0x7f, 0xfc, 0xc7, 0xc3, 0x73, 0xfc, 0x87, 0xc1, 0x73,
0xfc, 0x8f, 0xf1, 0x71, 0xfc, 0xff, 0xff, 0x70, 0xfc, 0xff, 0x7f, 0x60,
0x3c, 0xff, 0x3f, 0x60, 0x3c, 0xfe, 0x0f, 0x60, 0x3c, 0x30, 0x00, 0x70,
0x3c, 0x00, 0x00, 0x30, 0x78, 0xf8, 0xff, 0x39, 0x70, 0xfe, 0xff, 0x1f,
0xf0, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x0f, 0x80, 0xff, 0xff, 0x03,
0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct logo {
const uint8_t *binary;
uint8_t width;
uint8_t height;
};
logo logoArray[5] = {
{ logo16_glcd_bmp, 16, 16 },
{ logo16_glcd2_bmp, 16, 16 },
{ logo_smiley_bored, 16, 16 },
{ hzv_logo, 32, 32 },
{ halloween_bits, 32, 32 }
};
// all display types
U8G2_SSD1306_64X48_ER_F_HW_I2C display64x48(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C display128x64(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C display128x32(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
struct display {
U8G2 *display;
const u8g2_cb_t *rotation;
uint16_t position;
uint8_t width;
uint8_t height;
};
/* display array, order matters */
display OLEDS[NUMSCREENS] = {
{ &display128x32, U8G2_R3 },
{ &display64x48, U8G2_R0 },
{ &display64x48, U8G2_R0 },
{ &display64x48, U8G2_R0 },
{ &display128x64, U8G2_R0 },
{ &display128x32, U8G2_R3 },
{ &display128x32, U8G2_R3 },
{ &display128x32, U8G2_R3 }
};
/* I2C multiplexer */
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
#define MATRIX_SIZE 64
bool matrix[MATRIX_SIZE][MATRIX_SIZE];
void setMatrix(uint8_t depth) {
float matrixwidth = MATRIX_SIZE;
float matrixheight = MATRIX_SIZE;
//Serial.println("Setting Matrix");
for(uint8_t y=0;y<matrixheight;y++) {
bool ystate = y%depth == 1;
for(uint8_t x=0;x<matrixwidth;x++) {
bool xstate = x%depth == 1;
matrix[x][y] = ystate ? xstate : !xstate;
//Serial.print(xstate);
}
//Serial.println();
}
//Serial.println();
}
void projectMatrix(uint8_t dnum, float zoom, float angle, float width, float height, float offsetx, float offsety) {
float ratio = 1/zoom;
float virtualwidth = (float)MATRIX_SIZE*zoom;
float virtualheight = (float)MATRIX_SIZE*zoom;
float virtualcenterx = virtualwidth/2;
float virtualcentery = virtualheight/2;
float vectorx = cos(angle);
float vectory = sin(angle);
float marginx = (virtualwidth - width) / 2 + offsetx;
float marginy = (virtualheight - height) / 2 + offsety;
tcaselect(dnum);
OLEDS[dnum].display->clearBuffer();
for( uint8_t i=0; i<height; i++ ) {
float x1 = marginx;
float y1 = marginy+i;
float x2 = virtualwidth-marginx;
float y2 = marginy+i;
for( uint8_t j=0; j<width; j++ ) {
float x = round( x1+(x2-x1)*j/width );
float y = round( y1+(y2-y1)*j/width );
float nx = (vectorx * (x - virtualcenterx)) + (vectory * (y - virtualcentery)) + virtualcenterx;
float ny = (vectorx * (y - virtualcentery)) - (vectory * (x - virtualcenterx)) + virtualcentery;
uint8_t mx = nx*ratio;
uint8_t my = ny*ratio;
//Serial.println(String(x) + " " + String(y) + " / " + String() + " " + String(ny*ratio));
if(matrix[mx][my]) {
OLEDS[dnum].display->drawPixel(j, i);
}
}
}
OLEDS[dnum].display->sendBuffer();
}
void drawDisplay(uint8_t dnum) {
display curDisplay = OLEDS[dnum];
U8G2 *display = curDisplay.display;
display->clearBuffer();
float w = display->getDisplayWidth();
float h = display->getDisplayHeight();
float wratio = 128 / w;
float hratio = 64 / h;
for (uint8_t f=0; f<NUMSPRITES; f++) {
logo curLogo = logoArray[icons[f][SPRITE]];
if( icons[f][XPOS]+(curLogo.width/2) > curDisplay.position
&& icons[f][XPOS]-(curLogo.width/2) < curDisplay.position + curDisplay.width ) {
display->drawXBM(icons[f][XPOS] - curDisplay.position - (curLogo.width/2), icons[f][YPOS], curLogo.width, curLogo.height, curLogo.binary);
}
}
display->sendBuffer();
}
void setup() {
Serial.begin(115200);
while (!Serial); // Leonardo: wait for serial monitor
Wire.begin();
uint16_t pos = 0;
for(uint8_t i=0;i<NUMSCREENS;i++) {
tcaselect(i);
OLEDS[i].display->begin();
OLEDS[i].display->setDisplayRotation( OLEDS[i].rotation );
OLEDS[i].width = OLEDS[i].display->getDisplayWidth();
OLEDS[i].height = OLEDS[i].display->getDisplayHeight();
OLEDS[i].position = pos;
pos += OLEDS[i].width;
if(OLEDS[i].height > maxvpos) maxvpos = OLEDS[i].height;
Serial.print(i);
Serial.print("\t");
Serial.print(OLEDS[i].width);
Serial.print("\t");
Serial.print(OLEDS[i].height);
Serial.print("\t");
Serial.print(OLEDS[i].position);
Serial.println();
}
maxhpos = pos;
Serial.println("Display Setup Complete");
setMatrix(2);
for(float i=-PI;i<PI*12;i=i+0.2) {
//setMatrix(cos(i)*2+16);
projectMatrix(/*displaynum*/4, /*zoom*/32 + cos(i)*16, /*angle*/i, /*width*/128, /*height*/64, /*offsetx*/0, /*offsety*/0);
}
}
void loop() {
// initialize sprites
for (uint8_t f=0; f< NUMSPRITES; f++) {
icons[f][XPOS] = random(maxhpos) - (LOGO16_GLCD_WIDTH/2);
icons[f][YPOS] = random(maxvpos) - (LOGO16_GLCD_HEIGHT/2);
icons[f][DELTAY] = random(5) + 1;
icons[f][DIR] = random(8) - 4;
icons[f][SPRITE] = random(5);
}
while (1) {
// draw displays
for (uint8_t f=0; f< NUMSCREENS; f++) {
tcaselect( f );
//u8g2 = OLEDS[f].display;
drawDisplay(f);
}
// move sprites
for (uint8_t f=0; f< NUMSPRITES; f++) {
icons[f][YPOS] += icons[f][DELTAY];
icons[f][XPOS] += icons[f][DIR];
if(icons[f][XPOS]>maxhpos) {
icons[f][XPOS] = 0;
}
if(icons[f][XPOS]<0) {
icons[f][XPOS] = maxhpos;
}
// if its gone, reinit
if (icons[f][YPOS] > maxvpos) {
icons[f][XPOS] = random(maxhpos) - (LOGO16_GLCD_WIDTH/2);
icons[f][YPOS] = -15;
icons[f][DELTAY] = random(5) + 1;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment