// some of this code was written by originally; // it is in the public domain. //#include #include #include #include #include "SSD1306.h" #include "glcdfont.c" static uint8_t is_reversed = 0; // a 5x7 font table extern uint8_t PROGMEM font[]; // the memory buffer for the LCD static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x0A, 0x0A, 0x0A, 0x04, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x1E, 0x20, 0x1E, 0x20, 0x1E, 0x00, 0x3E, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x3E, 0x0A, 0x0A, 0x0A, 0x34, 0x00, 0x3E, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x2A, 0x2A, 0x2A, 0x14, 0x00, 0x06, 0x08, 0x30, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x84, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x1C, 0x00, 0x18, 0x34, 0x2C, 0x08, 0x00, 0x28, 0x2C, 0x34, 0x14, 0x00, 0x3A, 0x00, 0x18, 0xA4, 0xA4, 0x7C, 0x00, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x3E, 0x22, 0x22, 0x1C, 0x00, 0x3E, 0x04, 0x08, 0x3E, 0x00, 0x3C, 0x12, 0x12, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0xF0, 0x08, 0x04, 0x84, 0x42, 0x22, 0x11, 0x11, 0x18, 0x28, 0x44, 0x84, 0x0A, 0x12, 0x21, 0xC0, 0xC1, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, #if (SSD1306_LCDHEIGHT == 64) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1A, 0xA3, 0xC4, 0x48, 0x48, 0x30, 0x20, 0x10, 0x08, 0x88, 0x84, 0x45, 0x42, 0x21, 0x10, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x20, 0x60, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x70, 0x38, 0x18, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x41, 0x60, 0x50, 0x88, 0x04, 0x02, 0x02, 0x05, 0x05, 0x08, 0x10, 0x21, 0xA2, 0x44, 0x28, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xC0, 0x20, 0x30, 0x18, 0x0C, 0xE6, 0x7F, 0x21, 0x20, 0xC0, 0x00, 0x80, 0xE0, 0x30, 0x20, 0x16, 0x1E, 0x06, 0x04, 0x02, 0x0E, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x80, 0x43, 0x24, 0x28, 0x10, 0x11, 0x8A, 0x8C, 0xC4, 0x42, 0x22, 0xA1, 0x11, 0x10, 0x88, 0x04, 0x43, 0x00, 0x10, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x1E, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #endif }; void SSD1306::drawbitmap(uint8_t x, uint8_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color) { for (uint8_t j=0; j= SSD1306_LCDWIDTH) { x = 0; // ran out of this line line++; } if (line >= (SSD1306_LCDHEIGHT/8)) return; // ran out of space :( } } void SSD1306::drawchar(uint8_t x, uint8_t line, uint8_t c) { if ((line >= SSD1306_LCDHEIGHT/8) || (x >= (SSD1306_LCDWIDTH - 6))) return; for (uint8_t i =0; i<5; i++ ) { buffer[x + (line*128) ] = pgm_read_byte(font+(c*5)+i); x++; } } // bresenham's algorithm - thx wikpedia void SSD1306::drawline(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color) { uint8_t steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swap(x0, y0); swap(x1, y1); } if (x0 > x1) { swap(x0, x1); swap(y0, y1); } uint8_t dx, dy; dx = x1 - x0; dy = abs(y1 - y0); int8_t err = dx / 2; int8_t ystep; if (y0 < y1) { ystep = 1; } else { ystep = -1;} for (; x0= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; setpixel(x0 + x, y0 + y, color); setpixel(x0 - x, y0 + y, color); setpixel(x0 + x, y0 - y, color); setpixel(x0 - x, y0 - y, color); setpixel(x0 + y, y0 + x, color); setpixel(x0 - y, y0 + x, color); setpixel(x0 + y, y0 - x, color); setpixel(x0 - y, y0 - x, color); } } void SSD1306::fillcircle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color) { int8_t f = 1 - r; int8_t ddF_x = 1; int8_t ddF_y = -2 * r; int8_t x = 0; int8_t y = r; for (uint8_t i=y0-r; i<=y0+r; i++) { setpixel(x0, i, color); } while (x= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; for (uint8_t i=y0-y; i<=y0+y; i++) { setpixel(x0+x, i, color); setpixel(x0-x, i, color); } for (uint8_t i=y0-x; i<=y0+x; i++) { setpixel(x0+y, i, color); setpixel(x0-y, i, color); } } } // the most basic function, set a single pixel void SSD1306::setpixel(uint8_t x, uint8_t y, uint8_t color) { if ((x >= SSD1306_LCDWIDTH) || (y >= SSD1306_LCDHEIGHT)) return; // x is which column if (color == WHITE) buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= _BV((y%8)); else buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~_BV((y%8)); } void SSD1306::ssd1306_init(uint8_t vccstate) { // set pin directions pinMode(sid, OUTPUT); pinMode(sclk, OUTPUT); pinMode(dc, OUTPUT); pinMode(rst, OUTPUT); pinMode(cs, OUTPUT); digitalWrite(rst, HIGH); // VDD (3.3V) goes high at start, lets just chill for a ms delay(1); // bring0xset low digitalWrite(rst, LOW); // wait 10ms delay(10); // bring out of reset digitalWrite(rst, HIGH); // turn on VCC (9V?) #if defined SSD1306_128_32 // Init sequence for 128x32 OLED module ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 ssd1306_command(0x80); // the suggested ratio 0x80 ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 ssd1306_command(0x1F); ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 ssd1306_command(0x0); // no offset ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D if (vccstate == SSD1306_EXTERNALVCC) { ssd1306_command(0x10); } else { ssd1306_command(0x14); } ssd1306_command(SSD1306_MEMORYMODE); // 0x20 ssd1306_command(0x00); // 0x0 act like ks0108 ssd1306_command(SSD1306_SEGREMAP | 0x1); ssd1306_command(SSD1306_COMSCANDEC); ssd1306_command(SSD1306_SETCOMPINS); // 0xDA ssd1306_command(0x02); ssd1306_command(SSD1306_SETCONTRAST); // 0x81 ssd1306_command(0x8F); ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 if (vccstate == SSD1306_EXTERNALVCC) { ssd1306_command(0x22); } else { ssd1306_command(0xF1); } ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB ssd1306_command(0x40); ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 #endif #if defined SSD1306_128_64 // Init sequence for 128x64 OLED module ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 ssd1306_command(0x80); // the suggested ratio 0x80 ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 ssd1306_command(0x3F); ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 ssd1306_command(0x0); // no offset ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D if (vccstate == SSD1306_EXTERNALVCC) { ssd1306_command(0x10); } else { ssd1306_command(0x14); } ssd1306_command(SSD1306_MEMORYMODE); // 0x20 ssd1306_command(0x00); // 0x0 act like ks0108 ssd1306_command(SSD1306_SEGREMAP | 0x1); ssd1306_command(SSD1306_COMSCANDEC); ssd1306_command(SSD1306_SETCOMPINS); // 0xDA ssd1306_command(0x12); ssd1306_command(SSD1306_SETCONTRAST); // 0x81 if (vccstate == SSD1306_EXTERNALVCC) { ssd1306_command(0x9F); } else { ssd1306_command(0xCF); } ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 if (vccstate == SSD1306_EXTERNALVCC) { ssd1306_command(0x22); } else { ssd1306_command(0xF1); } ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB ssd1306_command(0x40); ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 #endif ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel } void SSD1306::invert(uint8_t i) { if (i) { ssd1306_command(SSD1306_INVERTDISPLAY); } else { ssd1306_command(SSD1306_NORMALDISPLAY); } } inline void SSD1306::spiwrite(uint8_t c) { shiftOut(sid, sclk, MSBFIRST, c); } void SSD1306::ssd1306_command(uint8_t c) { digitalWrite(cs, HIGH); digitalWrite(dc, LOW); digitalWrite(cs, LOW); spiwrite(c); digitalWrite(cs, HIGH); } void SSD1306::ssd1306_data(uint8_t c) { digitalWrite(cs, HIGH); digitalWrite(dc, HIGH); digitalWrite(cs, LOW); spiwrite(c); digitalWrite(cs, HIGH); } void SSD1306::ssd1306_set_brightness(uint8_t val) { } void SSD1306::display(void) { ssd1306_command(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0 ssd1306_command(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0 ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { ssd1306_data(buffer[i]); } // i wonder why we have to do this (check datasheet) if (SSD1306_LCDHEIGHT == 32) { for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { ssd1306_data(0); } } } // clear everything void SSD1306::clear(void) { memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8)); } void SSD1306::clear_display(void) { }