Created
November 2, 2017 07:10
-
-
Save tobozo/dcbc8ca498a59e0ace3a752aa5bc7614 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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