9 #define SH1106_SET_COLUMN_ADDR_LOW 0x00
10 #define SH1106_SET_COLUMN_ADDR_HIGH 0x10
11 #define SH1106_SET_CONTRAST 0x81
12 #define SH1106_SET_SEGMENT_REMAP 0xA0
13 #define SH1106_SET_INVERT_DISPLAY 0xA6
14 #define SH1106_SET_DISPLAY_ON 0xAE
15 #define SH1106_SET_PAGE_ADDR 0xB0
16 #define SH1106_SET_COM_SCAN_DIR 0xC0
115 memset(textBuffer,
' ',
sizeof(textBuffer));
122 void clearDisplayRam()
124 core.sh1106TransferStart();
125 core.sh1106CommandMode();
126 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | 2);
127 for (uint8_t page = 0; page < 8; page++)
129 core.sh1106CommandMode();
130 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
131 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | 0);
132 core.sh1106DataMode();
133 for (uint8_t i = 0; i < 128; i++)
138 core.sh1106TransferEnd();
139 clearDisplayRamOnNextDisplay =
false;
142 void configureDefault()
144 core.sh1106TransferStart();
145 core.sh1106CommandMode();
146 core.sh1106Write(SH1106_SET_SEGMENT_REMAP | 1);
147 core.sh1106Write(SH1106_SET_COM_SCAN_DIR | 8);
148 core.sh1106Write(SH1106_SET_CONTRAST);
149 core.sh1106Write(0xFF);
150 core.sh1106Write(SH1106_SET_DISPLAY_ON | 1);
151 core.sh1106TransferEnd();
176 void init() {
if (!initialized) { init2(); } }
198 core.sh1106TransferStart();
199 core.sh1106CommandMode();
200 core.sh1106Write(SH1106_SET_INVERT_DISPLAY | 1);
201 core.sh1106TransferEnd();
208 core.sh1106TransferStart();
209 core.sh1106CommandMode();
210 core.sh1106Write(SH1106_SET_INVERT_DISPLAY | 0);
211 core.sh1106TransferEnd();
218 core.sh1106TransferStart();
219 core.sh1106CommandMode();
220 core.sh1106Write(SH1106_SET_SEGMENT_REMAP);
221 core.sh1106Write(SH1106_SET_COM_SCAN_DIR);
222 core.sh1106TransferEnd();
235 core.sh1106TransferStart();
236 core.sh1106CommandMode();
237 core.sh1106Write(SH1106_SET_SEGMENT_REMAP | 1);
238 core.sh1106Write(SH1106_SET_COM_SCAN_DIR | 8);
239 core.sh1106TransferEnd();
249 core.sh1106TransferStart();
250 core.sh1106CommandMode();
251 core.sh1106Write(SH1106_SET_CONTRAST);
252 core.sh1106Write(contrast);
253 core.sh1106TransferEnd();
260 graphicsBuffer =
nullptr;
261 displayFunction = &PololuSH1106Main::display8x2Text;
262 displayPartialFunction = &PololuSH1106Main::display8x2TextPartial;
263 clearDisplayRamOnNextDisplay =
true;
272 graphicsBuffer = graphics;
273 displayFunction = &PololuSH1106Main::display8x2TextAndGraphics;
274 displayPartialFunction = &PololuSH1106Main::display8x2TextAndGraphicsPartial;
275 clearDisplayRamOnNextDisplay =
true;
286 graphicsBuffer =
nullptr;
287 displayFunction = &PololuSH1106Main::display11x4Text;
288 displayPartialFunction = &PololuSH1106Main::display11x4TextPartial;
289 clearDisplayRamOnNextDisplay =
true;
302 graphicsBuffer = graphics;
303 displayFunction = &PololuSH1106Main::display11x4TextAndGraphics;
304 displayPartialFunction = &PololuSH1106Main::display11x4TextAndGraphicsPartial;
305 clearDisplayRamOnNextDisplay =
true;
312 graphicsBuffer =
nullptr;
313 displayFunction = &PololuSH1106Main::display21x8Text;
314 displayPartialFunction = &PololuSH1106Main::display21x8TextPartial;
315 clearDisplayRamOnNextDisplay =
true;
324 graphicsBuffer = graphics;
325 displayFunction = &PololuSH1106Main::display21x8TextAndGraphics;
326 displayPartialFunction = &PololuSH1106Main::display21x8TextAndGraphicsPartial;
327 clearDisplayRamOnNextDisplay =
true;
334 uint8_t getGlyphColumn(uint8_t glyph, uint8_t pixelX)
342 return customChars[glyph][pixelX];
350 void writePageGraphics(uint8_t page)
352 core.sh1106CommandMode();
353 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
354 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | 0);
355 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | 2);
356 core.sh1106DataMode();
357 const uint8_t * g = graphicsBuffer + page * 128;
358 for (uint8_t x = 0; x < 128; x++) {
core.sh1106Write(*g++); }
361 void writeSegmentUpperText(uint8_t page, uint8_t columnAddr,
362 const uint8_t * text, uint8_t textLength)
364 core.sh1106CommandMode();
365 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
366 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | (columnAddr >> 4));
367 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | (columnAddr & 0xF));
368 core.sh1106DataMode();
369 for (uint8_t i = 0; i < textLength; i++)
371 uint8_t glyph = *text++;
372 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
374 uint8_t column = PololuOLEDHelpers::repeatBits(
375 getGlyphColumn(glyph, pixelX) & 0xF);
376 core.sh1106Write(column);
377 core.sh1106Write(column);
384 void writeSegmentLowerText(uint8_t page, uint8_t columnAddr,
385 const uint8_t * text, uint8_t textLength)
387 core.sh1106CommandMode();
388 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
389 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | (columnAddr >> 4));
390 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | (columnAddr & 0xF));
391 core.sh1106DataMode();
392 for (uint8_t i = 0; i < textLength; i++)
394 uint8_t glyph = *text++;
395 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
397 uint8_t column = PololuOLEDHelpers::repeatBits(
398 getGlyphColumn(glyph, pixelX) >> 4);
399 core.sh1106Write(column);
400 core.sh1106Write(column);
407 void writeSegmentUpperTextAndGraphics(uint8_t page, uint8_t columnAddr,
408 const uint8_t * text, uint8_t textLength)
410 core.sh1106CommandMode();
411 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
412 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | (columnAddr >> 4));
413 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | (columnAddr & 0xF));
414 core.sh1106DataMode();
415 const uint8_t * g = graphicsBuffer + page * 128 + (columnAddr - 2);
416 for (uint8_t i = 0; i < textLength; i++)
418 uint8_t glyph = *text++;
419 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
421 uint8_t column = PololuOLEDHelpers::repeatBits(
422 getGlyphColumn(glyph, pixelX) & 0xF);
423 core.sh1106Write(column ^ *g++);
424 core.sh1106Write(column ^ *g++);
426 core.sh1106Write(*g++);
427 core.sh1106Write(*g++);
431 void writeSegmentLowerTextAndGraphics(uint8_t page, uint8_t columnAddr,
432 const uint8_t * text, uint8_t textLength)
434 core.sh1106CommandMode();
435 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
436 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | (columnAddr >> 4));
437 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | (columnAddr & 0xF));
438 core.sh1106DataMode();
439 const uint8_t * g = graphicsBuffer + page * 128 + (columnAddr - 2);
440 for (uint8_t i = 0; i < textLength; i++)
442 uint8_t glyph = *text++;
445 for (uint8_t pixelX = 0; pixelX < 5 && g < graphicsBuffer + 1023; pixelX++)
447 uint8_t column = PololuOLEDHelpers::repeatBits(
448 getGlyphColumn(glyph, pixelX) >> 4);
449 core.sh1106Write(column ^ *g++);
450 core.sh1106Write(column ^ *g++);
452 if(g < graphicsBuffer + 1023)
454 core.sh1106Write(*g++);
455 core.sh1106Write(*g++);
460 void writePageUpperTextAndGraphics(uint8_t page,
const uint8_t * text,
461 uint8_t leftMargin, uint8_t textLength)
463 core.sh1106CommandMode();
464 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
465 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | 0);
466 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | 2);
467 core.sh1106DataMode();
468 const uint8_t * g = graphicsBuffer + page * 128;
469 for (uint8_t i = 0; i < leftMargin; i++) {
core.sh1106Write(*g++); }
470 for (uint8_t textX = 0; textX < textLength; textX++)
472 uint8_t glyph = *text++;
473 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
475 uint8_t column = PololuOLEDHelpers::repeatBits(
476 getGlyphColumn(glyph, pixelX) & 0xF);
477 core.sh1106Write(column ^ *g++);
478 core.sh1106Write(column ^ *g++);
480 core.sh1106Write(*g++);
481 core.sh1106Write(*g++);
483 for (uint8_t x = leftMargin + textLength * 12; x < 128; x++)
485 core.sh1106Write(*g++);
489 void writePageLowerTextAndGraphics(uint8_t page,
const uint8_t * text,
490 uint8_t leftMargin, uint8_t textLength)
492 core.sh1106CommandMode();
493 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
494 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | 0);
495 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | 2);
496 core.sh1106DataMode();
497 const uint8_t * g = graphicsBuffer + page * 128;
498 for (uint8_t i = 0; i < leftMargin; i++) {
core.sh1106Write(*g++); }
499 for (uint8_t textX = 0; textX < textLength; textX++)
501 uint8_t glyph = *text++;
504 for (uint8_t pixelX = 0; pixelX < 5 && g < graphicsBuffer + 1023; pixelX++)
506 uint8_t column = PololuOLEDHelpers::repeatBits(
507 getGlyphColumn(glyph, pixelX) >> 4);
508 core.sh1106Write(column ^ *g++);
509 core.sh1106Write(column ^ *g++);
511 if(g < graphicsBuffer + 1023)
513 core.sh1106Write(*g++);
514 core.sh1106Write(*g++);
517 for (uint8_t x = leftMargin + textLength * 12; x < 128; x++)
519 core.sh1106Write(*g++);
523 void writeSegmentText(uint8_t page, uint8_t columnAddr,
524 const uint8_t * text, uint8_t textLength)
526 core.sh1106CommandMode();
527 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
528 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | (columnAddr >> 4));
529 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | (columnAddr & 0xF));
530 core.sh1106DataMode();
531 for (uint8_t i = 0; i < textLength; i++)
533 uint8_t glyph = *text++;
534 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
536 core.sh1106Write(getGlyphColumn(glyph, pixelX));
542 void writeSegmentTextAndGraphics(uint8_t page, uint8_t columnAddr,
543 const uint8_t * text, uint8_t textLength)
545 core.sh1106CommandMode();
546 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
547 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | (columnAddr >> 4));
548 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | (columnAddr & 0xF));
549 core.sh1106DataMode();
550 const uint8_t * g = graphicsBuffer + page * 128 + (columnAddr - 2);
551 for (uint8_t i = 0; i < textLength; i++)
553 uint8_t glyph = *text++;
554 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
556 core.sh1106Write(getGlyphColumn(glyph, pixelX) ^ *g++);
558 core.sh1106Write(*g++);
562 void writePageTextAndGraphics(uint8_t page,
const uint8_t * text,
563 uint8_t leftMargin, uint8_t textLength)
565 core.sh1106CommandMode();
566 core.sh1106Write(SH1106_SET_PAGE_ADDR | page);
567 core.sh1106Write(SH1106_SET_COLUMN_ADDR_HIGH | 0);
568 core.sh1106Write(SH1106_SET_COLUMN_ADDR_LOW | 2);
569 core.sh1106DataMode();
570 const uint8_t * g = graphicsBuffer + page * 128;
571 for (uint8_t i = 0; i < leftMargin; i++) {
core.sh1106Write(*g++); }
572 for (uint8_t textX = 0; textX < textLength; textX++)
574 uint8_t glyph = *text++;
575 for (uint8_t pixelX = 0; pixelX < 5; pixelX++)
577 core.sh1106Write(getGlyphColumn(glyph, pixelX) ^ *g++);
579 core.sh1106Write(*g++);
581 for (uint8_t x = leftMargin + textLength * 6; x < 128; x++)
583 core.sh1106Write(*g++);
595 void display8x2TextPartial(uint8_t x, uint8_t y, uint8_t width)
597 if (x >= 8 || y >= 2) {
return; }
598 if (width > (uint8_t)(8 - x)) { width = 8 - x; }
599 if (width == 0) {
return; }
601 const uint8_t page = 2 + y * 3;
602 const uint8_t columnAddr = 2 + 17 + x * 12;
605 core.sh1106TransferStart();
606 writeSegmentUpperText(page, columnAddr, text, width);
607 writeSegmentLowerText(page + 1, columnAddr, text, width);
608 core.sh1106TransferEnd();
611 void display8x2Text()
613 core.sh1106TransferStart();
618 core.sh1106TransferEnd();
621 void display8x2TextAndGraphicsPartial(uint8_t x, uint8_t y, uint8_t width)
623 if (x >= 8 || y >= 2) {
return; }
624 if (width > (uint8_t)(8 - x)) { width = 8 - x; }
625 if (width == 0) {
return; }
627 const uint8_t page = 2 + y * 3;
628 const uint8_t columnAddr = 2 + 17 + x * 12;
631 core.sh1106TransferStart();
632 writeSegmentUpperTextAndGraphics(page, columnAddr, text, width);
633 writeSegmentLowerTextAndGraphics(page + 1, columnAddr, text, width);
634 core.sh1106TransferEnd();
637 void display8x2TextAndGraphics()
639 core.sh1106TransferStart();
640 writePageGraphics(0);
641 writePageGraphics(1);
644 writePageGraphics(4);
647 writePageGraphics(7);
648 core.sh1106TransferEnd();
661 void display11x4TextPartial(uint8_t x, uint8_t y, uint8_t width)
663 if (x >= 11 || y >= 4) {
return; }
664 if (width > (uint8_t)(11 - x)) { width = 11 - x; }
665 if (width == 0) {
return; }
667 const uint8_t page = y * 2;
668 const uint8_t columnAddr = 2 + x * 12;
671 core.sh1106TransferStart();
672 writeSegmentUpperText(page, columnAddr, textStart, width);
673 writeSegmentLowerText(page + 1, columnAddr, textStart, width);
674 core.sh1106TransferEnd();
677 void display11x4Text()
679 core.sh1106TransferStart();
688 core.sh1106TransferEnd();
691 void display11x4TextAndGraphicsPartial(uint8_t x, uint8_t y, uint8_t width)
693 if (x >= 11 || y >= 4) {
return; }
694 if (width > (uint8_t)(10 - x)) { width = 11 - x; }
695 if (width == 0) {
return; }
697 const uint8_t page = y * 2;
698 const uint8_t columnAddr = 2 + x * 12;
701 core.sh1106TransferStart();
702 writeSegmentUpperTextAndGraphics(page, columnAddr, text, width);
703 writeSegmentLowerTextAndGraphics(page + 1, columnAddr, text, width);
704 core.sh1106TransferEnd();
707 void display11x4TextAndGraphics()
709 core.sh1106TransferStart();
718 core.sh1106TransferEnd();
728 void display21x8TextPartial(uint8_t x, uint8_t y, uint8_t width)
730 if (x >= 21 || y >= 8) {
return; }
731 if (width > (uint8_t)(21 - x)) { width = 21 - x; }
732 if (width == 0) {
return; }
734 const uint8_t columnAddr = 2 + x * 6;
737 core.sh1106TransferStart();
738 writeSegmentText(y, columnAddr, textStart, width);
739 core.sh1106TransferEnd();
742 void display21x8Text()
744 core.sh1106TransferStart();
753 core.sh1106TransferEnd();
756 void display21x8TextAndGraphicsPartial(uint8_t x, uint8_t y, uint8_t width)
758 if (x >= 21 || y >= 8) {
return; }
759 if (width > (uint8_t)(21 - x)) { width = 21 - x; }
760 if (width == 0) {
return; }
762 const uint8_t columnAddr = 2 + x * 6;
765 core.sh1106TransferStart();
766 writeSegmentTextAndGraphics(y, columnAddr, text, width);
767 core.sh1106TransferEnd();
770 void display21x8TextAndGraphics()
772 core.sh1106TransferStart();
781 core.sh1106TransferEnd();
797 if (clearDisplayRamOnNextDisplay) { clearDisplayRam(); }
798 ((*this).*(displayFunction))();
799 disableAutoDisplay =
false;
825 if (clearDisplayRamOnNextDisplay) { clearDisplayRam(); }
826 ((*this).*(displayPartialFunction))(x, y, width);
841 disableAutoDisplay =
true;
864 return textBuffer + line * textBufferWidth;
881 uint8_t
getX() {
return textCursorX; }
884 uint8_t
getY() {
return textCursorY; }
889 memmove(textBuffer, textBuffer + textBufferWidth, textBufferWidth * (textBufferHeight - 1));
890 memset(textBuffer + textBufferWidth * (textBufferHeight - 1),
' ', textBufferWidth);
891 if (!disableAutoDisplay) {
display(); }
903 memset(textBuffer,
' ',
sizeof(textBuffer));
905 if (!disableAutoDisplay) {
display(); }
926 size_t write(
const uint8_t * buffer,
size_t size)
override
928 if (textCursorY >= textBufferHeight) {
return 0; }
929 if (textCursorX >= textBufferWidth) {
return 0; }
930 if (size > (uint8_t)(textBufferWidth - textCursorX))
932 size = textBufferWidth - textCursorX;
937 if (!disableAutoDisplay)
952 if (textCursorY >= textBufferHeight) {
return 0; }
953 if (textCursorX >= textBufferWidth) {
return 0; }
957 if (!disableAutoDisplay)
971 uint8_t * columns = customChars[number];
972 for (uint8_t i = 0; i < 5; i++)
976 for (uint8_t i = 0; i < 8; i++)
978 uint8_t row = picture[i];
979 uint8_t mask = 1 << i;
980 if (row & (1 << 0)) { columns[4] |= mask; }
981 if (row & (1 << 1)) { columns[3] |= mask; }
982 if (row & (1 << 2)) { columns[2] |= mask; }
983 if (row & (1 << 3)) { columns[1] |= mask; }
984 if (row & (1 << 4)) { columns[0] |= mask; }
993 uint8_t ram_picture[8];
994 for (uint8_t i = 0; i < 8; i++)
996 ram_picture[i] = pgm_read_byte(picture + i);
1018 bool clearDisplayRamOnNextDisplay;
1020 bool disableAutoDisplay;
1026 void (
PololuSH1106Main::*displayPartialFunction)(uint8_t, uint8_t, uint8_t);
1028 static const uint8_t textBufferWidth = 21, textBufferHeight = 8;
1030 uint8_t textBuffer[textBufferHeight * textBufferWidth];
1031 uint8_t textCursorX;
1032 uint8_t textCursorY;
1033 uint8_t customChars[8][5];
1035 const uint8_t * graphicsBuffer;
const PROGMEM uint8_t pololuOledFont[][5]
This array defines the appearance of characters 32 through 255.
This class makes it easy to display text and graphics on a 128x64 SH1106 OLED.
void loadCustomCharacterFromRam(const uint8_t *picture, uint8_t number)
Defines a custom character from RAM.
void invert()
Configures the OLED to invert all the pixels, resulting in black-on-white text.
void rotate180()
Configures the OLED to rotate its display 180 degrees from normal.
void setLayout8x2WithGraphics(const uint8_t *graphics)
Configures this library to use a layout with 8 columns and 2 rows of text, XORed with a graphics buff...
uint8_t getY()
Gets the Y coordinate of the text cursor.
void noRotate()
Configures the OLED to use the default orientation.
void gotoXY(uint8_t x, uint8_t y)
Changes the location of the text cursor.
void noAutoDisplay()
Turns off auto display mode.
void loadCustomCharacter(const uint8_t *picture, uint8_t number)
Defines a custom character.
void setLayout21x8WithGraphics(const uint8_t *graphics)
Configures this library to use a layout with 21 columns and 8 rows of text, XORed with a graphics buf...
void clear()
Clears the text and resets the text cursor to the upper left.
void setLayout11x4()
Configures this library to use a layout with 11 columns and 4 rows of text.
void setLayout8x2()
Configures this library to use its default layout, which allows for 8 columns and 2 rows of text.
void reinitialize()
Reinitializes the OLED and its settings.
void loadCustomCharacter(const char *picture, uint8_t number)
Defines a custom character.
void display()
Writes all of the text/graphics to the OLED.
void init()
Initializes the OLED if it has not already been initialized.
void setLayout21x8()
Configures this library to use a layout with 21 columns and 8 rows of text.
size_t write(uint8_t d) override
Writes a single character of text.
C core
This object handles all low-level communication with the SH1106.
uint8_t * getLinePointer(uint8_t line)
Gets a pointer to a line of text in this library's text buffer.
void displayPartial(uint8_t x, uint8_t y, uint8_t width)
Writes a certain region of text/graphics to the OLED.
void scrollDisplayUp()
Moves all the text up one row. (Does not change the cursor position.)
uint8_t getX()
Gets the X coordinate of the text cursor.
void noInvert()
Configures the OLED to not invert its pixels (the default).
size_t write(const uint8_t *buffer, size_t size) override
Writes a string of text.
void setContrast(uint8_t contrast)
Sets the contrast (i.e. brightness) of the OLED.
void setLayout11x4WithGraphics(const uint8_t *graphics)
Configures this library to use a layout with 11 columns and 4 rows of text, XORed with a graphics buf...